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
term()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&
operator =(static_string const & str)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&
operator =(static_string<M,CharT,Traits> const & str)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&
operator =(CharT ch)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&
operator =(std::initializer_list<CharT> init)185     operator=(std::initializer_list<CharT> init)
186     {
187         return assign(init);
188     }
189 
190     /// Assign from `string_view_type`.
191     static_string&
operator =(string_view_type sv)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&
assign(static_string<M,CharT,Traits> const & str)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&
assign(CharT const * s)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&
assign(std::initializer_list<CharT> init)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&
assign(string_view_type str)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
operator [](size_type pos)283     operator[](size_type pos)
284     {
285         return s_[pos];
286     }
287 
288     /// Access specified character.
289     const_reference
operator [](size_type pos) const290     operator[](size_type pos) const
291     {
292         return s_[pos];
293     }
294 
295     /// Accesses the first character.
296     CharT&
front()297     front()
298     {
299         return s_[0];
300     }
301 
302     /// Accesses the first character.
303     CharT const&
front() const304     front() const
305     {
306         return s_[0];
307     }
308 
309     /// Accesses the last character.
310     CharT&
back()311     back()
312     {
313         return s_[n_-1];
314     }
315 
316     /// Accesses the last character.
317     CharT const&
back() const318     back() const
319     {
320         return s_[n_-1];
321     }
322 
323     /// Returns a pointer to the first character of a string.
324     CharT*
data()325     data()
326     {
327         return &s_[0];
328     }
329 
330     /// Returns a pointer to the first character of a string.
331     CharT const*
data() const332     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*
c_str() const339     c_str() const
340     {
341         return data();
342     }
343 
344     /// Convert a static string to a `string_view_type`
operator string_view_type() const345     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
begin()357     begin()
358     {
359         return &s_[0];
360     }
361 
362     /// Returns an iterator to the beginning.
363     const_iterator
begin() const364     begin() const
365     {
366         return &s_[0];
367     }
368 
369     /// Returns an iterator to the beginning.
370     const_iterator
cbegin() const371     cbegin() const
372     {
373         return &s_[0];
374     }
375 
376     /// Returns an iterator to the end.
377     iterator
end()378     end()
379     {
380         return &s_[n_];
381     }
382 
383     /// Returns an iterator to the end.
384     const_iterator
end() const385     end() const
386     {
387         return &s_[n_];
388     }
389 
390     /// Returns an iterator to the end.
391     const_iterator
cend() const392     cend() const
393     {
394         return &s_[n_];
395     }
396 
397     /// Returns a reverse iterator to the beginning.
398     reverse_iterator
rbegin()399     rbegin()
400     {
401         return reverse_iterator{end()};
402     }
403 
404     /// Returns a reverse iterator to the beginning.
405     const_reverse_iterator
rbegin() const406     rbegin() const
407     {
408         return const_reverse_iterator{cend()};
409     }
410 
411     /// Returns a reverse iterator to the beginning.
412     const_reverse_iterator
crbegin() const413     crbegin() const
414     {
415         return const_reverse_iterator{cend()};
416     }
417 
418     /// Returns a reverse iterator to the end.
419     reverse_iterator
rend()420     rend()
421     {
422         return reverse_iterator{begin()};
423     }
424 
425     /// Returns a reverse iterator to the end.
426     const_reverse_iterator
rend() const427     rend() const
428     {
429         return const_reverse_iterator{cbegin()};
430     }
431 
432     /// Returns a reverse iterator to the end.
433     const_reverse_iterator
crend() const434     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
empty() const445     empty() const
446     {
447         return n_ == 0;
448     }
449 
450     /// Returns the number of characters, excluding the null terminator.
451     size_type
size() const452     size() const
453     {
454         return n_;
455     }
456 
457     /// Returns the number of characters, excluding the null terminator.
458     size_type
length() const459     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
max_size() const466     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
capacity() const481     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
shrink_to_fit()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&
insert(size_type index,CharT const * s)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&
insert(size_type index,static_string<M,CharT,Traits> const & str)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
insert(const_iterator pos,CharT ch)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
insert(const_iterator pos,std::initializer_list<CharT> init)549     insert(const_iterator pos, std::initializer_list<CharT> init)
550     {
551         return insert(pos, init.begin(), init.end());
552     }
553 
554     static_string&
insert(size_type index,string_view_type str)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
pop_back()585     pop_back()
586     {
587         Traits::assign(s_[--n_], 0);
588     }
589 
590     static_string&
append(size_type count,CharT ch)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&
append(static_string<M,CharT,Traits> const & str)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&
append(CharT const * s,size_type count)611     append(CharT const* s, size_type count)
612     {
613         insert(size(), s, count);
614         return *this;
615     }
616 
617     static_string&
append(CharT const * s)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
append(InputIt first,InputIt last)632     append(InputIt first, InputIt last)
633     {
634         insert(end(), first, last);
635         return *this;
636     }
637 
638     static_string&
append(std::initializer_list<CharT> init)639     append(std::initializer_list<CharT> init)
640     {
641         insert(end(), init);
642         return *this;
643     }
644 
645     static_string&
append(string_view_type sv)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
append(T const & t,size_type pos,size_type count=npos)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&
operator +=(static_string<M,CharT,Traits> const & str)665     operator+=(static_string<M, CharT, Traits> const& str)
666     {
667         return append(str.data(), str.size());
668     }
669 
670     static_string&
operator +=(CharT ch)671     operator+=(CharT ch)
672     {
673         push_back(ch);
674         return *this;
675     }
676 
677     static_string&
operator +=(CharT const * s)678     operator+=(CharT const* s)
679     {
680         return append(s);
681     }
682 
683     static_string&
operator +=(std::initializer_list<CharT> init)684     operator+=(std::initializer_list<CharT> init)
685     {
686         return append(init);
687     }
688 
689     static_string&
operator +=(string_view_type const & str)690     operator+=(string_view_type const& str)
691     {
692         return append(str);
693     }
694 
695     template<std::size_t M>
696     int
compare(static_string<M,CharT,Traits> const & str) const697     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
compare(size_type pos1,size_type count1,static_string<M,CharT,Traits> const & str) const705     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
compare(size_type pos1,size_type count1,static_string<M,CharT,Traits> const & str,size_type pos2,size_type count2=npos) const714     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
compare(CharT const * s) const723     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
compare(size_type pos1,size_type count1,CharT const * s) const730     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
compare(size_type pos1,size_type count1,CharT const * s,size_type count2) const738     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
compare(string_view_type str) const746     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
compare(size_type pos1,size_type count1,string_view_type str) const753     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
compare(size_type pos1,size_type count1,T const & t,size_type pos2,size_type count2=npos) const769     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
operator ==(static_string<N,CharT,Traits> const & lhs,static_string<M,CharT,Traits> const & rhs)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
operator !=(static_string<N,CharT,Traits> const & lhs,static_string<M,CharT,Traits> const & rhs)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
operator <(static_string<N,CharT,Traits> const & lhs,static_string<M,CharT,Traits> const & rhs)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
operator <=(static_string<N,CharT,Traits> const & lhs,static_string<M,CharT,Traits> const & rhs)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
operator >(static_string<N,CharT,Traits> const & lhs,static_string<M,CharT,Traits> const & rhs)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
operator >=(static_string<N,CharT,Traits> const & lhs,static_string<M,CharT,Traits> const & rhs)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
operator ==(CharT const * lhs,static_string<N,CharT,Traits> const & rhs)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
operator ==(static_string<N,CharT,Traits> const & lhs,CharT const * rhs)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
operator !=(CharT const * lhs,static_string<N,CharT,Traits> const & rhs)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
operator !=(static_string<N,CharT,Traits> const & lhs,CharT const * rhs)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
operator <(CharT const * lhs,static_string<N,CharT,Traits> const & rhs)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
operator <(static_string<N,CharT,Traits> const & lhs,CharT const * rhs)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
operator <=(CharT const * lhs,static_string<N,CharT,Traits> const & rhs)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
operator <=(static_string<N,CharT,Traits> const & lhs,CharT const * rhs)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
operator >(CharT const * lhs,static_string<N,CharT,Traits> const & rhs)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
operator >(static_string<N,CharT,Traits> const & lhs,CharT const * rhs)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
operator >=(CharT const * lhs,static_string<N,CharT,Traits> const & rhs)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
operator >=(static_string<N,CharT,Traits> const & lhs,CharT const * rhs)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
swap(static_string<N,CharT,Traits> & lhs,static_string<N,CharT,Traits> & rhs)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
swap(static_string<N,CharT,Traits> & lhs,static_string<M,CharT,Traits> & rhs)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>&
operator <<(std::basic_ostream<CharT,Traits> & os,static_string<N,CharT,Traits> const & str)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
1114