General Utility Library for C++14  2.8
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  size_type copy(charT* s, size_type n, size_type pos=0) const {
198  if (pos > size())
199  throw std::out_of_range("string_view::copy" );
200  size_type rlen = (std::min)(n, len_ - pos);
201  // use std::copy(begin() + pos, begin() + pos + rlen, s) rather than
202  // std::copy_n(begin() + pos, rlen, s) to support pre-C++11 standard libraries
203  std::copy(begin() + pos, begin() + pos + rlen, s);
204  return rlen;
205  }
206 
207  constexpr basic_string_view substr(size_type pos, size_type n=npos) const {
208  if ( pos > size())
209  throw std::out_of_range ( "string_view::substr" );
210  if (n == npos || pos + n > size())
211  n = size () - pos;
212  return basic_string_view(data() + pos, n);
213  }
214 
215  constexpr int compare(basic_string_view x) const noexcept {
216  const int cmp = traits::compare(ptr_, x.ptr_, (std::min)(len_, x.len_));
217  return cmp != 0 ? cmp : (len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1);
218  }
219 
220  constexpr int compare(size_type pos1, size_type n1, basic_string_view x)
221  const noexcept {
222  return substr(pos1, n1).compare(x);
223  }
224 
225  constexpr int compare(size_type pos1, size_type n1,
226  basic_string_view x, size_type pos2, size_type n2) const {
227  return substr(pos1, n1).compare(x.substr(pos2, n2));
228  }
229 
230  constexpr int compare(const charT* x) const {
231  return compare(basic_string_view(x));
232  }
233 
234  constexpr int compare(size_type pos1, size_type n1, const charT* x) const {
235  return substr(pos1, n1).compare(basic_string_view(x));
236  }
237 
238  constexpr int compare(size_type pos1, size_type n1,
239  const charT* x, size_type n2) const {
240  return substr(pos1, n1).compare(basic_string_view(x, n2));
241  }
242 
243  // find
244  constexpr size_type find(basic_string_view s, size_type pos = 0) const noexcept {
245  if (pos > size())
246  return npos;
247  if (s.empty())
248  return pos;
249  if (len_ < s.len_)
250  return npos;
251  auto const end = len_ - s.len_;
252  for (auto cur = pos; cur <= end; ++cur) {
253  if (traits::compare(ptr_ + cur, s.ptr_, s.len_) == 0)
254  return cur;
255  }
256  return npos;
257  }
258  constexpr size_type find(charT c, size_type pos = 0) const noexcept
259  { return find(basic_string_view(&c, 1), pos); }
260  constexpr size_type find(const charT* s, size_type pos, size_type n) const noexcept
261  { return find(basic_string_view(s, n), pos); }
262  constexpr size_type find(const charT* s, size_type pos = 0) const noexcept
263  { return find(basic_string_view(s), pos); }
264 
265  // rfind
266  constexpr size_type rfind(basic_string_view s, size_type pos = npos) const noexcept {
267  if (len_ < s.len_)
268  return npos;
269  if (pos > len_ - s.len_)
270  pos = len_ - s.len_;
271  if (s.len_ == 0u) // an empty string is always found
272  return pos;
273  for (const charT* cur = ptr_ + pos; ; --cur) {
274  if (traits::compare(cur, s.ptr_, s.len_) == 0)
275  return cur - ptr_;
276  if (cur == ptr_)
277  return npos;
278  };
279  }
280  constexpr size_type rfind(charT c, size_type pos = npos) const noexcept
281  { return rfind(basic_string_view(&c, 1), pos); }
282  constexpr size_type rfind(const charT* s, size_type pos, size_type n) const noexcept
283  { return rfind(basic_string_view(s, n), pos); }
284  constexpr size_type rfind(const charT* s, size_type pos = npos) const noexcept
285  { return rfind(basic_string_view(s), pos); }
286 
287  // find_first_of
288  constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept {
289  if (pos >= len_ || s.len_ == 0)
290  return npos;
291  const_iterator iter = std::find_first_of
292  (this->cbegin () + pos, this->cend (), s.cbegin (), s.cend (), traits::eq);
293  return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter );
294  }
295  constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept
296  { return find_first_of(basic_string_view(&c, 1), pos); }
297  constexpr size_type find_first_of(const charT* s, size_type pos, size_type n) const noexcept
298  { return find_first_of(basic_string_view(s, n), pos); }
299  constexpr size_type find_first_of(const charT* s, size_type pos = 0) const noexcept
300  { return find_first_of(basic_string_view(s), pos); }
301 
302  // find_last_of
303  constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept {
304  if (s.len_ == 0u)
305  return npos;
306  if (pos >= len_)
307  pos = 0;
308  else
309  pos = len_ - (pos+1);
310  const_reverse_iterator iter = std::find_first_of
311  ( this->crbegin () + pos, this->crend (), s.cbegin (), s.cend (), traits::eq );
312  return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter);
313  }
314  constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept
315  { return find_last_of(basic_string_view(&c, 1), pos); }
316  constexpr size_type find_last_of(const charT* s, size_type pos, size_type n) const noexcept
317  { return find_last_of(basic_string_view(s, n), pos); }
318  constexpr size_type find_last_of(const charT* s, size_type pos = npos) const noexcept
319  { return find_last_of(basic_string_view(s), pos); }
320 
321  // find_first_not_of
322  constexpr size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept {
323  if (pos >= len_)
324  return npos;
325  if (s.len_ == 0)
326  return pos;
327  const_iterator iter = find_not_of ( this->cbegin () + pos, this->cend (), s );
328  return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter );
329  }
330  constexpr size_type find_first_not_of(charT c, size_type pos = 0) const noexcept
331  { return find_first_not_of(basic_string_view(&c, 1), pos); }
332  constexpr size_type find_first_not_of(const charT* s, size_type pos, size_type n) const noexcept
333  { return find_first_not_of(basic_string_view(s, n), pos); }
334  constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const noexcept
335  { return find_first_not_of(basic_string_view(s), pos); }
336 
337  // find_last_not_of
338  constexpr size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept {
339  if (pos >= len_)
340  pos = len_ - 1;
341  if (s.len_ == 0u)
342  return pos;
343  pos = len_ - (pos+1);
344  const_reverse_iterator iter = find_not_of ( this->crbegin () + pos, this->crend (), s );
345  return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter );
346  }
347  constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept
348  { return find_last_not_of(basic_string_view(&c, 1), pos); }
349  constexpr size_type find_last_not_of(const charT* s, size_type pos, size_type n) const noexcept
350  { return find_last_not_of(basic_string_view(s, n), pos); }
351  constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const noexcept
352  { return find_last_not_of(basic_string_view(s), pos); }
353 
354 private:
355  template <typename r_iter>
356  size_type reverse_distance(r_iter first, r_iter last) const noexcept {
357  // Portability note here: std::distance is not NOEXCEPT, but calling it with a string_view::reverse_iterator will not throw.
358  return len_ - 1 - std::distance ( first, last );
359  }
360 
361  template <typename Iterator>
362  Iterator find_not_of(Iterator first, Iterator last, basic_string_view s) const noexcept {
363  for (; first != last ; ++first)
364  if ( 0 == traits::find(s.ptr_, s.len_, *first))
365  return first;
366  return last;
367  }
368 
369  const charT *ptr_;
370  std::size_t len_;
371 };
372 
374 
375 // Comparison operators
376 // Equality
377 template<typename charT, typename traits>
378 inline bool operator==(basic_string_view<charT, traits> x,
380  if (x.size () != y.size ()) return false;
381  return x.compare(y) == 0;
382 }
383 
384 // Inequality
385 template<typename charT, typename traits>
386 inline bool operator!=(basic_string_view<charT, traits> x,
387  basic_string_view<charT, traits> y) noexcept {
388  if ( x.size () != y.size ()) return true;
389  return x.compare(y) != 0;
390 }
391 
392 // Less than
393 template<typename charT, typename traits>
394 inline bool operator<(basic_string_view<charT, traits> x,
395  basic_string_view<charT, traits> y) noexcept {
396  return x.compare(y) < 0;
397 }
398 
399 // Greater than
400 template<typename charT, typename traits>
401 inline bool operator>(basic_string_view<charT, traits> x,
402  basic_string_view<charT, traits> y) noexcept {
403  return x.compare(y) > 0;
404 }
405 
406 // Less than or equal to
407 template<typename charT, typename traits>
408 inline bool operator<=(basic_string_view<charT, traits> x,
409  basic_string_view<charT, traits> y) noexcept {
410  return x.compare(y) <= 0;
411 }
412 
413 // Greater than or equal to
414 template<typename charT, typename traits>
415 inline bool operator>=(basic_string_view<charT, traits> x,
416  basic_string_view<charT, traits> y) noexcept {
417  return x.compare(y) >= 0;
418 }
419 
420 // "sufficient additional overloads of comparison functions"
421 template<typename charT, typename traits, typename Allocator>
422 inline bool operator==(basic_string_view<charT, traits> x,
423  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
424  return x == basic_string_view<charT, traits>(y);
425 }
426 
427 template<typename charT, typename traits, typename Allocator>
428 inline bool operator==(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
429  basic_string_view<charT, traits> y) noexcept {
430  return basic_string_view<charT, traits>(x) == y;
431 }
432 
433 template<typename charT, typename traits>
434 inline bool operator==(basic_string_view<charT, traits> x,
435  const charT * y) noexcept {
436  return x == basic_string_view<charT, traits>(y);
437 }
438 
439 template<typename charT, typename traits>
440 inline bool operator==(const charT * x,
441  basic_string_view<charT, traits> y) noexcept {
442  return basic_string_view<charT, traits>(x) == y;
443 }
444 
445 template<typename charT, typename traits, typename Allocator>
446 inline bool operator!=(basic_string_view<charT, traits> x,
447  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
448  return x != basic_string_view<charT, traits>(y);
449 }
450 
451 template<typename charT, typename traits, typename Allocator>
452 inline bool operator!=(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
453  basic_string_view<charT, traits> y) noexcept {
454  return basic_string_view<charT, traits>(x) != y;
455 }
456 
457 template<typename charT, typename traits>
458 inline bool operator!=(basic_string_view<charT, traits> x,
459  const charT * y) noexcept {
460  return x != basic_string_view<charT, traits>(y);
461 }
462 
463 template<typename charT, typename traits>
464 inline bool operator!=(const charT * x,
465  basic_string_view<charT, traits> y) noexcept {
466  return basic_string_view<charT, traits>(x) != y;
467 }
468 
469 template<typename charT, typename traits, typename Allocator>
470 inline bool operator<(basic_string_view<charT, traits> x,
471  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
472  return x < basic_string_view<charT, traits>(y);
473 }
474 
475 template<typename charT, typename traits, typename Allocator>
476 inline bool operator<(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
477  basic_string_view<charT, traits> y) noexcept {
478  return basic_string_view<charT, traits>(x) < y;
479 }
480 
481 template<typename charT, typename traits>
482 inline bool operator<(basic_string_view<charT, traits> x,
483  const charT * y) noexcept {
484  return x < basic_string_view<charT, traits>(y);
485 }
486 
487 template<typename charT, typename traits>
488 inline bool operator<(const charT * x,
489  basic_string_view<charT, traits> y) noexcept {
490  return basic_string_view<charT, traits>(x) < y;
491 }
492 
493 template<typename charT, typename traits, typename Allocator>
494 inline bool operator>(basic_string_view<charT, traits> x,
495  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
496  return x > basic_string_view<charT, traits>(y);
497 }
498 
499 template<typename charT, typename traits, typename Allocator>
500 inline bool operator>(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
501  basic_string_view<charT, traits> y) noexcept {
502  return basic_string_view<charT, traits>(x) > y;
503 }
504 
505 template<typename charT, typename traits>
506 inline bool operator>(basic_string_view<charT, traits> x,
507  const charT * y) noexcept {
508  return x > basic_string_view<charT, traits>(y);
509 }
510 
511 template<typename charT, typename traits>
512 inline bool operator>(const charT * x,
513  basic_string_view<charT, traits> y) noexcept {
514  return basic_string_view<charT, traits>(x) > y;
515 }
516 
517 template<typename charT, typename traits, typename Allocator>
518 inline bool operator<=(basic_string_view<charT, traits> x,
519  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
520  return x <= basic_string_view<charT, traits>(y);
521 }
522 
523 template<typename charT, typename traits, typename Allocator>
524 inline bool operator<=(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
525  basic_string_view<charT, traits> y) noexcept {
526  return basic_string_view<charT, traits>(x) <= y;
527 }
528 
529 template<typename charT, typename traits>
530 inline bool operator<=(basic_string_view<charT, traits> x,
531  const charT * y) noexcept {
532  return x <= basic_string_view<charT, traits>(y);
533 }
534 
535 template<typename charT, typename traits>
536 inline bool operator<=(const charT * x,
537  basic_string_view<charT, traits> y) noexcept {
538  return basic_string_view<charT, traits>(x) <= y;
539 }
540 
541 template<typename charT, typename traits, typename Allocator>
542 inline bool operator>=(basic_string_view<charT, traits> x,
543  const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & y) noexcept {
544  return x >= basic_string_view<charT, traits>(y);
545 }
546 
547 template<typename charT, typename traits, typename Allocator>
548 inline bool operator>=(const std::basic_string<charT, typename char_traits<charT>::base_traits, Allocator> & x,
549  basic_string_view<charT, traits> y) noexcept {
550  return basic_string_view<charT, traits>(x) >= y;
551 }
552 
553 template<typename charT, typename traits>
554 inline bool operator>=(basic_string_view<charT, traits> x,
555  const charT * y) noexcept {
556  return x >= basic_string_view<charT, traits>(y);
557 }
558 
559 template<typename charT, typename traits>
560 inline bool operator>=(const charT * x,
561  basic_string_view<charT, traits> y) noexcept {
562  return basic_string_view<charT, traits>(x) >= y;
563 }
564 
565 namespace detail {
566 
567 template<class charT, class traits>
568 inline void sv_insert_fill_chars(std::basic_ostream<charT, traits>& os, std::size_t n) {
569  enum { chunk_size = 8 };
570  charT fill_chars[chunk_size];
571  std::fill_n(fill_chars, static_cast< std::size_t >(chunk_size), os.fill());
572  for (; n >= chunk_size && os.good(); n -= chunk_size)
573  os.write(fill_chars, static_cast< std::size_t >(chunk_size));
574  if (n > 0 && os.good())
575  os.write(fill_chars, n);
576 }
577 
578 template<class charT, class traits>
579 void sv_insert_aligned(std::basic_ostream<charT, typename char_traits<charT>::base_traits>& os, const basic_string_view<charT,traits>& str) {
580  const std::size_t size = str.size();
581  const std::size_t alignment_size = static_cast< std::size_t >(os.width()) - size;
582  const bool align_left = (os.flags() & std::basic_ostream<charT, typename char_traits<charT>::base_traits>::adjustfield)
583  == std::basic_ostream<charT, typename char_traits<charT>::base_traits>::left;
584  if (!align_left) {
585  detail::sv_insert_fill_chars(os, alignment_size);
586  if (os.good())
587  os.write(str.data(), size);
588  }
589  else {
590  os.write(str.data(), size);
591  if (os.good())
592  detail::sv_insert_fill_chars(os, alignment_size);
593  }
594 }
595 
596 } // namespace detail
597 
598 // Inserter
599 template<class charT, class traits>
600 inline std::basic_ostream<charT, typename char_traits<charT>::base_traits>&
601 operator<<(std::basic_ostream<charT, typename char_traits<charT>::base_traits>& os,
602  const basic_string_view<charT,traits>& str) {
603  if (os.good()) {
604  const std::size_t size = str.size();
605  const std::size_t w = static_cast< std::size_t >(os.width());
606  if (w <= size)
607  os.write(str.data(), size);
608  else
609  detail::sv_insert_aligned(os, str);
610  os.width(0);
611  }
612  return os;
613 }
614 
616 
617 
624 
631 
638 
645 
646 
647 
648 // Custom extensions (Lars Froehlich)
649 
651 
652 inline std::string &operator+=(std::string &a, string_view b)
653 {
654  a.append(b.begin(), b.end());
655  return a;
656 }
657 
658 inline std::string operator+(std::string a, string_view b)
659 {
660  a += b;
661  return a;
662 }
663 
664 inline std::string operator+(string_view a, std::string b)
665 {
666  b.insert(b.begin(), a.begin(), a.end());
667  return b;
668 }
669 
671 
672 } // namespace gul14
673 
674 #endif
A view to a contiguous sequence of chars or char-like objects.
Definition: string_view.h:107
Definition of macros used internally by GUL.
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26
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:1649
basic_string_view< char > string_view
A view to a contiguous sequence of chars.
Definition: string_view.h:623