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