Coverage Report

Created: 2026-02-09 06:05

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