]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/core/static_string.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / Beast / include / beast / core / static_string.hpp
1 //
2 // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7
8 #ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
9 #define BEAST_WEBSOCKET_STATIC_STRING_HPP
10
11 #include <beast/config.hpp>
12 #include <beast/core/detail/type_traits.hpp>
13 #include <array>
14 #include <cstdint>
15 #include <iterator>
16 #include <stdexcept>
17 #include <string>
18
19 namespace beast {
20
21 /** A string with a fixed-size storage area.
22
23 These objects behave like `std::string` except that the storage
24 is not dynamically allocated but rather fixed in size.
25
26 These strings offer performance advantages when a protocol
27 imposes a natural small upper limit on the size of a value.
28
29 @note The stored string is always null-terminated.
30 */
31 template<
32 std::size_t N,
33 class CharT = char,
34 class Traits = std::char_traits<CharT>>
35 class static_string
36 {
37 template<std::size_t, class, class>
38 friend class static_string;
39
40 std::size_t n_;
41 std::array<CharT, N+1> s_;
42
43 public:
44 using traits_type = Traits;
45 using value_type = typename Traits::char_type;
46 using size_type = std::size_t;
47 using difference_type = std::ptrdiff_t;
48 using pointer = value_type*;
49 using reference = value_type&;
50 using const_pointer = value_type const*;
51 using const_reference = value_type const&;
52 using iterator = value_type*;
53 using const_iterator = value_type const*;
54 using reverse_iterator =
55 std::reverse_iterator<iterator>;
56 using const_reverse_iterator =
57 std::reverse_iterator<const_iterator>;
58
59 /** Default constructor.
60
61 The string is initially empty, and null terminated.
62 */
63 static_string();
64
65 /// Copy constructor.
66 static_string(static_string const& s);
67
68 /// Copy constructor.
69 template<std::size_t M>
70 static_string(static_string<M, CharT, Traits> const& s);
71
72 /// Copy assignment.
73 static_string&
74 operator=(static_string const& s);
75
76 /// Copy assignment.
77 template<std::size_t M>
78 static_string&
79 operator=(static_string<M, CharT, Traits> const& s);
80
81 /// Construct from string literal.
82 template<std::size_t M>
83 static_string(const CharT (&s)[M]);
84
85 /// Assign from string literal.
86 template<std::size_t M>
87 static_string& operator=(const CharT (&s)[M]);
88
89 /// Access specified character with bounds checking.
90 reference
91 at(size_type pos);
92
93 /// Access specified character with bounds checking.
94 const_reference
95 at(size_type pos) const;
96
97 /// Access specified character.
98 reference
99 operator[](size_type pos)
100 {
101 return s_[pos];
102 }
103
104 /// Access specified character.
105 const_reference
106 operator[](size_type pos) const
107 {
108 return s_[pos];
109 }
110
111 /// Accesses the first character.
112 CharT&
113 front()
114 {
115 return s_[0];
116 }
117
118 /// Accesses the first character.
119 CharT const&
120 front() const
121 {
122 return s_[0];
123 }
124
125 /// Accesses the last character.
126 CharT&
127 back()
128 {
129 return s_[n_-1];
130 }
131
132 /// Accesses the last character.
133 CharT const&
134 back() const
135 {
136 return s_[n_-1];
137 }
138
139 /// Returns a pointer to the first character of a string.
140 CharT*
141 data()
142 {
143 return &s_[0];
144 }
145
146 /// Returns a pointer to the first character of a string.
147 CharT const*
148 data() const
149 {
150 return &s_[0];
151 }
152
153 /// Returns a non-modifiable standard C character array version of the string.
154 CharT const*
155 c_str() const
156 {
157 return &s_[0];
158 }
159
160 /// Returns an iterator to the beginning.
161 iterator
162 begin()
163 {
164 return &s_[0];
165 }
166
167 /// Returns an iterator to the beginning.
168 const_iterator
169 begin() const
170 {
171 return &s_[0];
172 }
173
174 /// Returns an iterator to the beginning.
175 const_iterator
176 cbegin() const
177 {
178 return &s_[0];
179 }
180
181 /// Returns an iterator to the end.
182 iterator
183 end()
184 {
185 return &s_[n_];
186 }
187
188 /// Returns an iterator to the end.
189 const_iterator
190 end() const
191 {
192 return &s_[n_];
193 }
194
195 /// Returns an iterator to the end.
196 const_iterator
197 cend() const
198 {
199 return &s_[n_];
200 }
201
202 /// Returns a reverse iterator to the beginning.
203 reverse_iterator
204 rbegin()
205 {
206 return reverse_iterator{end()};
207 }
208
209 /// Returns a reverse iterator to the beginning.
210 const_reverse_iterator
211 rbegin() const
212 {
213 return const_reverse_iterator{cend()};
214 }
215
216 /// Returns a reverse iterator to the beginning.
217 const_reverse_iterator
218 crbegin() const
219 {
220 return const_reverse_iterator{cend()};
221 }
222
223 /// Returns a reverse iterator to the end.
224 reverse_iterator
225 rend()
226 {
227 return reverse_iterator{begin()};
228 }
229
230 /// Returns a reverse iterator to the end.
231 const_reverse_iterator
232 rend() const
233 {
234 return const_reverse_iterator{cbegin()};
235 }
236
237 /// Returns a reverse iterator to the end.
238 const_reverse_iterator
239 crend() const
240 {
241 return const_reverse_iterator{cbegin()};
242 }
243
244 /// Returns `true` if the string is empty.
245 bool
246 empty() const
247 {
248 return n_ == 0;
249 }
250
251 /// Returns the number of characters, excluding the null terminator.
252 size_type
253 size() const
254 {
255 return n_;
256 }
257
258 /// Returns the maximum number of characters that can be stored, excluding the null terminator.
259 size_type constexpr
260 max_size() const
261 {
262 return N;
263 }
264
265 /// Returns the number of characters that can be held in currently allocated storage.
266 size_type
267 capacity() const
268 {
269 return N;
270 }
271
272 /// Clears the contents.
273 void
274 clear()
275 {
276 resize(0);
277 }
278
279 /** Changes the number of characters stored.
280
281 @note No value-initialization is performed.
282 */
283 void
284 resize(std::size_t n);
285
286 /** Changes the number of characters stored.
287
288 If the resulting string is larger, the new
289 characters are initialized to the value of `c`.
290 */
291 void
292 resize(std::size_t n, CharT c);
293
294 /// Compare two character sequences.
295 template<std::size_t M>
296 int
297 compare(static_string<M, CharT, Traits> const& rhs) const;
298
299 /// Return the characters as a `basic_string`.
300 std::basic_string<CharT, Traits>
301 to_string() const
302 {
303 return std::basic_string<
304 CharT, Traits>{&s_[0], n_};
305 }
306
307 private:
308 void
309 assign(CharT const* s);
310 };
311
312 template<std::size_t N, class CharT, class Traits>
313 static_string<N, CharT, Traits>::
314 static_string()
315 : n_(0)
316 {
317 s_[0] = 0;
318 }
319
320 template<std::size_t N, class CharT, class Traits>
321 static_string<N, CharT, Traits>::
322 static_string(static_string const& s)
323 : n_(s.n_)
324 {
325 Traits::copy(&s_[0], &s.s_[0], n_ + 1);
326 }
327
328 template<std::size_t N, class CharT, class Traits>
329 template<std::size_t M>
330 static_string<N, CharT, Traits>::
331 static_string(static_string<M, CharT, Traits> const& s)
332 {
333 if(s.size() > N)
334 throw detail::make_exception<std::length_error>(
335 "static_string overflow", __FILE__, __LINE__);
336 n_ = s.size();
337 Traits::copy(&s_[0], &s.s_[0], n_ + 1);
338 }
339
340 template<std::size_t N, class CharT, class Traits>
341 auto
342 static_string<N, CharT, Traits>::
343 operator=(static_string const& s) ->
344 static_string&
345 {
346 n_ = s.n_;
347 Traits::copy(&s_[0], &s.s_[0], n_ + 1);
348 return *this;
349 }
350
351 template<std::size_t N, class CharT, class Traits>
352 template<std::size_t M>
353 auto
354 static_string<N, CharT, Traits>::
355 operator=(static_string<M, CharT, Traits> const& s) ->
356 static_string&
357 {
358 if(s.size() > N)
359 throw detail::make_exception<std::length_error>(
360 "static_string overflow", __FILE__, __LINE__);
361 n_ = s.size();
362 Traits::copy(&s_[0], &s.s_[0], n_ + 1);
363 return *this;
364 }
365
366 template<std::size_t N, class CharT, class Traits>
367 template<std::size_t M>
368 static_string<N, CharT, Traits>::
369 static_string(const CharT (&s)[M])
370 : n_(M-1)
371 {
372 static_assert(M-1 <= N,
373 "static_string overflow");
374 Traits::copy(&s_[0], &s[0], M);
375 }
376
377 template<std::size_t N, class CharT, class Traits>
378 template<std::size_t M>
379 auto
380 static_string<N, CharT, Traits>::
381 operator=(const CharT (&s)[M]) ->
382 static_string&
383 {
384 static_assert(M-1 <= N,
385 "static_string overflow");
386 n_ = M-1;
387 Traits::copy(&s_[0], &s[0], M);
388 return *this;
389 }
390
391 template<std::size_t N, class CharT, class Traits>
392 auto
393 static_string<N, CharT, Traits>::
394 at(size_type pos) ->
395 reference
396 {
397 if(pos >= n_)
398 throw detail::make_exception<std::out_of_range>(
399 "invalid pos", __FILE__, __LINE__);
400 return s_[pos];
401 }
402
403 template<std::size_t N, class CharT, class Traits>
404 auto
405 static_string<N, CharT, Traits>::
406 at(size_type pos) const ->
407 const_reference
408 {
409 if(pos >= n_)
410 throw detail::make_exception<std::out_of_range>(
411 "static_string::at", __FILE__, __LINE__);
412 return s_[pos];
413 }
414
415 template<std::size_t N, class CharT, class Traits>
416 void
417 static_string<N, CharT, Traits>::
418 resize(std::size_t n)
419 {
420 if(n > N)
421 throw detail::make_exception<std::length_error>(
422 "static_string overflow", __FILE__, __LINE__);
423 n_ = n;
424 s_[n_] = 0;
425 }
426
427 template<std::size_t N, class CharT, class Traits>
428 void
429 static_string<N, CharT, Traits>::
430 resize(std::size_t n, CharT c)
431 {
432 if(n > N)
433 throw detail::make_exception<std::length_error>(
434 "static_string overflow", __FILE__, __LINE__);
435 if(n > n_)
436 Traits::assign(&s_[n_], n - n_, c);
437 n_ = n;
438 s_[n_] = 0;
439 }
440
441 template<std::size_t N, class CharT, class Traits>
442 template<std::size_t M>
443 int
444 static_string<N, CharT, Traits>::
445 compare(static_string<M, CharT, Traits> const& rhs) const
446 {
447 if(size() < rhs.size())
448 {
449 auto const v = Traits::compare(
450 data(), rhs.data(), size());
451 if(v == 0)
452 return -1;
453 return v;
454 }
455 else if(size() > rhs.size())
456 {
457 auto const v = Traits::compare(
458 data(), rhs.data(), rhs.size());
459 if(v == 0)
460 return 1;
461 return v;
462 }
463 return Traits::compare(data(), rhs.data(), size());
464 }
465
466 template<std::size_t N, class CharT, class Traits>
467 void
468 static_string<N, CharT, Traits>::
469 assign(CharT const* s)
470 {
471 auto const n = Traits::length(s);
472 if(n > N)
473 throw detail::make_exception<std::out_of_range>(
474 "too large", __FILE__, __LINE__);
475 n_ = n;
476 Traits::copy(&s_[0], s, n_ + 1);
477 }
478
479 namespace detail {
480
481 template<std::size_t N, std::size_t M, class CharT, class Traits>
482 int
483 compare(
484 static_string<N, CharT, Traits> const& lhs,
485 const CharT (&s)[M])
486 {
487 if(lhs.size() < M-1)
488 {
489 auto const v = Traits::compare(
490 lhs.data(), &s[0], lhs.size());
491 if(v == 0)
492 return -1;
493 return v;
494 }
495 else if(lhs.size() > M-1)
496 {
497 auto const v = Traits::compare(
498 lhs.data(), &s[0], M-1);
499 if(v == 0)
500 return 1;
501 return v;
502 }
503 return Traits::compare(lhs.data(), &s[0], lhs.size());
504 }
505
506 template<std::size_t N, std::size_t M, class CharT, class Traits>
507 inline
508 int
509 compare(
510 const CharT (&s)[M],
511 static_string<N, CharT, Traits> const& rhs)
512 {
513 return -compare(rhs, s);
514 }
515
516 } // detail
517
518 template<std::size_t N, std::size_t M, class CharT, class Traits>
519 bool
520 operator==(
521 static_string<N, CharT, Traits> const& lhs,
522 static_string<M, CharT, Traits> const& rhs)
523 {
524 return lhs.compare(rhs) == 0;
525 }
526
527 template<std::size_t N, std::size_t M, class CharT, class Traits>
528 bool
529 operator!=(
530 static_string<N, CharT, Traits> const& lhs,
531 static_string<M, CharT, Traits> const& rhs)
532 {
533 return lhs.compare(rhs) != 0;
534 }
535
536 template<std::size_t N, std::size_t M, class CharT, class Traits>
537 bool
538 operator<(
539 static_string<N, CharT, Traits> const& lhs,
540 static_string<M, CharT, Traits> const& rhs)
541 {
542 return lhs.compare(rhs) < 0;
543 }
544
545 template<std::size_t N, std::size_t M, class CharT, class Traits>
546 bool
547 operator<=(
548 static_string<N, CharT, Traits> const& lhs,
549 static_string<M, CharT, Traits> const& rhs)
550 {
551 return lhs.compare(rhs) <= 0;
552 }
553
554 template<std::size_t N, std::size_t M, class CharT, class Traits>
555 bool
556 operator>(
557 static_string<N, CharT, Traits> const& lhs,
558 static_string<M, CharT, Traits> const& rhs)
559 {
560 return lhs.compare(rhs) > 0;
561 }
562
563 template<std::size_t N, std::size_t M, class CharT, class Traits>
564 bool
565 operator>=(
566 static_string<N, CharT, Traits> const& lhs,
567 static_string<M, CharT, Traits> const& rhs)
568 {
569 return lhs.compare(rhs) >= 0;
570 }
571
572 //---
573
574 template<std::size_t N, std::size_t M, class CharT, class Traits>
575 bool
576 operator==(
577 const CharT (&s)[N],
578 static_string<M, CharT, Traits> const& rhs)
579 {
580 return detail::compare(s, rhs) == 0;
581 }
582
583 template<std::size_t N, class CharT, class Traits, std::size_t M>
584 bool
585 operator==(
586 static_string<N, CharT, Traits> const& lhs,
587 const CharT (&s)[M])
588 {
589 return detail::compare(lhs, s) == 0;
590 }
591
592 template<std::size_t N, std::size_t M, class CharT, class Traits>
593 bool
594 operator!=(
595 const CharT (&s)[N],
596 static_string<M, CharT, Traits> const& rhs)
597 {
598 return detail::compare(s, rhs) != 0;
599 }
600
601 template<std::size_t N, class CharT, class Traits, std::size_t M>
602 bool
603 operator!=(
604 static_string<N, CharT, Traits> const& lhs,
605 const CharT (&s)[M])
606 {
607 return detail::compare(lhs, s) != 0;
608 }
609
610 template<std::size_t N, std::size_t M, class CharT, class Traits>
611 bool
612 operator<(
613 const CharT (&s)[N],
614 static_string<M, CharT, Traits> const& rhs)
615 {
616 return detail::compare(s, rhs) < 0;
617 }
618
619 template<std::size_t N, class CharT, class Traits, std::size_t M>
620 bool
621 operator<(
622 static_string<N, CharT, Traits> const& lhs,
623 const CharT (&s)[M])
624 {
625 return detail::compare(lhs, s) < 0;
626 }
627
628 template<std::size_t N, std::size_t M, class CharT, class Traits>
629 bool
630 operator<=(
631 const CharT (&s)[N],
632 static_string<M, CharT, Traits> const& rhs)
633 {
634 return detail::compare(s, rhs) <= 0;
635 }
636
637 template<std::size_t N, class CharT, class Traits, std::size_t M>
638 bool
639 operator<=(
640 static_string<N, CharT, Traits> const& lhs,
641 const CharT (&s)[M])
642 {
643 return detail::compare(lhs, s) <= 0;
644 }
645
646 template<std::size_t N, std::size_t M, class CharT, class Traits>
647 bool
648 operator>(
649 const CharT (&s)[N],
650 static_string<M, CharT, Traits> const& rhs)
651 {
652 return detail::compare(s, rhs) > 0;
653 }
654
655 template<std::size_t N, class CharT, class Traits, std::size_t M>
656 bool
657 operator>(
658 static_string<N, CharT, Traits> const& lhs,
659 const CharT (&s)[M])
660 {
661 return detail::compare(lhs, s) > 0;
662 }
663
664 template<std::size_t N, std::size_t M, class CharT, class Traits>
665 bool
666 operator>=(
667 const CharT (&s)[N],
668 static_string<M, CharT, Traits> const& rhs)
669 {
670 return detail::compare(s, rhs) >= 0;
671 }
672
673 template<std::size_t N, class CharT, class Traits, std::size_t M>
674 bool
675 operator>=(
676 static_string<N, CharT, Traits> const& lhs,
677 const CharT (&s)[M])
678 {
679 return detail::compare(lhs, s) >= 0;
680 }
681
682 } // beast
683
684 #endif