General Utility Library for C++14  2.7
string_view.h
Go to the documentation of this file.
1 
24 #ifndef GUL14_STRING_VIEW_H_
25 #define GUL14_STRING_VIEW_H_
26 
27 #include <cstddef>
28 #include <stdexcept>
29 #include <algorithm>
30 #include <iterator>
31 #include <string>
32 #include <cstring>
33 #include <iosfwd>
34 #include "gul14/internal.h"
35 
36 namespace gul14 {
37 
38 namespace detail {
39 
40 // A helper functor because sometimes we don't have lambdas
41 template <typename charT, typename traits>
42 class string_view_traits_eq {
43 public:
44  string_view_traits_eq ( charT ch ) : ch_(ch) {}
45  bool operator()( charT val ) const { return traits::eq (ch_, val); }
46  charT ch_;
47 };
48 
49 } // namespace detail
50 
51 // We use custom traits to allow constexpr operations on string_view
52 template <typename charT, typename BaseT = std::char_traits<charT>>
53 struct char_traits : public BaseT
54 {
55  using char_type = typename BaseT::char_type;
56  using int_type = typename BaseT::int_type;
57  using pos_type = typename BaseT::pos_type;
58  using off_type = typename BaseT::off_type;
59  using state_type = typename BaseT::state_type;
60 
61  using base_traits = BaseT;
62 
63  using BaseT::lt;
64  using BaseT::eq;
65 
66  static constexpr void assign(char_type& c1, const char_type& c2) noexcept
67  {
68  c1 = c2;
69  }
70 
71  static constexpr int compare(const char_type* s1, const char_type* s2, size_t n) noexcept
72  {
73  for (;n > 0; --n, ++s1, ++s2) {
74  if (lt(*s1, *s2))
75  return -1;
76  else if (lt(*s2, *s1))
77  return 1;
78  }
79  return 0;
80  }
81 
82  static constexpr size_t length(const char_type* s) noexcept
83  {
84  auto len = std::size_t{ };
85  while (!eq(s[len], char_type{ }))
86  ++len;
87  return len;
88  }
89 
90  static constexpr const char_type* find(const char_type* s, std::size_t n, const char_type& a) noexcept
91  {
92  for (;n > 0; --n, ++s) {
93  if (eq(*s, a))
94  return s;
95  }
96  return nullptr;
97  }
98 };
99 
100 
106 template<typename charT, typename traits = gul14::char_traits<charT>>
108 public:
109  // types
110  typedef traits traits_type;
111  typedef charT value_type;
112  typedef charT* pointer;
113  typedef const charT* const_pointer;
114  typedef charT& reference;
115  typedef const charT& const_reference;
116  typedef const_pointer const_iterator; // impl-defined
117  typedef const_iterator iterator;
118  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
119  typedef const_reverse_iterator reverse_iterator;
120  typedef std::size_t size_type;
121  typedef std::ptrdiff_t difference_type;
122  static constexpr size_type npos = size_type(-1);
123 
124  // construct/copy
125  constexpr basic_string_view() noexcept
126  : ptr_(NULL), len_(0) {}
127 
128  // by defaulting these functions, basic_string_ref becomes
129  // trivially copy/move constructible.
130  constexpr basic_string_view(const basic_string_view &rhs) noexcept = default;
131 
132  basic_string_view& operator=(const basic_string_view &rhs) noexcept = default;
133 
134  template<typename Allocator, typename Traits>
135  basic_string_view(const std::basic_string<charT, Traits,
136  Allocator>& str) noexcept
137  : ptr_(str.data()), len_(str.length()) {}
138 
139  constexpr basic_string_view(const charT* str)
140  : ptr_(str), len_(traits::length(str)) {}
141 
142  constexpr basic_string_view(const charT* str, size_type len)
143  : ptr_(str), len_(len) {}
144 
145  // iterators
146  constexpr const_iterator begin() const noexcept { return ptr_; }
147  constexpr const_iterator cbegin() const noexcept { return ptr_; }
148  constexpr const_iterator end() const noexcept { return ptr_ + len_; }
149  constexpr const_iterator cend() const noexcept { return ptr_ + len_; }
150  const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
151  const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
152  const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
153  const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
154 
155  // capacity
156  constexpr size_type size() const noexcept { return len_; }
157  constexpr size_type length() const noexcept { return len_; }
158  constexpr size_type max_size() const noexcept { return len_; }
159  constexpr bool empty() const noexcept { return len_ == 0; }
160 
161  // element access
162  constexpr const_reference operator[](size_type pos) const noexcept { return ptr_[pos]; }
163 
164  constexpr const_reference at(size_t pos) const {
165  return pos >= len_ ? throw std::out_of_range("gul14::string_view::at") : ptr_[pos];
166  }
167 
168  constexpr const_reference front() const { return ptr_[0]; }
169  constexpr const_reference back() const { return ptr_[len_-1]; }
170  constexpr const_pointer data() const noexcept { return ptr_; }
171 
172  // modifiers
173  constexpr void remove_prefix(size_type n) {
174  if ( n > len_ )
175  n = len_;
176  ptr_ += n;
177  len_ -= n;
178  }
179 
180  constexpr void remove_suffix(size_type n) {
181  if ( n > len_ )
182  n = len_;
183  len_ -= n;
184  }
185 
186  constexpr void swap(basic_string_view& s) noexcept {
187  std::swap(ptr_, s.ptr_);
188  std::swap(len_, s.len_);
189  }
190 
191  // basic_string_view string operations
192  template<typename Allocator>
193  explicit operator std::basic_string<charT, typename traits::base_traits, Allocator>() const {
194  return std::basic_string<charT, typename traits::base_traits, Allocator>(begin(), end());
195  }
196 
197  template<typename Allocator = std::allocator<charT> >
198  std::basic_string<charT, typename traits::base_traits, Allocator> to_string(const Allocator& a = Allocator()) const {
199  return std::basic_string<charT, typename traits::base_traits, Allocator>(begin(), end(), a);
200  }
201 
202  size_type copy(charT* s, size_type n, size_type pos=0) const {
203  if (pos > size())
204  throw std::out_of_range("string_view::copy" );
205  size_type rlen = (std::min)(n, len_ - pos);
206  // use std::copy(begin() + pos, begin() + pos + rlen, s) rather than
207  // std::copy_n(begin() + pos, rlen, s) to support pre-C++11 standard libraries
208  std::copy(begin() + pos, begin() + pos + rlen, s);
209  return rlen;
210  }
211 
212  constexpr basic_string_view substr(size_type pos, size_type n=npos) const {
213  if ( pos > size())
214  throw std::out_of_range ( "string_view::substr" );
215  if (n == npos || pos + n > size())
216  n = size () - pos;
217  return basic_string_view(data() + pos, n);
218  }
219 
220  constexpr int compare(basic_string_view x) const noexcept {
221  const int cmp = traits::compare(ptr_, x.ptr_, (std::min)(len_, x.len_));
222  return cmp != 0 ? cmp : (len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1);
223  }
224 
225  constexpr int compare(size_type pos1, size_type n1, basic_string_view x)
226  const noexcept {
227  return substr(pos1, n1).compare(x);
228  }
229 
230  constexpr int compare(size_type pos1, size_type n1,
231  basic_string_view x, size_type pos2, size_type n2) const {
232  return substr(pos1, n1).compare(x.substr(pos2, n2));
233  }
234 
235  constexpr int compare(const charT* x) const {
236  return compare(basic_string_view(x));
237  }
238 
239  constexpr int compare(size_type pos1, size_type n1, const charT* x) const {
240  return substr(pos1, n1).compare(basic_string_view(x));
241  }
242 
243  constexpr int compare(size_type pos1, size_type n1,
244  const charT* x, size_type n2) const {
245  return substr(pos1, n1).compare(basic_string_view(x, n2));
246  }
247 
248  // find
249  constexpr size_type find(basic_string_view s, size_type pos = 0) const noexcept {
250  if (pos > size())
251  return npos;
252  if (s.empty())
253  return pos;
254  if (len_ < s.len_)
255  return npos;
256  auto const end = len_ - s.len_;
257  for (auto cur = pos; cur <= end; ++cur) {
258  if (traits::compare(ptr_ + cur, s.ptr_, s.len_) == 0)
259  return cur;
260  }
261  return npos;
262  }
263  constexpr size_type find(charT c, size_type pos = 0) const noexcept
264  { return find(basic_string_view(&c, 1), pos); }
265  constexpr size_type find(const charT* s, size_type pos, size_type n) const noexcept
266  { return find(basic_string_view(s, n), pos); }
267  constexpr size_type find(const charT* s, size_type pos = 0) const noexcept
268  { return find(basic_string_view(s), pos); }
269 
270  // rfind
271  constexpr size_type rfind(basic_string_view s, size_type pos = npos) const noexcept {
272  if (len_ < s.len_)
273  return npos;
274  if (pos > len_ - s.len_)
275  pos = len_ - s.len_;
276  if (s.len_ == 0u) // an empty string is always found
277  return pos;
278  for (const charT* cur = ptr_ + pos; ; --cur) {
279  if (traits::compare(cur, s.ptr_, s.len_) == 0)
280  return cur - ptr_;
281  if (cur == ptr_)
282  return npos;
283  };
284  }
285  constexpr size_type rfind(charT c, size_type pos = npos) const noexcept
286  { return rfind(basic_string_view(&c, 1), pos); }
287  constexpr size_type rfind(const charT* s, size_type pos, size_type n) const noexcept
288  { return rfind(basic_string_view(s, n), pos); }
289  constexpr size_type rfind(const charT* s, size_type pos = npos) const noexcept
290  { return rfind(basic_string_view(s), pos); }
291 
292  // find_first_of
293  constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept {
294  if (pos >= len_ || s.len_ == 0)
295  return npos;
296  const_iterator iter = std::find_first_of
297  (this->cbegin () + pos, this->cend (), s.cbegin (), s.cend (), traits::eq);
298  return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter );
299  }
300  constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept
301  { return find_first_of(basic_string_view(&c, 1), pos); }
302  constexpr size_type find_first_of(const charT* s, size_type pos, size_type n) const noexcept
303  { return find_first_of(basic_string_view(s, n), pos); }
304  constexpr size_type find_first_of(const charT* s, size_type pos = 0) const noexcept
305  { return find_first_of(basic_string_view(s), pos); }
306 
307  // find_last_of
308  constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept {
309  if (s.len_ == 0u)
310  return npos;
311  if (pos >= len_)
312  pos = 0;
313  else
314  pos = len_ - (pos+1);
315  const_reverse_iterator iter = std::find_first_of
316  ( this->crbegin () + pos, this->crend (), s.cbegin (), s.cend (), traits::eq );
317  return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter);
318  }
319  constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept
320  { return find_last_of(basic_string_view(&c, 1), pos); }
321  constexpr size_type find_last_of(const charT* s, size_type pos, size_type n) const noexcept
322  { return find_last_of(basic_string_view(s, n), pos); }
323  constexpr size_type find_last_of(const charT* s, size_type pos = npos) const noexcept
324  { return find_last_of(basic_string_view(s), pos); }
325 
326  // find_first_not_of
327  constexpr size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept {
328  if (pos >= len_)
329  return npos;
330  if (s.len_ == 0)
331  return pos;
332  const_iterator iter = find_not_of ( this->cbegin () + pos, this->cend (), s );
333  return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter );
334  }
335  constexpr size_type find_first_not_of(charT c, size_type pos = 0) const noexcept
336  { return find_first_not_of(basic_string_view(&c, 1), pos); }
337  constexpr size_type find_first_not_of(const charT* s, size_type pos, size_type n) const noexcept
338  { return find_first_not_of(basic_string_view(s, n), pos); }
339  constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const noexcept
340  { return find_first_not_of(basic_string_view(s), pos); }
341 
342  // find_last_not_of
343  constexpr size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept {
344  if (pos >= len_)
345  pos = len_ - 1;
346  if (s.len_ == 0u)
347  return pos;
348  pos = len_ - (pos+1);
349  const_reverse_iterator iter = find_not_of ( this->crbegin () + pos, this->crend (), s );
350  return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter );
351  }
352  constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept
353  { return find_last_not_of(basic_string_view(&c, 1), pos); }
354  constexpr size_type find_last_not_of(const charT* s, size_type pos, size_type n) const noexcept
355  { return find_last_not_of(basic_string_view(s, n), pos); }
356  constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const noexcept
357  { return find_last_not_of(basic_string_view(s), pos); }
358 
359 private:
360  template <typename r_iter>
361  size_type reverse_distance(r_iter first, r_iter last) const noexcept {
362  // Portability note here: std::distance is not NOEXCEPT, but calling it with a string_view::reverse_iterator will not throw.
363  return len_ - 1 - std::distance ( first, last );
364  }
365 
366  template <typename Iterator>
367  Iterator find_not_of(Iterator first, Iterator last, basic_string_view s) const noexcept {
368  for (; first != last ; ++first)
369  if ( 0 == traits::find(s.ptr_, s.len_, *first))
370  return first;
371  return last;
372  }
373 
374  const charT *ptr_;
375  std::size_t len_;
376 };
377 
379 
380 // Comparison operators
381 // Equality
382 template<typename charT, typename traits>
383 inline bool operator==(basic_string_view<charT, traits> x,
385  if (x.size () != y.size ()) return false;
386  return x.compare(y) == 0;
387 }
388 
389 // Inequality
390 template<typename charT, typename traits>
391 inline bool operator!=(basic_string_view<charT, traits> x,
392  basic_string_view<charT, traits> y) noexcept {
393  if ( x.size () != y.size ()) return true;
394  return x.compare(y) != 0;
395 }
396 
397 // Less than
398 template<typename charT, typename traits>
399 inline bool operator<(basic_string_view<charT, traits> x,
400  basic_string_view<charT, traits> y) noexcept {
401  return x.compare(y) < 0;
402 }
403 
404 // Greater than
405 template<typename charT, typename traits>
406 inline bool operator>(basic_string_view<charT, traits> x,
407  basic_string_view<charT, traits> y) noexcept {
408  return x.compare(y) > 0;
409 }
410 
411 // Less than or equal to
412 template<typename charT, typename traits>
413 inline bool operator<=(basic_string_view<charT, traits> x,
414  basic_string_view<charT, traits> y) noexcept {
415  return x.compare(y) <= 0;
416 }
417 
418 // Greater than or equal to
419 template<typename charT, typename traits>
420 inline bool operator>=(basic_string_view<charT, traits> x,
421  basic_string_view<charT, traits> y) noexcept {
422  return x.compare(y) >= 0;
423 }
424 
425 // "sufficient additional overloads of comparison functions"
426 template<typename charT, typename traits, typename Allocator>
427 inline bool operator==(basic_string_view<charT, traits> x,
428  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
429  return x == basic_string_view<charT, traits>(y);
430 }
431 
432 template<typename charT, typename traits, typename Allocator>
433 inline bool operator==(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
434  basic_string_view<charT, traits> y) noexcept {
435  return basic_string_view<charT, traits>(x) == y;
436 }
437 
438 template<typename charT, typename traits>
439 inline bool operator==(basic_string_view<charT, traits> x,
440  const charT * y) noexcept {
441  return x == basic_string_view<charT, traits>(y);
442 }
443 
444 template<typename charT, typename traits>
445 inline bool operator==(const charT * x,
446  basic_string_view<charT, traits> y) noexcept {
447  return basic_string_view<charT, traits>(x) == y;
448 }
449 
450 template<typename charT, typename traits, typename Allocator>
451 inline bool operator!=(basic_string_view<charT, traits> x,
452  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
453  return x != basic_string_view<charT, traits>(y);
454 }
455 
456 template<typename charT, typename traits, typename Allocator>
457 inline bool operator!=(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
458  basic_string_view<charT, traits> y) noexcept {
459  return basic_string_view<charT, traits>(x) != y;
460 }
461 
462 template<typename charT, typename traits>
463 inline bool operator!=(basic_string_view<charT, traits> x,
464  const charT * y) noexcept {
465  return x != basic_string_view<charT, traits>(y);
466 }
467 
468 template<typename charT, typename traits>
469 inline bool operator!=(const charT * x,
470  basic_string_view<charT, traits> y) noexcept {
471  return basic_string_view<charT, traits>(x) != y;
472 }
473 
474 template<typename charT, typename traits, typename Allocator>
475 inline bool operator<(basic_string_view<charT, traits> x,
476  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
477  return x < basic_string_view<charT, traits>(y);
478 }
479 
480 template<typename charT, typename traits, typename Allocator>
481 inline bool operator<(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
482  basic_string_view<charT, traits> y) noexcept {
483  return basic_string_view<charT, traits>(x) < y;
484 }
485 
486 template<typename charT, typename traits>
487 inline bool operator<(basic_string_view<charT, traits> x,
488  const charT * y) noexcept {
489  return x < basic_string_view<charT, traits>(y);
490 }
491 
492 template<typename charT, typename traits>
493 inline bool operator<(const charT * x,
494  basic_string_view<charT, traits> y) noexcept {
495  return basic_string_view<charT, traits>(x) < y;
496 }
497 
498 template<typename charT, typename traits, typename Allocator>
499 inline bool operator>(basic_string_view<charT, traits> x,
500  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
501  return x > basic_string_view<charT, traits>(y);
502 }
503 
504 template<typename charT, typename traits, typename Allocator>
505 inline bool operator>(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
506  basic_string_view<charT, traits> y) noexcept {
507  return basic_string_view<charT, traits>(x) > y;
508 }
509 
510 template<typename charT, typename traits>
511 inline bool operator>(basic_string_view<charT, traits> x,
512  const charT * y) noexcept {
513  return x > basic_string_view<charT, traits>(y);
514 }
515 
516 template<typename charT, typename traits>
517 inline bool operator>(const charT * x,
518  basic_string_view<charT, traits> y) noexcept {
519  return basic_string_view<charT, traits>(x) > y;
520 }
521 
522 template<typename charT, typename traits, typename Allocator>
523 inline bool operator<=(basic_string_view<charT, traits> x,
524  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
525  return x <= basic_string_view<charT, traits>(y);
526 }
527 
528 template<typename charT, typename traits, typename Allocator>
529 inline bool operator<=(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
530  basic_string_view<charT, traits> y) noexcept {
531  return basic_string_view<charT, traits>(x) <= y;
532 }
533 
534 template<typename charT, typename traits>
535 inline bool operator<=(basic_string_view<charT, traits> x,
536  const charT * y) noexcept {
537  return x <= basic_string_view<charT, traits>(y);
538 }
539 
540 template<typename charT, typename traits>
541 inline bool operator<=(const charT * x,
542  basic_string_view<charT, traits> y) noexcept {
543  return basic_string_view<charT, traits>(x) <= y;
544 }
545 
546 template<typename charT, typename traits, typename Allocator>
547 inline bool operator>=(basic_string_view<charT, traits> x,
548  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
549  return x >= basic_string_view<charT, traits>(y);
550 }
551 
552 template<typename charT, typename traits, typename Allocator>
553 inline bool operator>=(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
554  basic_string_view<charT, traits> y) noexcept {
555  return basic_string_view<charT, traits>(x) >= y;
556 }
557 
558 template<typename charT, typename traits>
559 inline bool operator>=(basic_string_view<charT, traits> x,
560  const charT * y) noexcept {
561  return x >= basic_string_view<charT, traits>(y);
562 }
563 
564 template<typename charT, typename traits>
565 inline bool operator>=(const charT * x,
566  basic_string_view<charT, traits> y) noexcept {
567  return basic_string_view<charT, traits>(x) >= y;
568 }
569 
570 namespace detail {
571 
572 template<class charT, class traits>
573 inline void sv_insert_fill_chars(std::basic_ostream<charT, traits>& os, std::size_t n) {
574  enum { chunk_size = 8 };
575  charT fill_chars[chunk_size];
576  std::fill_n(fill_chars, static_cast< std::size_t >(chunk_size), os.fill());
577  for (; n >= chunk_size && os.good(); n -= chunk_size)
578  os.write(fill_chars, static_cast< std::size_t >(chunk_size));
579  if (n > 0 && os.good())
580  os.write(fill_chars, n);
581 }
582 
583 template<class charT, class traits>
584 void sv_insert_aligned(std::basic_ostream<charT, typename char_traits<charT>::base_traits>& os, const basic_string_view<charT,traits>& str) {
585  const std::size_t size = str.size();
586  const std::size_t alignment_size = static_cast< std::size_t >(os.width()) - size;
587  const bool align_left = (os.flags() & std::basic_ostream<charT, typename char_traits<charT>::base_traits>::adjustfield)
588  == std::basic_ostream<charT, typename char_traits<charT>::base_traits>::left;
589  if (!align_left) {
590  detail::sv_insert_fill_chars(os, alignment_size);
591  if (os.good())
592  os.write(str.data(), size);
593  }
594  else {
595  os.write(str.data(), size);
596  if (os.good())
597  detail::sv_insert_fill_chars(os, alignment_size);
598  }
599 }
600 
601 } // namespace detail
602 
603 // Inserter
604 template<class charT, class traits>
605 inline std::basic_ostream<charT, typename char_traits<charT>::base_traits>&
606 operator<<(std::basic_ostream<charT, typename char_traits<charT>::base_traits>& os,
607  const basic_string_view<charT,traits>& str) {
608  if (os.good()) {
609  const std::size_t size = str.size();
610  const std::size_t w = static_cast< std::size_t >(os.width());
611  if (w <= size)
612  os.write(str.data(), size);
613  else
614  detail::sv_insert_aligned(os, str);
615  os.width(0);
616  }
617  return os;
618 }
619 
621 
622 
629 
636 
643 
650 
651 
652 
653 // Custom extensions (Lars Froehlich)
654 
656 
657 inline std::string &operator+=(std::string &a, string_view b)
658 {
659  a.append(b.begin(), b.end());
660  return a;
661 }
662 
663 inline std::string operator+(std::string a, string_view b)
664 {
665  a += b;
666  return a;
667 }
668 
669 inline std::string operator+(string_view a, std::string b)
670 {
671  b.insert(b.begin(), a.begin(), a.end());
672  return b;
673 }
674 
676 
677 } // namespace gul14
678 
679 #endif
gul14::swap
void swap(SmallVector< ElementT, in_capacity > &a, SmallVector< ElementT, in_capacity > &b)
Exchange the contents of one SmallVector with those of another one.
Definition: SmallVector.h:1645
gul14::basic_string_view
A view to a contiguous sequence of chars or char-like objects.
Definition: string_view.h:107
gul14::string_view
basic_string_view< char > string_view
A view to a contiguous sequence of chars.
Definition: string_view.h:628
internal.h
Definition of macros used internally by GUL.
gul14
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26