tlx
Loading...
Searching...
No Matches
string_view.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 * tlx/container/string_view.hpp
3 *
4 * A simplified string_view implementation for portability.
5 *
6 * Copyright (C) 2012-2015 Marshall Clow
7 * Copyright (C) 2015 Beman Dawes
8 *
9 * Based on the StringRef implementation in LLVM (http://llvm.org) and
10 * N3422 by Jeffrey Yasskin
11 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
12 * Updated July 2015 to reflect the Library Fundamentals TS
13 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html
14 *
15 * Part of tlx - http://panthema.net/tlx
16 *
17 * Copyright (C) 2016-2020 Timo Bingmann <tb@panthema.net>
18 *
19 * All rights reserved. Published under the Boost Software License, Version 1.0
20 ******************************************************************************/
21
22#ifndef TLX_CONTAINER_STRING_VIEW_HEADER
23#define TLX_CONTAINER_STRING_VIEW_HEADER
24
25#include <algorithm>
26#include <cstring>
27#include <iterator>
28#include <ostream>
29#include <stdexcept>
30#include <string>
31
33
34namespace tlx {
35
36//! \addtogroup tlx_container
37//! \{
38
39/*!
40 * StringView is a reference to a part of a string, consisting of only a char
41 * pointer and a length. It does not have ownership of the substring and is used
42 * mainly for temporary objects.
43 */
45{
46public:
47 // types
48 typedef char value_type;
49 typedef char* pointer;
50 typedef const char* const_pointer;
51 typedef char& reference;
52 typedef const char& const_reference;
55 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
57 typedef std::size_t size_type;
58 typedef std::ptrdiff_t difference_type;
59
60 static constexpr size_type npos = size_type(-1);
61
62 //! default construction
63 StringView() noexcept : ptr_(nullptr), size_(0) { }
64
65 //! copy construction
66 StringView(const StringView& rhs) noexcept = default;
67 //! assignment
68 StringView& operator = (const StringView& rhs) noexcept = default;
69
70 //! assign a whole string
71 StringView(const std::string& str) noexcept
72 : ptr_(str.data()), size_(str.size()) { }
73
74 //! constructing a StringView from a temporary string is a bad idea
75 StringView(std::string&&) = delete;
76
77 //! assign a whole C-style string
78 StringView(const char* str) noexcept
79 : ptr_(str), size_(str ? std::strlen(str) : 0) { }
80
81 //! assign a C-style string with given length
82 StringView(const char* str, size_type size) noexcept
83 : ptr_(str), size_(size) { }
84
85 //! assign a string iterator with given length
86 StringView(const std::string::const_iterator& begin, size_t size) noexcept
87 : ptr_(&(*begin)), size_(size) { }
88
89 //! assign a string between two iterators
90 StringView(const std::string::const_iterator& begin,
91 const std::string::const_iterator& end) noexcept
92 : StringView(begin, end - begin) { }
93
94 //! \name iterators
95 //! \{
96
97 const_iterator begin() const noexcept { return ptr_; }
98 const_iterator cbegin() const noexcept { return ptr_; }
99 const_iterator end() const noexcept { return ptr_ + size_; }
100 const_iterator cend() const noexcept { return ptr_ + size_; }
101
103 return const_reverse_iterator(end());
104 }
106 return const_reverse_iterator(end());
107 }
108 const_reverse_iterator rend() const noexcept {
110 }
111 const_reverse_iterator crend() const noexcept {
113 }
114
115 //! \}
116
117 //! \name capacity
118 //! \{
119
120 size_type size() const noexcept { return size_; }
121 size_type length() const noexcept { return size_; }
122 size_type max_size() const noexcept { return size_; }
123 bool empty() const noexcept { return size_ == 0; }
124
125 //! \}
126
127 //! \name element access
128 //! \{
129
130 const_pointer data() const noexcept { return ptr_; }
131
133 return ptr_[pos];
134 }
135
136 const_reference at(size_t pos) const {
137 if (pos >= size_)
138 throw std::out_of_range("StringView::at");
139 return ptr_[pos];
140 }
141
142 const_reference front() const { return ptr_[0]; }
143 const_reference back() const { return ptr_[size_ - 1]; }
144
145 //! \}
146
147 //! \name modifiers
148 //! \{
149
150 void clear() noexcept { size_ = 0; }
151
153 if (n > size_)
154 n = size_;
155 ptr_ += n;
156 size_ -= n;
157 }
158
160 if (n > size_)
161 n = size_;
162 size_ -= n;
163 }
164
165 void swap(StringView& s) noexcept {
166 std::swap(ptr_, s.ptr_);
167 std::swap(size_, s.size_);
168 }
169
170 //! \}
171
172 // StringView string operations
173 explicit operator std::string() const {
174 return std::string(begin(), end());
175 }
176
177 //! Returns the data of this StringView as a std::string
178 std::string to_string() const { return std::string(ptr_, size_); }
179
180 size_type copy(char* s, size_type n, size_type pos = 0) const {
181 if (pos > size())
182 throw std::out_of_range("StringView::copy");
183 size_type rsize = std::min(n, size_ - pos);
184 std::copy(data(), data() + rsize, s);
185 return rsize;
186 }
187
189 if (pos > size())
190 throw std::out_of_range("StringView::substr");
191 return StringView(data() + pos, (std::min)(size() - pos, n));
192 }
193
194 //! \name comparisons
195 //! \{
196
197 int compare(StringView x) const noexcept {
198 const int cmp = std::strncmp(ptr_, x.ptr_, std::min(size_, x.size_));
199 return cmp != 0 ? cmp
200 : (size_ == x.size_ ? 0 : size_ < x.size_ ? -1 : 1);
201 }
202
203 int compare(size_type pos1, size_type n1, StringView x) const noexcept {
204 return substr(pos1, n1).compare(x);
205 }
206
208 size_type n2) const {
209 return substr(pos1, n1).compare(x.substr(pos2, n2));
210 }
211
212 int compare(const char* x) const {
213 return compare(StringView(x));
214 }
215
216 int compare(size_type pos1, size_type n1, const char* x) const {
217 return substr(pos1, n1).compare(StringView(x));
218 }
219
221 size_type pos1, size_type n1, const char* x, size_type n2) const {
222 return substr(pos1, n1).compare(StringView(x, n2));
223 }
224
225 //! \}
226
227 //! \name comparison operators
228 //! \{
229
230 //! Equality operator to compare a StringView with another StringView
231 bool operator == (const StringView& other) const noexcept {
232 return size_ == other.size_ &&
233 std::equal(ptr_, ptr_ + size_, other.ptr_);
234 }
235
236 //! Inequality operator to compare a StringView with another StringView
237 bool operator != (const StringView& other) const noexcept {
238 return !(operator == (other));
239 }
240
241 //! Less operator to compare a StringView with another StringView
242 //! lexicographically
243 bool operator < (const StringView& other) const noexcept {
244 return std::lexicographical_compare(
245 ptr_, ptr_ + size_, other.ptr_, other.ptr_ + other.size_);
246 }
247
248 //! Greater than
249 bool operator > (const StringView& other) const noexcept {
250 return other.operator < (*this);
251 }
252
253 //! Less than or equal to
254 bool operator <= (const StringView& other) const noexcept {
255 return !other.operator < (*this);
256 }
257
258 //! Less than or equal to
259 bool operator >= (const StringView& other) const noexcept {
260 return !operator < (other);
261 }
262
263 //! \}
264
265 //! \name searches
266 //! \{
267
268 bool starts_with(char c) const noexcept {
269 return !empty() && c == front();
270 }
271
272 bool starts_with(StringView x) const noexcept {
273 return size_ >= x.size_ && std::equal(ptr_, ptr_ + x.size_, x.ptr_);
274 }
275
276 bool ends_with(char c) const noexcept {
277 return !empty() && c == back();
278 }
279
280 bool ends_with(StringView x) const noexcept {
281 return size_ >= x.size_ &&
282 std::equal(ptr_ + size_ - x.size_, ptr_ + size_, x.ptr_);
283 }
284
285 //! \}
286
287 //! \name find
288 //! \{
289
290 size_type find(StringView s, size_type pos = 0) const noexcept {
291 if (pos > size())
292 return npos;
293 if (s.empty())
294 return pos;
295 const_iterator iter =
296 std::search(cbegin() + pos, cend(), s.cbegin(), s.cend());
297 return iter == cend() ? npos : std::distance(cbegin(), iter);
298 }
299 size_type find(char c, size_type pos = 0) const noexcept {
300 return find(StringView(&c, 1), pos);
301 }
302 size_type find(const char* s, size_type pos, size_type n) const noexcept {
303 return find(StringView(s, n), pos);
304 }
305 size_type find(const char* s, size_type pos = 0) const noexcept {
306 return find(StringView(s), pos);
307 }
308
309 //! \}
310
311 //! \name rfind
312 //! \{
313
314 size_type rfind(StringView s, size_type pos = npos) const noexcept {
315 if (size_ < s.size_)
316 return npos;
317 if (pos > size_ - s.size_)
318 pos = size_ - s.size_;
319 if (s.size_ == 0u) // an empty string is always found
320 return pos;
321 for (const char* cur = ptr_ + pos; ; --cur) {
322 if (std::strncmp(cur, s.ptr_, s.size_) == 0)
323 return cur - ptr_;
324 if (cur == ptr_)
325 return npos;
326 }
327 }
328 size_type rfind(char c, size_type pos = npos) const noexcept {
329 return rfind(StringView(&c, 1), pos);
330 }
331 size_type rfind(const char* s, size_type pos, size_type n) const noexcept {
332 return rfind(StringView(s, n), pos);
333 }
334 size_type rfind(const char* s, size_type pos = npos) const noexcept {
335 return rfind(StringView(s), pos);
336 }
337
338 //! \}
339
340 //! \name find_first_of
341 //! \{
342
343 size_type find_first_of(StringView s, size_type pos = 0) const noexcept {
344 if (pos >= size_ || s.size_ == 0)
345 return npos;
346 const_iterator iter =
347 std::find_first_of(cbegin() + pos, cend(), s.cbegin(), s.cend());
348 return iter == cend() ? npos : std::distance(cbegin(), iter);
349 }
350 size_type find_first_of(char c, size_type pos = 0) const noexcept {
351 return find_first_of(StringView(&c, 1), pos);
352 }
354 size_type pos, size_type n) const noexcept {
355 return find_first_of(StringView(s, n), pos);
356 }
357 size_type find_first_of(const char* s, size_type pos = 0) const noexcept {
358 return find_first_of(StringView(s), pos);
359 }
360
361 //! \}
362
363 //! \name find_last_of
364 //! \{
365
366 size_type find_last_of(StringView s, size_type pos = npos) const noexcept {
367 if (s.size_ == 0u)
368 return npos;
369 if (pos >= size_)
370 pos = 0;
371 else
372 pos = size_ - (pos + 1);
374 std::find_first_of(crbegin() + pos, crend(), s.cbegin(), s.cend());
375 return iter == crend() ? npos : reverse_distance(crbegin(), iter);
376 }
377 size_type find_last_of(char c, size_type pos = npos) const noexcept {
378 return find_last_of(StringView(&c, 1), pos);
379 }
380 size_type find_last_of(const char* s,
381 size_type pos, size_type n) const noexcept {
382 return find_last_of(StringView(s, n), pos);
383 }
384 size_type find_last_of(const char* s, size_type pos = npos) const noexcept {
385 return find_last_of(StringView(s), pos);
386 }
387
388 //! \}
389
390 //! \name find_first_not_of
391 //! \{
392
394 size_type pos = 0) const noexcept {
395 if (pos >= size_)
396 return npos;
397 if (s.size_ == 0)
398 return pos;
399 const_iterator iter = find_not_of(cbegin() + pos, cend(), s);
400 return iter == cend() ? npos : std::distance(cbegin(), iter);
401 }
402 size_type find_first_not_of(char c, size_type pos = 0) const noexcept {
403 return find_first_not_of(StringView(&c, 1), pos);
404 }
406 size_type n) const noexcept {
407 return find_first_not_of(StringView(s, n), pos);
408 }
410 size_type pos = 0) const noexcept {
411 return find_first_not_of(StringView(s), pos);
412 }
413
414 //! \}
415
416 //! \name find_last_not_of
417 //! \{
418
420 size_type pos = npos) const noexcept {
421 if (pos >= size_)
422 pos = size_ - 1;
423 if (s.size_ == 0u)
424 return pos;
425 pos = size_ - (pos + 1);
426 const_reverse_iterator iter = find_not_of(crbegin() + pos, crend(), s);
427 return iter == crend() ? npos : reverse_distance(crbegin(), iter);
428 }
429 size_type find_last_not_of(char c, size_type pos = npos) const noexcept {
430 return find_last_not_of(StringView(&c, 1), pos);
431 }
433 size_type pos, size_type n) const noexcept {
434 return find_last_not_of(StringView(s, n), pos);
435 }
437 size_type pos = npos) const noexcept {
438 return find_last_not_of(StringView(s), pos);
439 }
440
441 //! \}
442
443 // ostream
444 friend std::ostream& operator << (std::ostream& os, const StringView& v) {
445 os.write(v.data(), v.size());
446 return os;
447 }
448
449private:
450 template <typename r_iter>
451 size_type reverse_distance(r_iter first, r_iter last) const noexcept {
452 // Portability note here: std::distance is not NOEXCEPT, but calling it
453 // with a StringView::reverse_iterator will not throw.
454 return size_ - 1 - std::distance(first, last);
455 }
456
457 template <typename Iterator>
458 Iterator find_not_of(Iterator first, Iterator last, StringView s) const
459 noexcept {
460 for ( ; first != last; ++first)
461 if (0 == std::char_traits<char>::find(s.ptr_, s.size_, *first))
462 return first;
463 return last;
464 }
465
466 const char* ptr_;
468};
469
470/*----------------------------------------------------------------------------*/
471
472//! make alias due to STL similarity
474
475/*----------------------------------------------------------------------------*/
476// comparison operators: StringView with std::string
477
478//! equality operator to compare a StringView with a std::string
479static inline
480bool operator == (const StringView& a, const std::string& b) noexcept {
481 return a.size() == b.size() &&
482 std::equal(a.begin(), a.end(), b.begin());
483}
484
485//! equality operator to compare a StringView with a std::string
486static inline
487bool operator == (const std::string& a, const StringView& b) noexcept {
488 return a.size() == b.size() &&
489 std::equal(a.begin(), a.end(), b.begin());
490}
491
492//! inequality operator to compare a StringView with a std::string
493static inline
494bool operator != (const StringView& a, const std::string& b) noexcept {
495 return !(a.operator == (b));
496}
497
498//! inequality operator to compare a StringView with a std::string
499static inline
500bool operator != (const std::string& a, const StringView& b) noexcept {
501 return !(b.operator == (a));
502}
503
504//! less operator to compare a StringView with a std::string
505//! lexicographically
506static inline
507bool operator < (const StringView& a, const std::string& b) noexcept {
508 return std::lexicographical_compare(
509 a.begin(), a.end(), b.begin(), b.end());
510}
511
512//! less operator to compare a StringView with a std::string
513//! lexicographically
514static inline
515bool operator < (const std::string& a, const StringView& b) noexcept {
516 return std::lexicographical_compare(
517 a.begin(), a.end(), b.begin(), b.end());
518}
519
520static inline
521bool operator > (const StringView& x, const std::string& y) noexcept {
522 return x > StringView(y);
523}
524
525static inline
526bool operator > (const std::string& x, const StringView& y) noexcept {
527 return StringView(x) > y;
528}
529
530static inline
531bool operator <= (const StringView& x, const std::string& y) noexcept {
532 return x <= StringView(y);
533}
534
535static inline
536bool operator <= (const std::string& x, const StringView& y) noexcept {
537 return StringView(x) <= y;
538}
539
540static inline
541bool operator >= (const StringView& x, const std::string& y) noexcept {
542 return x >= StringView(y);
543}
544
545static inline
546bool operator >= (const std::string& x, const StringView& y) noexcept {
547 return StringView(x) >= y;
548}
549
550/*----------------------------------------------------------------------------*/
551// comparison operators: StringView with const char*
552
553//! equality operator to compare a StringView with a const char*
554static inline
555bool operator == (const StringView& x, const char* y) noexcept {
556 return x == StringView(y);
557}
558
559//! equality operator to compare a StringView with a const char*
560static inline
561bool operator == (const char* x, const StringView& y) noexcept {
562 return StringView(x) == y;
563}
564
565//! inequality operator to compare a StringView with a const char*
566static inline
567bool operator != (const StringView& x, const char* y) noexcept {
568 return x != StringView(y);
569}
570
571//! inequality operator to compare a StringView with a const char*
572static inline
573bool operator != (const char* x, const StringView& y) noexcept {
574 return StringView(x) != y;
575}
576
577static inline
578bool operator < (const StringView& x, const char* y) noexcept {
579 return x < StringView(y);
580}
581
582static inline
583bool operator < (const char* x, const StringView& y) noexcept {
584 return StringView(x) < y;
585}
586
587static inline
588bool operator > (const StringView& x, const char* y) noexcept {
589 return x > StringView(y);
590}
591
592static inline
593bool operator > (const char* x, const StringView& y) noexcept {
594 return StringView(x) > y;
595}
596
597static inline
598bool operator <= (const StringView& x, const char* y) noexcept {
599 return x <= StringView(y);
600}
601
602static inline
603bool operator <= (const char* x, const StringView& y) noexcept {
604 return StringView(x) <= y;
605}
606
607static inline
608bool operator >= (const StringView& x, const char* y) noexcept {
609 return x >= StringView(y);
610}
611
612static inline
613bool operator >= (const char* x, const StringView& y) noexcept {
614 return StringView(x) >= y;
615}
616
617//! \}
618
619} // namespace tlx
620
621namespace std {
622template <>
623struct hash<tlx::StringView> {
624 size_t operator () (const tlx::StringView& sv) const {
625 return tlx::hash_djb2(sv.data(), sv.size());
626 }
627};
628
629} // namespace std
630
631#endif // !TLX_CONTAINER_STRING_VIEW_HEADER
632
633/******************************************************************************/
StringView is a reference to a part of a string, consisting of only a char pointer and a length.
Definition: string_view.hpp:45
size_type find_first_of(const char *s, size_type pos=0) const noexcept
size_type find_first_not_of(const char *s, size_type pos=0) const noexcept
void clear() noexcept
bool operator==(const StringView &other) const noexcept
Equality operator to compare a StringView with another StringView.
size_type size() const noexcept
const_reference front() const
int compare(size_type pos1, size_type n1, StringView x) const noexcept
void swap(StringView &s) noexcept
size_type rfind(const char *s, size_type pos=npos) const noexcept
size_type find(StringView s, size_type pos=0) const noexcept
size_type find_first_not_of(StringView s, size_type pos=0) const noexcept
const_iterator begin() const noexcept
Definition: string_view.hpp:97
void remove_suffix(size_type n)
Iterator find_not_of(Iterator first, Iterator last, StringView s) const noexcept
size_type copy(char *s, size_type n, size_type pos=0) const
size_type rfind(StringView s, size_type pos=npos) const noexcept
static constexpr size_type npos
Definition: string_view.hpp:60
int compare(size_type pos1, size_type n1, const char *x) const
const char * ptr_
size_type find_last_not_of(StringView s, size_type pos=npos) const noexcept
bool operator>=(const StringView &other) const noexcept
Less than or equal to.
bool empty() const noexcept
bool starts_with(char c) const noexcept
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: string_view.hpp:55
size_type find_last_of(const char *s, size_type pos=npos) const noexcept
StringView(const StringView &rhs) noexcept=default
copy construction
size_type find_first_not_of(const char *s, size_type pos, size_type n) const noexcept
size_type find_first_of(const char *s, size_type pos, size_type n) const noexcept
bool operator<=(const StringView &other) const noexcept
Less than or equal to.
const_iterator end() const noexcept
Definition: string_view.hpp:99
bool ends_with(StringView x) const noexcept
const_reference back() const
size_type find_last_not_of(char c, size_type pos=npos) const noexcept
size_type length() const noexcept
size_type find(const char *s, size_type pos, size_type n) const noexcept
size_type rfind(char c, size_type pos=npos) const noexcept
size_type rfind(const char *s, size_type pos, size_type n) const noexcept
int compare(size_type pos1, size_type n1, const char *x, size_type n2) const
size_type find_first_not_of(char c, size_type pos=0) const noexcept
const_reverse_iterator reverse_iterator
Definition: string_view.hpp:56
size_type find_first_of(char c, size_type pos=0) const noexcept
size_type find_last_not_of(const char *s, size_type pos, size_type n) const noexcept
StringView(const std::string::const_iterator &begin, size_t size) noexcept
assign a string iterator with given length
Definition: string_view.hpp:86
int compare(size_type pos1, size_type n1, StringView x, size_type pos2, size_type n2) const
StringView(std::string &&)=delete
constructing a StringView from a temporary string is a bad idea
size_type find(const char *s, size_type pos=0) const noexcept
std::size_t size_type
Definition: string_view.hpp:57
size_type find_last_not_of(const char *s, size_type pos=npos) const noexcept
size_type find_last_of(const char *s, size_type pos, size_type n) const noexcept
const_reference at(size_t pos) const
size_type reverse_distance(r_iter first, r_iter last) const noexcept
const_iterator cend() const noexcept
bool ends_with(char c) const noexcept
const char & const_reference
Definition: string_view.hpp:52
const_pointer const_iterator
Definition: string_view.hpp:53
StringView substr(size_type pos, size_type n=npos) const
std::string to_string() const
Returns the data of this StringView as a std::string.
StringView(const char *str, size_type size) noexcept
assign a C-style string with given length
Definition: string_view.hpp:82
const_pointer data() const noexcept
size_type find_last_of(StringView s, size_type pos=npos) const noexcept
const_reverse_iterator crbegin() const noexcept
StringView(const std::string &str) noexcept
assign a whole string
Definition: string_view.hpp:71
const_iterator cbegin() const noexcept
Definition: string_view.hpp:98
size_type find_first_of(StringView s, size_type pos=0) const noexcept
size_type max_size() const noexcept
StringView & operator=(const StringView &rhs) noexcept=default
assignment
const_reverse_iterator rend() const noexcept
StringView(const std::string::const_iterator &begin, const std::string::const_iterator &end) noexcept
assign a string between two iterators
Definition: string_view.hpp:90
const_iterator iterator
Definition: string_view.hpp:54
const_reverse_iterator crend() const noexcept
bool starts_with(StringView x) const noexcept
StringView(const char *str) noexcept
assign a whole C-style string
Definition: string_view.hpp:78
std::ptrdiff_t difference_type
Definition: string_view.hpp:58
bool operator<(const StringView &other) const noexcept
Less operator to compare a StringView with another StringView lexicographically.
size_type find_last_of(char c, size_type pos=npos) const noexcept
friend std::ostream & operator<<(std::ostream &os, const StringView &v)
const_reference operator[](size_type pos) const noexcept
const char * const_pointer
Definition: string_view.hpp:50
StringView() noexcept
default construction
Definition: string_view.hpp:63
int compare(const char *x) const
bool operator!=(const StringView &other) const noexcept
Inequality operator to compare a StringView with another StringView.
void remove_prefix(size_type n)
int compare(StringView x) const noexcept
bool operator>(const StringView &other) const noexcept
Greater than.
size_type find(char c, size_type pos=0) const noexcept
const_reverse_iterator rbegin() const noexcept
static bool operator>=(const StringView &x, const std::string &y) noexcept
static bool operator<=(const StringView &x, const std::string &y) noexcept
static bool operator==(const StringView &a, const std::string &b) noexcept
equality operator to compare a StringView with a std::string
static bool operator<(const StringView &a, const std::string &b) noexcept
less operator to compare a StringView with a std::string lexicographically
static bool operator!=(const StringView &a, const std::string &b) noexcept
inequality operator to compare a StringView with a std::string
static bool operator>(const StringView &x, const std::string &y) noexcept
static std::uint32_t hash_djb2(const unsigned char *str)
Simple, fast, but "insecure" string hash method by Dan Bernstein from http://www.cse....
Definition: hash_djb2.hpp:27
STL namespace.