Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / beast / core / static_string.hpp
1 //
2 // Copyright (c) 2016-2019 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 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_STATIC_STRING_HPP
11 #define BOOST_BEAST_STATIC_STRING_HPP
12
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/string.hpp>
15 #include <boost/beast/core/detail/static_string.hpp>
16 #include <algorithm>
17 #include <cstdint>
18 #include <initializer_list>
19 #include <iosfwd>
20 #include <stdexcept>
21 #include <string>
22 #include <type_traits>
23
24 namespace boost {
25 namespace beast {
26
27 /** A modifiable string with a fixed-size storage area.
28
29     These objects behave like `std::string` except that the storage
30     is not dynamically allocated but rather fixed in size.
31
32     These strings offer performance advantages when a protocol
33     imposes a natural small upper limit on the size of a value.
34
35     @note The stored string is always null-terminated.
36
37     @see to_static_string 
38 */
39 template<
40     std::size_t N,
41     class CharT = char,
42     class Traits = std::char_traits<CharT>>
43 class static_string
44 {
45     template<std::size_t, class, class>
46     friend class static_string;
47
48     void
49     term()
50     {
51         Traits::assign(s_[n_], 0);
52     }
53
54     std::size_t n_;
55     CharT s_[N+1];
56
57 public:
58     //
59     // Member types
60     //
61
62     using traits_type = Traits;
63     using value_type = typename Traits::char_type;
64     using size_type = std::size_t;
65     using difference_type = std::ptrdiff_t;
66     using pointer = value_type*;
67     using reference = value_type&;
68     using const_pointer = value_type const*;
69     using const_reference = value_type const&;
70     using iterator = value_type*;
71     using const_iterator = value_type const*;
72     using reverse_iterator =
73         std::reverse_iterator<iterator>;
74     using const_reverse_iterator =
75         std::reverse_iterator<const_iterator>;
76
77     /// The type of `string_view` returned by the interface
78     using string_view_type =
79         basic_string_view<CharT, Traits>;
80
81     //
82     // Constants
83     //
84
85     /// Maximum size of the string excluding the null terminator
86     static std::size_t constexpr max_size_n = N;
87
88     /// A special index
89     static constexpr size_type npos = size_type(-1);
90
91     //
92     // (constructor)
93     //
94
95     /// Default constructor (empty string).
96     static_string();
97
98     /** Construct with count copies of character `ch`.
99     
100         The behavior is undefined if `count >= npos`
101     */
102     static_string(size_type count, CharT ch);
103
104     /// Construct with a substring (pos, other.size()) of `other`.
105     template<std::size_t M>
106     static_string(static_string<M, CharT, Traits> const& other,
107         size_type pos);
108
109     /// Construct with a substring (pos, count) of `other`.
110     template<std::size_t M>
111     static_string(static_string<M, CharT, Traits> const& other,
112         size_type pos, size_type count);
113
114     /// Construct with the first `count` characters of `s`, including nulls.
115     static_string(CharT const* s, size_type count);
116
117     /// Construct from a null terminated string.
118     static_string(CharT const* s);
119
120     /// Construct from a range of characters
121     template<class InputIt>
122     static_string(InputIt first, InputIt last);
123
124     /// Copy constructor.
125     static_string(static_string const& other);
126
127     /// Copy constructor.
128     template<std::size_t M>
129     static_string(static_string<M, CharT, Traits> const& other);
130
131     /// Construct from an initializer list
132     static_string(std::initializer_list<CharT> init);
133
134     /// Construct from a `string_view`
135     explicit
136     static_string(string_view_type sv);
137
138     /** Construct from any object convertible to `string_view_type`.
139
140         The range (pos, n) is extracted from the value
141         obtained by converting `t` to `string_view_type`,
142         and used to construct the string.
143     */
144 #if BOOST_BEAST_DOXYGEN
145     template<class T>
146 #else
147     template<class T, class = typename std::enable_if<
148         std::is_convertible<T, string_view_type>::value>::type>
149 #endif
150     static_string(T const& t, size_type pos, size_type n);
151
152     //
153     // (assignment)
154     //
155
156     /// Copy assignment.
157     static_string&
158     operator=(static_string const& str)
159     {
160         return assign(str);
161     }
162
163     /// Copy assignment.
164     template<std::size_t M>
165     static_string&
166     operator=(static_string<M, CharT, Traits> const& str)
167     {
168         return assign(str);
169     }
170
171     /// Assign from null-terminated string.
172     static_string&
173     operator=(CharT const* s);
174
175     /// Assign from single character.
176     static_string&
177     operator=(CharT ch)
178     {
179         return assign_char(ch,
180             std::integral_constant<bool, (N>0)>{});
181     }
182
183     /// Assign from initializer list.
184     static_string&
185     operator=(std::initializer_list<CharT> init)
186     {
187         return assign(init);
188     }
189
190     /// Assign from `string_view_type`.
191     static_string&
192     operator=(string_view_type sv)
193     {
194         return assign(sv);
195     }
196
197     /// Assign `count` copies of `ch`.
198     static_string&
199     assign(size_type count, CharT ch);
200
201     /// Assign from another `static_string`
202     static_string&
203     assign(static_string const& str);
204
205     // VFALCO NOTE this could come in two flavors,
206     //             N>M and N<M, and skip the exception
207     //             check when N>M
208
209     /// Assign from another `static_string`
210     template<std::size_t M>
211     static_string&
212     assign(static_string<M, CharT, Traits> const& str)
213     {
214         return assign(str.data(), str.size());
215     }
216
217     /// Assign `count` characterss starting at `npos` from `other`.
218     template<std::size_t M>
219     static_string&
220     assign(static_string<M, CharT, Traits> const& str,
221         size_type pos, size_type count = npos);
222
223     /// Assign the first `count` characters of `s`, including nulls.
224     static_string&
225     assign(CharT const* s, size_type count);
226
227     /// Assign a null terminated string.
228     static_string&
229     assign(CharT const* s)
230     {
231         return assign(s, Traits::length(s));
232     }
233
234     /// Assign from an iterator range of characters.
235     template<class InputIt>
236     static_string&
237     assign(InputIt first, InputIt last);
238
239     /// Assign from initializer list.
240     static_string&
241     assign(std::initializer_list<CharT> init)
242     {
243         return assign(init.begin(), init.end());
244     }
245
246     /// Assign from `string_view_type`.
247     static_string&
248     assign(string_view_type str)
249     {
250         return assign(str.data(), str.size());
251     }
252
253     /** Assign from any object convertible to `string_view_type`.
254
255         The range (pos, n) is extracted from the value
256         obtained by converting `t` to `string_view_type`,
257         and used to assign the string.
258     */
259     template<class T>
260 #if BOOST_BEAST_DOXYGEN
261     static_string&
262 #else
263     typename std::enable_if<std::is_convertible<T,
264         string_view_type>::value, static_string&>::type
265 #endif
266     assign(T const& t,
267         size_type pos, size_type count = npos);
268
269     //
270     // Element access
271     //
272
273     /// Access specified character with bounds checking.
274     reference
275     at(size_type pos);
276
277     /// Access specified character with bounds checking.
278     const_reference
279     at(size_type pos) const;
280
281     /// Access specified character.
282     reference
283     operator[](size_type pos)
284     {
285         return s_[pos];
286     }
287
288     /// Access specified character.
289     const_reference
290     operator[](size_type pos) const
291     {
292         return s_[pos];
293     }
294
295     /// Accesses the first character.
296     CharT&
297     front()
298     {
299         return s_[0];
300     }
301
302     /// Accesses the first character.
303     CharT const&
304     front() const
305     {
306         return s_[0];
307     }
308
309     /// Accesses the last character.
310     CharT&
311     back()
312     {
313         return s_[n_-1];
314     }
315
316     /// Accesses the last character.
317     CharT const&
318     back() const
319     {
320         return s_[n_-1];
321     }
322
323     /// Returns a pointer to the first character of a string.
324     CharT*
325     data()
326     {
327         return &s_[0];
328     }
329
330     /// Returns a pointer to the first character of a string.
331     CharT const*
332     data() const
333     {
334         return &s_[0];
335     }
336
337     /// Returns a non-modifiable standard C character array version of the string.
338     CharT const*
339     c_str() const
340     {
341         return data();
342     }
343
344     /// Convert a static string to a `string_view_type`
345     operator string_view_type() const
346     {
347         return basic_string_view<
348             CharT, Traits>{data(), size()};
349     }
350
351     //
352     // Iterators
353     //
354
355     /// Returns an iterator to the beginning.
356     iterator
357     begin()
358     {
359         return &s_[0];
360     }
361
362     /// Returns an iterator to the beginning.
363     const_iterator
364     begin() const
365     {
366         return &s_[0];
367     }
368
369     /// Returns an iterator to the beginning.
370     const_iterator
371     cbegin() const
372     {
373         return &s_[0];
374     }
375
376     /// Returns an iterator to the end.
377     iterator
378     end()
379     {
380         return &s_[n_];
381     }
382
383     /// Returns an iterator to the end.
384     const_iterator
385     end() const
386     {
387         return &s_[n_];
388     }
389
390     /// Returns an iterator to the end.
391     const_iterator
392     cend() const
393     {
394         return &s_[n_];
395     }
396
397     /// Returns a reverse iterator to the beginning.
398     reverse_iterator
399     rbegin()
400     {
401         return reverse_iterator{end()};
402     }
403
404     /// Returns a reverse iterator to the beginning.
405     const_reverse_iterator
406     rbegin() const
407     {
408         return const_reverse_iterator{cend()};
409     }
410
411     /// Returns a reverse iterator to the beginning.
412     const_reverse_iterator
413     crbegin() const
414     {
415         return const_reverse_iterator{cend()};
416     }
417
418     /// Returns a reverse iterator to the end.
419     reverse_iterator
420     rend()
421     {
422         return reverse_iterator{begin()};
423     }
424
425     /// Returns a reverse iterator to the end.
426     const_reverse_iterator
427     rend() const
428     {
429         return const_reverse_iterator{cbegin()};
430     }
431
432     /// Returns a reverse iterator to the end.
433     const_reverse_iterator
434     crend() const
435     {
436         return const_reverse_iterator{cbegin()};
437     }
438
439     //
440     // Capacity
441     //
442
443     /// Returns `true` if the string is empty.
444     bool
445     empty() const
446     {
447         return n_ == 0;
448     }
449
450     /// Returns the number of characters, excluding the null terminator.
451     size_type
452     size() const
453     {
454         return n_;
455     }
456
457     /// Returns the number of characters, excluding the null terminator.
458     size_type
459     length() const
460     {
461         return size();
462     }
463
464     /// Returns the maximum number of characters that can be stored, excluding the null terminator.
465     size_type constexpr
466     max_size() const
467     {
468         return N;
469     }
470
471     /** Reserves storage.
472
473         This actually just throws an exception if `n > N`,
474         otherwise does nothing since the storage is fixed.
475     */
476     void
477     reserve(std::size_t n);
478
479     /// Returns the number of characters that can be held in currently allocated storage.
480     size_type constexpr
481     capacity() const
482     {
483         return max_size();
484     }
485     
486     /** Reduces memory usage by freeing unused memory.
487
488         This actually does nothing, since the storage is fixed.
489     */
490     void
491     shrink_to_fit()
492     {
493     }
494
495     //
496     // Operations
497     //
498
499     /// Clears the contents.
500     void
501     clear();
502
503     static_string&
504     insert(size_type index, size_type count, CharT ch);
505
506     static_string&
507     insert(size_type index, CharT const* s)
508     {
509         return insert(index, s, Traits::length(s));
510     }
511
512     static_string&
513     insert(size_type index, CharT const* s, size_type count);
514
515     template<std::size_t M>
516     static_string&
517     insert(size_type index,
518         static_string<M, CharT, Traits> const& str)
519     {
520         return insert(index, str.data(), str.size());
521     }
522
523     template<std::size_t M>
524     static_string&
525     insert(size_type index,
526         static_string<M, CharT, Traits> const& str,
527             size_type index_str, size_type count = npos);
528
529     iterator
530     insert(const_iterator pos, CharT ch)
531     {
532         return insert(pos, 1, ch);
533     }
534
535     iterator
536     insert(const_iterator pos, size_type count, CharT ch);
537
538     template<class InputIt>
539 #if BOOST_BEAST_DOXYGEN
540     iterator
541 #else
542     typename std::enable_if<
543         detail::is_input_iterator<InputIt>::value,
544             iterator>::type
545 #endif
546     insert(const_iterator pos, InputIt first, InputIt last);
547
548     iterator
549     insert(const_iterator pos, std::initializer_list<CharT> init)
550     {
551         return insert(pos, init.begin(), init.end());
552     }
553
554     static_string&
555     insert(size_type index, string_view_type str)
556     {
557         return insert(index, str.data(), str.size());
558     }
559
560     template<class T>
561 #if BOOST_BEAST_DOXYGEN
562     static_string&
563 #else
564     typename std::enable_if<
565         std::is_convertible<T const&, string_view_type>::value &&
566         ! std::is_convertible<T const&, CharT const*>::value,
567             static_string&>::type
568 #endif
569     insert(size_type index, T const& t,
570         size_type index_str, size_type count = npos);
571
572     static_string&
573     erase(size_type index = 0, size_type count = npos);
574
575     iterator
576     erase(const_iterator pos);
577
578     iterator
579     erase(const_iterator first, const_iterator last);
580
581     void
582     push_back(CharT ch);
583
584     void
585     pop_back()
586     {
587         Traits::assign(s_[--n_], 0);
588     }
589
590     static_string&
591     append(size_type count, CharT ch)
592     {
593         insert(end(), count, ch);
594         return *this;
595     }
596
597     template<std::size_t M>
598     static_string&
599     append(static_string<M, CharT, Traits> const& str)
600     {
601         insert(size(), str);
602         return *this;
603     }
604
605     template<std::size_t M>
606     static_string&
607     append(static_string<M, CharT, Traits> const& str,
608         size_type pos, size_type count = npos);
609
610     static_string&
611     append(CharT const* s, size_type count)
612     {
613         insert(size(), s, count);
614         return *this;
615     }
616
617     static_string&
618     append(CharT const* s)
619     {
620         insert(size(), s);
621         return *this;
622     }
623
624     template<class InputIt>
625 #if BOOST_BEAST_DOXYGEN
626     static_string&
627 #else
628     typename std::enable_if<
629         detail::is_input_iterator<InputIt>::value,
630             static_string&>::type
631 #endif
632     append(InputIt first, InputIt last)
633     {
634         insert(end(), first, last);
635         return *this;
636     }
637
638     static_string&
639     append(std::initializer_list<CharT> init)
640     {
641         insert(end(), init);
642         return *this;
643     }
644
645     static_string&
646     append(string_view_type sv)
647     {
648         insert(size(), sv);
649         return *this;
650     }
651
652     template<class T>
653     typename std::enable_if<
654         std::is_convertible<T const&, string_view_type>::value &&
655         ! std::is_convertible<T const&, CharT const*>::value,
656             static_string&>::type
657     append(T const& t, size_type pos, size_type count = npos)
658     {
659         insert(size(), t, pos, count);
660         return *this;
661     }
662
663     template<std::size_t M>
664     static_string&
665     operator+=(static_string<M, CharT, Traits> const& str)
666     {
667         return append(str.data(), str.size());
668     }
669
670     static_string&
671     operator+=(CharT ch)
672     {
673         push_back(ch);
674         return *this;
675     }
676
677     static_string&
678     operator+=(CharT const* s)
679     {
680         return append(s);
681     }
682
683     static_string&
684     operator+=(std::initializer_list<CharT> init)
685     {
686         return append(init);
687     }
688
689     static_string&
690     operator+=(string_view_type const& str)
691     {
692         return append(str);
693     }
694
695     template<std::size_t M>
696     int
697     compare(static_string<M, CharT, Traits> const& str) const
698     {
699         return detail::lexicographical_compare<CharT, Traits>(
700             &s_[0], n_, &str.s_[0], str.n_);
701     }
702
703     template<std::size_t M>
704     int
705     compare(size_type pos1, size_type count1,
706         static_string<M, CharT, Traits> const& str) const
707     {
708         return detail::lexicographical_compare<CharT, Traits>(
709             substr(pos1, count1), str.data(), str.size());
710     }
711
712     template<std::size_t M>
713     int
714     compare(size_type pos1, size_type count1,
715         static_string<M, CharT, Traits> const& str,
716             size_type pos2, size_type count2 = npos) const
717     {
718         return detail::lexicographical_compare(
719             substr(pos1, count1), str.substr(pos2, count2));
720     }
721
722     int
723     compare(CharT const* s) const
724     {
725         return detail::lexicographical_compare<CharT, Traits>(
726             &s_[0], n_, s, Traits::length(s));
727     }
728
729     int
730     compare(size_type pos1, size_type count1,
731         CharT const* s) const
732     {
733         return detail::lexicographical_compare<CharT, Traits>(
734             substr(pos1, count1), s, Traits::length(s));
735     }
736
737     int
738     compare(size_type pos1, size_type count1,
739         CharT const*s, size_type count2) const
740     {
741         return detail::lexicographical_compare<CharT, Traits>(
742             substr(pos1, count1), s, count2);
743     }
744
745     int
746     compare(string_view_type str) const
747     {
748         return detail::lexicographical_compare<CharT, Traits>(
749             &s_[0], n_, str.data(), str.size());
750     }
751
752     int
753     compare(size_type pos1, size_type count1,
754         string_view_type str) const
755     {
756         return detail::lexicographical_compare<CharT, Traits>(
757             substr(pos1, count1), str);
758     }
759
760     template<class T>
761 #if BOOST_BEAST_DOXYGEN
762     int
763 #else
764     typename std::enable_if<
765         std::is_convertible<T const&, string_view_type>::value &&
766         ! std::is_convertible<T const&, CharT const*>::value,
767             int>::type
768 #endif
769     compare(size_type pos1, size_type count1,
770         T const& t, size_type pos2,
771             size_type count2 = npos) const
772     {
773         return compare(pos1, count1,
774             string_view_type(t).substr(pos2, count2));
775     }
776
777     string_view_type
778     substr(size_type pos = 0, size_type count = npos) const;
779
780     /// Copy a substring (pos, pos+count) to character string pointed to by `dest`.
781     size_type
782     copy(CharT* dest, size_type count, size_type pos = 0) const;
783
784     /** Changes the number of characters stored.
785
786         If the resulting string is larger, the new
787         characters are uninitialized.
788     */
789     void
790     resize(std::size_t n);
791
792     /** Changes the number of characters stored.
793
794         If the resulting string is larger, the new
795         characters are initialized to the value of `c`.
796     */
797     void
798     resize(std::size_t n, CharT c);
799
800     /// Exchange the contents of this string with another.
801     void
802     swap(static_string& str);
803
804     /// Exchange the contents of this string with another.
805     template<std::size_t M>
806     void
807     swap(static_string<M, CharT, Traits>& str);
808
809     //
810     // Search
811     //
812
813 private:
814     static_string&
815     assign_char(CharT ch, std::true_type);
816
817     static_string&
818     assign_char(CharT ch, std::false_type);
819 };
820
821 //
822 // Disallowed operations
823 //
824
825 // These operations are explicitly deleted since
826 // there is no reasonable implementation possible.
827
828 template<std::size_t N, std::size_t M, class CharT, class Traits>
829 void
830 operator+(
831     static_string<N, CharT, Traits>const&,
832     static_string<M, CharT, Traits>const&) = delete;
833
834 template<std::size_t N, class CharT, class Traits>
835 void
836 operator+(CharT const*,
837     static_string<N, CharT, Traits>const&) = delete;
838
839 template<std::size_t N, class CharT, class Traits>
840 void
841 operator+(CharT,
842     static_string<N, CharT, Traits> const&) = delete;
843
844 template<std::size_t N, class CharT, class Traits>
845 void
846 operator+(static_string<N, CharT, Traits> const&,
847     CharT const*) = delete;
848
849 template<std::size_t N, class CharT, class Traits>
850 void
851 operator+(static_string<N, CharT, Traits> const&, CharT) = delete;
852
853 //
854 // Non-member functions
855 //
856
857 template<std::size_t N, std::size_t M,
858     class CharT, class Traits>
859 bool
860 operator==(
861     static_string<N, CharT, Traits> const& lhs,
862     static_string<M, CharT, Traits> const& rhs)
863 {
864     return lhs.compare(rhs) == 0;
865 }
866
867 template<std::size_t N, std::size_t M,
868     class CharT, class Traits>
869 bool
870 operator!=(
871     static_string<N, CharT, Traits> const& lhs,
872     static_string<M, CharT, Traits> const& rhs)
873 {
874     return lhs.compare(rhs) != 0;
875 }
876
877 template<std::size_t N, std::size_t M,
878     class CharT, class Traits>
879 bool
880 operator<(
881     static_string<N, CharT, Traits> const& lhs,
882     static_string<M, CharT, Traits> const& rhs)
883 {
884     return lhs.compare(rhs) < 0;
885 }
886
887 template<std::size_t N, std::size_t M,
888     class CharT, class Traits>
889 bool
890 operator<=(
891     static_string<N, CharT, Traits> const& lhs,
892     static_string<M, CharT, Traits> const& rhs)
893 {
894     return lhs.compare(rhs) <= 0;
895 }
896
897 template<std::size_t N, std::size_t M,
898     class CharT, class Traits>
899 bool
900 operator>(
901     static_string<N, CharT, Traits> const& lhs,
902     static_string<M, CharT, Traits> const& rhs)
903 {
904     return lhs.compare(rhs) > 0;
905 }
906
907 template<std::size_t N, std::size_t M,
908     class CharT, class Traits>
909 bool
910 operator>=(
911     static_string<N, CharT, Traits> const& lhs,
912     static_string<M, CharT, Traits> const& rhs)
913 {
914     return lhs.compare(rhs) >= 0;
915 }
916
917 template<std::size_t N, class CharT, class Traits>
918 bool
919 operator==(
920     CharT const* lhs,
921     static_string<N, CharT, Traits> const& rhs)
922 {
923     return detail::lexicographical_compare<CharT, Traits>(
924         lhs, Traits::length(lhs),
925         rhs.data(), rhs.size()) == 0;
926 }
927
928 template<std::size_t N, class CharT, class Traits>
929 bool
930 operator==(
931     static_string<N, CharT, Traits> const& lhs,
932     CharT const* rhs)
933 {
934     return detail::lexicographical_compare<CharT, Traits>(
935         lhs.data(), lhs.size(),
936         rhs, Traits::length(rhs)) == 0;
937 }
938
939 template<std::size_t N, class CharT, class Traits>
940 bool
941 operator!=(
942     CharT const* lhs,
943     static_string<N, CharT, Traits> const& rhs)
944 {
945     return detail::lexicographical_compare<CharT, Traits>(
946         lhs, Traits::length(lhs),
947         rhs.data(), rhs.size()) != 0;
948 }
949
950 template<std::size_t N, class CharT, class Traits>
951 bool
952 operator!=(
953     static_string<N, CharT, Traits> const& lhs,
954     CharT const* rhs)
955 {
956     return detail::lexicographical_compare<CharT, Traits>(
957         lhs.data(), lhs.size(),
958         rhs, Traits::length(rhs)) != 0;
959 }
960
961 template<std::size_t N, class CharT, class Traits>
962 bool
963 operator<(
964     CharT const* lhs,
965     static_string<N, CharT, Traits> const& rhs)
966 {
967     return detail::lexicographical_compare<CharT, Traits>(
968         lhs, Traits::length(lhs),
969         rhs.data(), rhs.size()) < 0;
970 }
971
972 template<std::size_t N, class CharT, class Traits>
973 bool
974 operator<(
975     static_string<N, CharT, Traits> const& lhs,
976     CharT const* rhs)
977 {
978     return detail::lexicographical_compare<CharT, Traits>(
979         lhs.data(), lhs.size(),
980         rhs, Traits::length(rhs)) < 0;
981 }
982
983 template<std::size_t N, class CharT, class Traits>
984 bool
985 operator<=(
986     CharT const* lhs,
987     static_string<N, CharT, Traits> const& rhs)
988 {
989     return detail::lexicographical_compare<CharT, Traits>(
990         lhs, Traits::length(lhs),
991         rhs.data(), rhs.size()) <= 0;
992 }
993
994 template<std::size_t N, class CharT, class Traits>
995 bool
996 operator<=(
997     static_string<N, CharT, Traits> const& lhs,
998     CharT const* rhs)
999 {
1000     return detail::lexicographical_compare<CharT, Traits>(
1001         lhs.data(), lhs.size(),
1002         rhs, Traits::length(rhs)) <= 0;
1003 }
1004
1005 template<std::size_t N, class CharT, class Traits>
1006 bool
1007 operator>(
1008     CharT const* lhs,
1009     static_string<N, CharT, Traits> const& rhs)
1010 {
1011     return detail::lexicographical_compare<CharT, Traits>(
1012         lhs, Traits::length(lhs),
1013         rhs.data(), rhs.size()) > 0;
1014 }
1015
1016 template<std::size_t N, class CharT, class Traits>
1017 bool
1018 operator>(
1019     static_string<N, CharT, Traits> const& lhs,
1020     CharT const* rhs)
1021 {
1022     return detail::lexicographical_compare<CharT, Traits>(
1023         lhs.data(), lhs.size(),
1024         rhs, Traits::length(rhs)) > 0;
1025 }
1026
1027 template<std::size_t N, class CharT, class Traits>
1028 bool
1029 operator>=(
1030     CharT const* lhs,
1031     static_string<N, CharT, Traits> const& rhs)
1032 {
1033     return detail::lexicographical_compare<CharT, Traits>(
1034         lhs, Traits::length(lhs),
1035         rhs.data(), rhs.size()) >= 0;
1036 }
1037
1038 template<std::size_t N, class CharT, class Traits>
1039 bool
1040 operator>=(
1041     static_string<N, CharT, Traits> const& lhs,
1042     CharT const* rhs)
1043 {
1044     return detail::lexicographical_compare<CharT, Traits>(
1045         lhs.data(), lhs.size(),
1046         rhs, Traits::length(rhs)) >= 0;
1047 }
1048
1049 //
1050 // swap
1051 //
1052
1053 template<std::size_t N, class CharT, class Traits>
1054 void
1055 swap(
1056     static_string<N, CharT, Traits>& lhs,
1057     static_string<N, CharT, Traits>& rhs)
1058 {
1059     lhs.swap(rhs);
1060 }
1061
1062 template<std::size_t N, std::size_t M,
1063     class CharT, class Traits>
1064 void
1065 swap(
1066     static_string<N, CharT, Traits>& lhs,
1067     static_string<M, CharT, Traits>& rhs)
1068 {
1069     lhs.swap(rhs);
1070 }
1071
1072 //
1073 // Input/Output
1074 //
1075
1076 template<std::size_t N, class CharT, class Traits>
1077 std::basic_ostream<CharT, Traits>& 
1078 operator<<(std::basic_ostream<CharT, Traits>& os, 
1079     static_string<N, CharT, Traits> const& str)
1080 {
1081     return os << static_cast<
1082         beast::basic_string_view<CharT, Traits>>(str);
1083 }
1084
1085 //
1086 // Numeric conversions
1087 //
1088
1089 /** Returns a static string representing an integer as a decimal.
1090
1091     @param x The signed or unsigned integer to convert.
1092     This must be an integral type.
1093
1094     @return A @ref static_string with an implementation defined
1095     maximum size large enough to hold the longest possible decimal
1096     representation of any integer of the given type.
1097 */
1098 template<
1099     class Integer
1100 #ifndef BOOST_BEAST_DOXYGEN
1101     ,class = typename std::enable_if<
1102         std::is_integral<Integer>::value>::type
1103 #endif
1104 >
1105 static_string<detail::max_digits(sizeof(Integer))>
1106 to_static_string(Integer x);
1107
1108 } // beast
1109 } // boost
1110
1111 #include <boost/beast/core/impl/static_string.hpp>
1112
1113 #endif