resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmString.hxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #pragma once
4
5 #include "cmConfigure.h" // IWYU pragma: keep
6
7 #include <algorithm>
8 #include <cstddef>
9 #include <functional>
10 #include <initializer_list>
11 #include <memory>
12 #include <ostream>
13 #include <string>
14 #include <type_traits>
15 #include <utility>
16
17 #include <cm/string_view>
18 #include <cmext/string_view>
19
20 namespace cm {
21
22 class String;
23
24 /**
25  * Trait to convert type T into a String.
26  * Implementations must derive from 'std::true_type'
27  * and define an 'into_string' member that accepts
28  * type T (by value or reference) and returns one of:
29  *
30  * - 'std::string' to construct an owned instance.
31  * - 'cm::string_view' to construct a borrowed or null instances.
32  *   The buffer from which the view is borrowed must outlive
33  *   all copies of the resulting String, e.g. static storage.
34  * - 'cm::String' for already-constructed instances.
35  */
36 template <typename T>
37 struct IntoString : std::false_type
38 {
39 };
40
41 template <typename T>
42 struct IntoString<T&> : IntoString<T>
43 {
44 };
45
46 template <typename T>
47 struct IntoString<T const> : IntoString<T>
48 {
49 };
50
51 template <typename T>
52 struct IntoString<T const*> : IntoString<T*>
53 {
54 };
55
56 template <typename T, std::string::size_type N>
57 struct IntoString<T const[N]> : IntoString<T[N]>
58 {
59 };
60
61 template <>
62 struct IntoString<char*> : std::true_type
63 {
64   static String into_string(const char* s);
65 };
66
67 template <>
68 struct IntoString<std::nullptr_t> : std::true_type
69 {
70   static string_view into_string(std::nullptr_t) { return string_view(); }
71 };
72
73 template <std::string::size_type N>
74 struct IntoString<char[N]> : std::true_type
75 {
76   static std::string into_string(char const (&s)[N])
77   {
78     return std::string(s, N - 1);
79   }
80 };
81
82 template <>
83 struct IntoString<std::string> : std::true_type
84 {
85   static std::string into_string(std::string s) { return s; }
86 };
87
88 template <>
89 struct IntoString<char> : std::true_type
90 {
91   static std::string into_string(char const& c) { return std::string(1, c); }
92 };
93
94 /**
95  * Trait to convert type T into a 'cm::string_view'.
96  * Implementations must derive from 'std::true_type' and
97  * define a 'view' member that accepts type T (by reference)
98  * and returns a 'cm::string_view'.
99  */
100 template <typename T>
101 struct AsStringView : std::false_type
102 {
103 };
104
105 template <typename T>
106 struct AsStringView<T&> : AsStringView<T>
107 {
108 };
109
110 template <typename T>
111 struct AsStringView<T const> : AsStringView<T>
112 {
113 };
114
115 template <typename T>
116 struct AsStringView<T const*> : AsStringView<T*>
117 {
118 };
119
120 template <typename T, std::string::size_type N>
121 struct AsStringView<T const[N]> : AsStringView<T[N]>
122 {
123 };
124
125 template <>
126 struct AsStringView<char*> : std::true_type
127 {
128   static string_view view(const char* s) { return s; }
129 };
130
131 template <std::string::size_type N>
132 struct AsStringView<char[N]> : std::true_type
133 {
134   static string_view view(char const (&s)[N]) { return string_view(s, N - 1); }
135 };
136
137 template <>
138 struct AsStringView<std::string> : std::true_type
139 {
140   static string_view view(std::string const& s) { return s; }
141 };
142
143 template <>
144 struct AsStringView<char> : std::true_type
145 {
146   static string_view view(const char& s) { return string_view(&s, 1); }
147 };
148
149 template <>
150 struct AsStringView<string_view> : std::true_type
151 {
152   static string_view view(string_view const& s) { return s; }
153 };
154
155 template <>
156 struct AsStringView<static_string_view> : std::true_type
157 {
158   static string_view view(static_string_view const& s) { return s; }
159 };
160
161 template <>
162 struct AsStringView<String> : std::true_type
163 {
164   static string_view view(String const& s);
165 };
166
167 /**
168  * \class String
169  *
170  * A custom string type that holds a view of a string buffer
171  * and optionally shares ownership of the buffer.  Instances
172  * may have one of the following states:
173  *
174  * - null: views and owns nothing.
175  *   Conversion to 'bool' is 'false'.
176  *   'data()' and 'c_str()' return nullptr.
177  *   'size()' returns 0.
178  *   'str()' returns an empty string.
179  *
180  * - borrowed: views a string but does not own it.  This is used
181  *   to bind to static storage (e.g. string literals) or for
182  *   temporary instances that do not outlive the borrowed buffer.
183  *   Copies and substrings still borrow the original buffer.
184  *   Mutation allocates a new internal string and converts to
185  *   the 'owned' state.
186  *   Conversion to 'bool' is 'true'.
187  *   'c_str()' may internally mutate to the 'owned' state.
188  *   'str()' internally mutates to the 'owned' state.
189  *
190  * - owned: views an immutable 'std::string' instance owned internally.
191  *   Copies and substrings share ownership of the internal string.
192  *   Mutation allocates a new internal string.
193  *   Conversion to 'bool' is 'true'.
194  */
195 class String
196 {
197   enum class Private
198   {
199   };
200
201 public:
202   using traits_type = std::string::traits_type;
203   using value_type = string_view::value_type;
204   using pointer = string_view::pointer;
205   using const_pointer = string_view::const_pointer;
206   using reference = string_view::reference;
207   using const_reference = string_view::const_reference;
208   using const_iterator = string_view::const_iterator;
209   using iterator = string_view::const_iterator;
210   using const_reverse_iterator = string_view::const_reverse_iterator;
211   using reverse_iterator = string_view::const_reverse_iterator;
212   using difference_type = string_view::difference_type;
213   using size_type = string_view::size_type;
214
215   static size_type const npos = string_view::npos;
216
217   /** Construct a null string.  */
218   String() = default;
219
220   /** Construct from any type implementing the IntoString trait.  */
221   template <typename T,
222             typename = typename std::enable_if<IntoString<T>::value>::type>
223   String(T&& s)
224     : String(IntoString<T>::into_string(std::forward<T>(s)), Private())
225   {
226   }
227
228   /**
229    * Construct via static_string_view constructor.
230    * explicit is required to avoid ambiguous overloaded operators (i.e ==,
231    * etc...) with the ones provided by string_view.
232    */
233   explicit String(static_string_view s)
234     : String(s, Private())
235   {
236   }
237   /**
238    * Construct via string_view constructor.
239    * explicit is required to avoid ambiguous overloaded operators (i.e ==,
240    * etc...) with the ones provided by string_view.
241    */
242   explicit String(string_view s)
243     : String(std::string(s), Private())
244   {
245   }
246
247   /** Construct via std::string initializer list constructor.  */
248   String(std::initializer_list<char> il)
249     : String(std::string(il))
250   {
251   }
252
253   /** Construct by copying the specified buffer.  */
254   String(const char* d, size_type s)
255     : String(std::string(d, s))
256   {
257   }
258
259   /** Construct by copying from input iterator range.  */
260   template <typename InputIterator>
261   String(InputIterator first, InputIterator last)
262     : String(std::string(first, last))
263   {
264   }
265
266   /** Construct a string with 'n' copies of character 'c'.  */
267   String(size_type n, char c)
268     : String(std::string(n, c))
269   {
270   }
271
272   /** Construct from a substring of another String instance.
273       This shares ownership of the other string's buffer
274       but views only a substring.  */
275   String(String const& s, size_type pos, size_type count = npos)
276     : string_(s.string_)
277     , view_(s.data() + pos, std::min(count, s.size() - pos))
278   {
279   }
280
281   /** Construct by moving from another String instance.
282       The other instance is left as a null string.  */
283   String(String&& s) noexcept
284     : string_(std::move(s.string_))
285     , view_(s.view_)
286   {
287     s.view_ = string_view();
288   }
289
290   /** Construct by copying from another String instance.
291       This shares ownership of the other string's buffer.  */
292   String(String const&) noexcept = default;
293
294   ~String() = default;
295
296   /** Construct by borrowing an externally-owned buffer.  The buffer
297       must outlive the returned instance and all copies of it.  */
298   static String borrow(string_view v) { return String(v, Private()); }
299
300   /** Assign by moving from another String instance.
301       The other instance is left as a null string.  */
302   String& operator=(String&& s) noexcept
303   {
304     this->string_ = std::move(s.string_);
305     this->view_ = s.view_;
306     s.view_ = string_view();
307     return *this;
308   }
309
310   /** Assign by copying from another String instance.
311       This shares ownership of the other string's buffer.  */
312   String& operator=(String const&) noexcept = default;
313
314   String& operator=(static_string_view s)
315   {
316     *this = String(s);
317     return *this;
318   }
319   String& operator=(string_view s)
320   {
321     *this = String(s);
322     return *this;
323   }
324
325   /** Assign from any type implementing the IntoString trait.  */
326   template <typename T>
327   typename // NOLINT(*)
328     std::enable_if<IntoString<T>::value, String&>::type
329     operator=(T&& s)
330   {
331     *this = String(std::forward<T>(s));
332     return *this;
333   }
334
335   /** Assign via std::string initializer list constructor.  */
336   String& operator=(std::initializer_list<char> il)
337   {
338     *this = String(il);
339     return *this;
340   }
341
342   /** Return true if the instance is not a null string.  */
343   explicit operator bool() const noexcept { return this->data() != nullptr; }
344
345   /** Return a view of the string.  */
346   string_view view() const noexcept { return this->view_; }
347   operator string_view() const noexcept { return this->view(); }
348
349   /** Return true if the instance is an empty stringn or null string.  */
350   bool empty() const noexcept { return this->view_.empty(); }
351
352   /** Return a pointer to the start of the string.  */
353   const char* data() const noexcept { return this->view_.data(); }
354
355   /** Return the length of the string in bytes.  */
356   size_type size() const noexcept { return this->view_.size(); }
357   size_type length() const noexcept { return this->view_.length(); }
358
359   /** Return the character at the given position.
360       No bounds checking is performed.  */
361   char operator[](size_type pos) const noexcept { return this->view_[pos]; }
362
363   /** Return the character at the given position.
364       If the position is out of bounds, throws std::out_of_range.  */
365   char at(size_type pos) const { return this->view_.at(pos); }
366
367   char front() const noexcept { return this->view_.front(); }
368
369   char back() const noexcept { return this->view_.back(); }
370
371   /** Return true if this instance is stable and otherwise false.
372       An instance is stable if it is in the 'null' state or if it is
373       an 'owned' state not produced by substring operations, or
374       after a call to 'stabilize()' or 'str()'.  */
375   bool is_stable() const;
376
377   /** If 'is_stable()' does not return true, mutate so it does.  */
378   void stabilize();
379
380   /** Get a pointer to a normal std::string if 'is_stable()' returns
381       true and otherwise nullptr.  The pointer is valid until this
382       instance is mutated or destroyed.  */
383   std::string const* str_if_stable() const;
384
385   /** Get a reference to a normal std::string.  The reference
386       is valid until this instance is mutated or destroyed.  */
387   std::string const& str();
388
389   /** Get a pointer to a C-style null-terminated string
390       containing the same value as this instance.  The pointer
391       is valid until this instance is mutated, destroyed,
392       or str() is called.  */
393   const char* c_str();
394
395   const_iterator begin() const noexcept { return this->view_.begin(); }
396   const_iterator end() const noexcept { return this->view_.end(); }
397   const_iterator cbegin() const noexcept { return this->begin(); }
398   const_iterator cend() const noexcept { return this->end(); }
399
400   const_reverse_iterator rbegin() const noexcept
401   {
402     return this->view_.rbegin();
403   }
404   const_reverse_iterator rend() const noexcept { return this->view_.rend(); }
405   const_reverse_iterator crbegin() const noexcept { return this->rbegin(); }
406   const_reverse_iterator crend() const noexcept { return this->rend(); }
407
408   /** Append to the string using any type that implements the
409       AsStringView trait.  */
410   template <typename T>
411   typename std::enable_if<AsStringView<T>::value, String&>::type operator+=(
412     T&& s)
413   {
414     string_view v = AsStringView<T>::view(std::forward<T>(s));
415     std::string r;
416     r.reserve(this->size() + v.size());
417     r.assign(this->data(), this->size());
418     r.append(v.data(), v.size());
419     return *this = std::move(r);
420   }
421
422   /** Assign to an empty string.  */
423   void clear() { *this = ""_s; }
424
425   /** Insert 'count' copies of 'ch' at position 'index'.  */
426   String& insert(size_type index, size_type count, char ch);
427
428   /** Erase 'count' characters starting at position 'index'.  */
429   String& erase(size_type index = 0, size_type count = npos);
430
431   void push_back(char ch)
432   {
433     std::string s;
434     s.reserve(this->size() + 1);
435     s.assign(this->data(), this->size());
436     s.push_back(ch);
437     *this = std::move(s);
438   }
439
440   void pop_back() { *this = String(*this, 0, this->size() - 1); }
441
442   template <typename T>
443   typename std::enable_if<AsStringView<T>::value, String&>::type replace(
444     size_type pos, size_type count, T&& s)
445   {
446     const_iterator first = this->begin() + pos;
447     const_iterator last = first + count;
448     return this->replace(first, last, std::forward<T>(s));
449   }
450
451   template <typename InputIterator>
452   String& replace(const_iterator first, const_iterator last,
453                   InputIterator first2, InputIterator last2)
454   {
455     std::string out;
456     out.append(this->view_.begin(), first);
457     out.append(first2, last2);
458     out.append(last, this->view_.end());
459     return *this = std::move(out);
460   }
461
462   template <typename T>
463   typename std::enable_if<AsStringView<T>::value, String&>::type replace(
464     const_iterator first, const_iterator last, T&& s)
465   {
466     string_view v = AsStringView<T>::view(std::forward<T>(s));
467     std::string out;
468     out.reserve((first - this->view_.begin()) + v.size() +
469                 (this->view_.end() - last));
470     out.append(this->view_.begin(), first);
471     out.append(v.data(), v.size());
472     out.append(last, this->view_.end());
473     return *this = std::move(out);
474   }
475
476   template <typename T>
477   typename std::enable_if<AsStringView<T>::value, String&>::type replace(
478     size_type pos, size_type count, T&& s, size_type pos2,
479     size_type count2 = npos)
480   {
481     string_view v = AsStringView<T>::view(std::forward<T>(s));
482     v = v.substr(pos2, count2);
483     return this->replace(pos, count, v);
484   }
485
486   String& replace(size_type pos, size_type count, size_type count2, char ch)
487   {
488     const_iterator first = this->begin() + pos;
489     const_iterator last = first + count;
490     return this->replace(first, last, count2, ch);
491   }
492
493   String& replace(const_iterator first, const_iterator last, size_type count2,
494                   char ch)
495   {
496     std::string out;
497     out.reserve((first - this->view_.begin()) + count2 +
498                 (this->view_.end() - last));
499     out.append(this->view_.begin(), first);
500     out.append(count2, ch);
501     out.append(last, this->view_.end());
502     return *this = std::move(out);
503   }
504
505   size_type copy(char* dest, size_type count, size_type pos = 0) const;
506
507   void resize(size_type count) { this->resize(count, char()); }
508
509   void resize(size_type count, char ch)
510   {
511     std::string s;
512     s.reserve(count);
513     if (count <= this->size()) {
514       s.assign(this->data(), count);
515     } else {
516       s.assign(this->data(), this->size());
517       s.resize(count, ch);
518     }
519     *this = std::move(s);
520   }
521
522   void swap(String& other)
523   {
524     std::swap(this->string_, other.string_);
525     std::swap(this->view_, other.view_);
526   }
527
528   /** Return a substring starting at position 'pos' and
529       consisting of at most 'count' characters.  */
530   String substr(size_type pos = 0, size_type count = npos) const;
531
532   template <typename T>
533   typename std::enable_if<AsStringView<T>::value, int>::type compare(
534     T&& s) const
535   {
536     return this->view_.compare(AsStringView<T>::view(std::forward<T>(s)));
537   }
538
539   int compare(size_type pos1, size_type count1, string_view v) const
540   {
541     return this->view_.compare(pos1, count1, v);
542   }
543
544   int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
545               size_type count2) const
546   {
547     return this->view_.compare(pos1, count1, v, pos2, count2);
548   }
549
550   int compare(size_type pos1, size_type count1, const char* s) const
551   {
552     return this->view_.compare(pos1, count1, s);
553   }
554
555   int compare(size_type pos1, size_type count1, const char* s,
556               size_type count2) const
557   {
558     return this->view_.compare(pos1, count1, s, count2);
559   }
560
561   template <typename T>
562   typename std::enable_if<AsStringView<T>::value, size_type>::type find(
563     T&& s, size_type pos = 0) const
564   {
565     string_view v = AsStringView<T>::view(std::forward<T>(s));
566     return this->view_.find(v, pos);
567   }
568
569   size_type find(const char* s, size_type pos, size_type count) const
570   {
571     return this->view_.find(s, pos, count);
572   }
573
574   template <typename T>
575   typename std::enable_if<AsStringView<T>::value, size_type>::type rfind(
576     T&& s, size_type pos = npos) const
577   {
578     string_view v = AsStringView<T>::view(std::forward<T>(s));
579     return this->view_.rfind(v, pos);
580   }
581
582   size_type rfind(const char* s, size_type pos, size_type count) const
583   {
584     return this->view_.rfind(s, pos, count);
585   }
586
587   template <typename T>
588   typename std::enable_if<AsStringView<T>::value, size_type>::type
589   find_first_of(T&& s, size_type pos = 0) const
590   {
591     string_view v = AsStringView<T>::view(std::forward<T>(s));
592     return this->view_.find_first_of(v, pos);
593   }
594
595   size_type find_first_of(const char* s, size_type pos, size_type count) const
596   {
597     return this->view_.find_first_of(s, pos, count);
598   }
599
600   template <typename T>
601   typename std::enable_if<AsStringView<T>::value, size_type>::type
602   find_first_not_of(T&& s, size_type pos = 0) const
603   {
604     string_view v = AsStringView<T>::view(std::forward<T>(s));
605     return this->view_.find_first_not_of(v, pos);
606   }
607
608   size_type find_first_not_of(const char* s, size_type pos,
609                               size_type count) const
610   {
611     return this->view_.find_first_not_of(s, pos, count);
612   }
613
614   template <typename T>
615   typename std::enable_if<AsStringView<T>::value, size_type>::type
616   find_last_of(T&& s, size_type pos = npos) const
617   {
618     string_view v = AsStringView<T>::view(std::forward<T>(s));
619     return this->view_.find_last_of(v, pos);
620   }
621
622   size_type find_last_of(const char* s, size_type pos, size_type count) const
623   {
624     return this->view_.find_last_of(s, pos, count);
625   }
626
627   template <typename T>
628   typename std::enable_if<AsStringView<T>::value, size_type>::type
629   find_last_not_of(T&& s, size_type pos = npos) const
630   {
631     string_view v = AsStringView<T>::view(std::forward<T>(s));
632     return this->view_.find_last_not_of(v, pos);
633   }
634
635   size_type find_last_not_of(const char* s, size_type pos,
636                              size_type count) const
637   {
638     return this->view_.find_last_not_of(s, pos, count);
639   }
640
641 private:
642   // Internal constructor to move from existing String.
643   String(String&& s, Private) noexcept
644     : String(std::move(s))
645   {
646   }
647
648   // Internal constructor for dynamically allocated string.
649   String(std::string&& s, Private);
650
651   // Internal constructor for view of statically allocated string.
652   String(string_view v, Private)
653     : view_(v)
654   {
655   }
656
657   void internally_mutate_to_stable_string();
658
659   std::shared_ptr<std::string const> string_;
660   string_view view_;
661 };
662
663 /**
664  * Trait for comparable types.
665  */
666 template <typename T>
667 struct IsComparable : std::false_type
668 {
669 };
670
671 template <typename T>
672 struct IsComparable<T&> : IsComparable<T>
673 {
674 };
675
676 template <typename T>
677 struct IsComparable<T const> : IsComparable<T>
678 {
679 };
680
681 template <typename T>
682 struct IsComparable<T const*> : IsComparable<T*>
683 {
684 };
685
686 template <typename T, std::string::size_type N>
687 struct IsComparable<T const[N]> : IsComparable<T[N]>
688 {
689 };
690
691 template <>
692 struct IsComparable<char*> : std::true_type
693 {
694 };
695
696 template <std::string::size_type N>
697 struct IsComparable<char[N]> : std::true_type
698 {
699 };
700
701 template <>
702 struct IsComparable<std::string> : std::true_type
703 {
704 };
705
706 template <>
707 struct IsComparable<char> : std::true_type
708 {
709 };
710
711 /** comparison operators */
712 inline bool operator==(const String& l, const String& r)
713 {
714   return l.view() == r.view();
715 }
716 template <typename L>
717 typename std::enable_if<IsComparable<L>::value, bool>::type operator==(
718   L&& l, const String& r)
719 {
720   return AsStringView<L>::view(std::forward<L>(l)) == r.view();
721 }
722 template <typename R>
723 typename std::enable_if<IsComparable<R>::value, bool>::type operator==(
724   const String& l, R&& r)
725 {
726   return l.view() == AsStringView<R>::view(std::forward<R>(r));
727 }
728
729 inline bool operator!=(const String& l, const String& r)
730 {
731   return l.view() != r.view();
732 }
733 template <typename L>
734 typename std::enable_if<IsComparable<L>::value, bool>::type operator!=(
735   L&& l, const String& r)
736 {
737   return AsStringView<L>::view(std::forward<L>(l)) != r.view();
738 }
739 template <typename R>
740 typename std::enable_if<IsComparable<R>::value, bool>::type operator!=(
741   const String& l, R&& r)
742 {
743   return l.view() != AsStringView<R>::view(std::forward<R>(r));
744 }
745
746 inline bool operator<(const String& l, const String& r)
747 {
748   return l.view() < r.view();
749 }
750 template <typename L>
751 typename std::enable_if<IsComparable<L>::value, bool>::type operator<(
752   L&& l, const String& r)
753 {
754   return AsStringView<L>::view(std::forward<L>(l)) < r.view();
755 }
756 template <typename R>
757 typename std::enable_if<IsComparable<R>::value, bool>::type operator<(
758   const String& l, R&& r)
759 {
760   return l.view() < AsStringView<R>::view(std::forward<R>(r));
761 }
762
763 inline bool operator<=(const String& l, const String& r)
764 {
765   return l.view() <= r.view();
766 }
767 template <typename L>
768 typename std::enable_if<IsComparable<L>::value, bool>::type operator<=(
769   L&& l, const String& r)
770 {
771   return AsStringView<L>::view(std::forward<L>(l)) <= r.view();
772 }
773 template <typename R>
774 typename std::enable_if<IsComparable<R>::value, bool>::type operator<=(
775   const String& l, R&& r)
776 {
777   return l.view() <= AsStringView<R>::view(std::forward<R>(r));
778 }
779
780 inline bool operator>(const String& l, const String& r)
781 {
782   return l.view() > r.view();
783 }
784 template <typename L>
785 typename std::enable_if<IsComparable<L>::value, bool>::type operator>(
786   L&& l, const String& r)
787 {
788   return AsStringView<L>::view(std::forward<L>(l)) > r.view();
789 }
790 template <typename R>
791 typename std::enable_if<IsComparable<R>::value, bool>::type operator>(
792   const String& l, R&& r)
793 {
794   return l.view() > AsStringView<R>::view(std::forward<R>(r));
795 }
796
797 inline bool operator>=(const String& l, const String& r)
798 {
799   return l.view() >= r.view();
800 }
801 template <typename L>
802 typename std::enable_if<IsComparable<L>::value, bool>::type operator>=(
803   L&& l, const String& r)
804 {
805   return AsStringView<L>::view(std::forward<L>(l)) >= r.view();
806 }
807 template <typename R>
808 typename std::enable_if<IsComparable<R>::value, bool>::type operator>=(
809   const String& l, R&& r)
810 {
811   return l.view() >= AsStringView<R>::view(std::forward<R>(r));
812 }
813
814 std::ostream& operator<<(std::ostream& os, String const& s);
815 std::string& operator+=(std::string& self, String const& s);
816
817 template <typename L, typename R>
818 struct StringOpPlus
819 {
820   L l;
821   R r;
822 #if defined(__SUNPRO_CC)
823   StringOpPlus(L in_l, R in_r)
824     : l(in_l)
825     , r(in_r)
826   {
827   }
828 #endif
829   operator std::string() const;
830   std::string::size_type size() const
831   {
832     return this->l.size() + this->r.size();
833   }
834 };
835
836 template <typename T>
837 struct StringAdd
838 {
839   static const bool value = AsStringView<T>::value;
840   using temp_type = string_view;
841   template <typename S>
842   static temp_type temp(S&& s)
843   {
844     return AsStringView<T>::view(std::forward<S>(s));
845   }
846 };
847
848 template <typename L, typename R>
849 struct StringAdd<StringOpPlus<L, R>> : std::true_type
850 {
851   using temp_type = StringOpPlus<L, R> const&;
852   static temp_type temp(temp_type s) { return s; }
853 };
854
855 template <typename L, typename R>
856 StringOpPlus<L, R>::operator std::string() const
857 {
858   std::string s;
859   s.reserve(this->size());
860   s += *this;
861   return s;
862 }
863
864 template <typename L, typename R>
865 std::string& operator+=(std::string& s, StringOpPlus<L, R> const& a)
866 {
867   s.reserve(s.size() + a.size());
868   s += a.l;
869   s += a.r;
870   return s;
871 }
872
873 template <typename L, typename R>
874 String& operator+=(String& s, StringOpPlus<L, R> const& a)
875 {
876   std::string r;
877   r.reserve(s.size() + a.size());
878   r.assign(s.data(), s.size());
879   r += a.l;
880   r += a.r;
881   s = std::move(r);
882   return s;
883 }
884
885 template <typename L, typename R>
886 std::ostream& operator<<(std::ostream& os, StringOpPlus<L, R> const& a)
887 {
888   return os << a.l << a.r;
889 }
890
891 template <typename L, typename R>
892 struct IntoString<StringOpPlus<L, R>> : std::true_type
893 {
894   static std::string into_string(StringOpPlus<L, R> const& a) { return a; }
895 };
896
897 template <typename L, typename R>
898 typename std::enable_if<StringAdd<L>::value && StringAdd<R>::value,
899                         StringOpPlus<typename StringAdd<L>::temp_type,
900                                      typename StringAdd<R>::temp_type>>::type
901 operator+(L&& l, R&& r)
902 {
903   return { StringAdd<L>::temp(std::forward<L>(l)),
904            StringAdd<R>::temp(std::forward<R>(r)) };
905 }
906
907 template <typename LL, typename LR, typename R>
908 typename std::enable_if<AsStringView<R>::value, bool>::type operator==(
909   StringOpPlus<LL, LR> const& l, R&& r)
910 {
911   return std::string(l) == AsStringView<R>::view(std::forward<R>(r));
912 }
913
914 template <typename L, typename RL, typename RR>
915 typename std::enable_if<AsStringView<L>::value, bool>::type operator==(
916   L&& l, StringOpPlus<RL, RR> const& r)
917 {
918   return AsStringView<L>::view(std::forward<L>(l)) == std::string(r);
919 }
920
921 } // namespace cm
922
923 namespace std {
924
925 template <>
926 struct hash<cm::String>
927 {
928   using argument_type = cm::String;
929   using result_type = size_t;
930
931   result_type operator()(argument_type const& s) const noexcept
932   {
933     result_type const h(std::hash<cm::string_view>{}(s.view()));
934     return h;
935   }
936 };
937 }