1 | /* |
2 | Copyright (c) Marshall Clow 2012-2015. |
3 | |
4 | Distributed under the Boost Software License, Version 1.0. (See accompanying |
5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
6 | |
7 | For more information, see http://www.boost.org |
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 | |
13 | */ |
14 | |
15 | #ifndef BOOST_STRING_REF_HPP |
16 | #define BOOST_STRING_REF_HPP |
17 | |
18 | #include <boost/config.hpp> |
19 | #include <boost/detail/workaround.hpp> |
20 | #include <boost/utility/string_ref_fwd.hpp> |
21 | #include <boost/throw_exception.hpp> |
22 | |
23 | #include <cstddef> |
24 | #include <stdexcept> |
25 | #include <algorithm> |
26 | #include <iterator> |
27 | #include <string> |
28 | #include <iosfwd> |
29 | |
30 | namespace boost { |
31 | |
32 | namespace detail { |
33 | // A helper functor because sometimes we don't have lambdas |
34 | template <typename charT, typename traits> |
35 | class string_ref_traits_eq { |
36 | public: |
37 | string_ref_traits_eq ( charT ch ) : ch_(ch) {} |
38 | bool operator () ( charT val ) const { return traits::eq ( ch_, val ); } |
39 | charT ch_; |
40 | }; |
41 | } |
42 | |
43 | template<typename charT, typename traits> |
44 | class basic_string_ref { |
45 | public: |
46 | // types |
47 | typedef charT value_type; |
48 | typedef const charT* pointer; |
49 | typedef const charT& reference; |
50 | typedef const charT& const_reference; |
51 | typedef pointer const_iterator; // impl-defined |
52 | typedef const_iterator iterator; |
53 | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; |
54 | typedef const_reverse_iterator reverse_iterator; |
55 | typedef std::size_t size_type; |
56 | typedef std::ptrdiff_t difference_type; |
57 | static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); |
58 | |
59 | // construct/copy |
60 | BOOST_CONSTEXPR basic_string_ref () |
61 | : ptr_(NULL), len_(0) {} |
62 | |
63 | BOOST_CONSTEXPR basic_string_ref (const basic_string_ref &rhs) |
64 | : ptr_(rhs.ptr_), len_(rhs.len_) {} |
65 | |
66 | basic_string_ref& operator=(const basic_string_ref &rhs) { |
67 | ptr_ = rhs.ptr_; |
68 | len_ = rhs.len_; |
69 | return *this; |
70 | } |
71 | |
72 | basic_string_ref(const charT* str) |
73 | : ptr_(str), len_(traits::length(str)) {} |
74 | |
75 | template<typename Allocator> |
76 | basic_string_ref(const std::basic_string<charT, traits, Allocator>& str) |
77 | : ptr_(str.data()), len_(str.length()) {} |
78 | |
79 | BOOST_CONSTEXPR basic_string_ref(const charT* str, size_type len) |
80 | : ptr_(str), len_(len) {} |
81 | |
82 | #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS |
83 | template<typename Allocator> |
84 | explicit operator std::basic_string<charT, traits, Allocator>() const { |
85 | return std::basic_string<charT, traits, Allocator> ( begin(), end()); |
86 | } |
87 | #endif |
88 | |
89 | std::basic_string<charT, traits> to_string () const { |
90 | return std::basic_string<charT, traits> ( begin(), end()); |
91 | } |
92 | |
93 | // iterators |
94 | BOOST_CONSTEXPR const_iterator begin() const { return ptr_; } |
95 | BOOST_CONSTEXPR const_iterator cbegin() const { return ptr_; } |
96 | BOOST_CONSTEXPR const_iterator end() const { return ptr_ + len_; } |
97 | BOOST_CONSTEXPR const_iterator cend() const { return ptr_ + len_; } |
98 | const_reverse_iterator rbegin() const { return const_reverse_iterator (end()); } |
99 | const_reverse_iterator crbegin() const { return const_reverse_iterator (end()); } |
100 | const_reverse_iterator rend() const { return const_reverse_iterator (begin()); } |
101 | const_reverse_iterator crend() const { return const_reverse_iterator (begin()); } |
102 | |
103 | // capacity |
104 | BOOST_CONSTEXPR size_type size() const { return len_; } |
105 | BOOST_CONSTEXPR size_type length() const { return len_; } |
106 | BOOST_CONSTEXPR size_type max_size() const { return len_; } |
107 | BOOST_CONSTEXPR bool empty() const { return len_ == 0; } |
108 | |
109 | // element access |
110 | BOOST_CONSTEXPR const charT& operator[](size_type pos) const { return ptr_[pos]; } |
111 | |
112 | const charT& at(size_t pos) const { |
113 | if ( pos >= len_ ) |
114 | BOOST_THROW_EXCEPTION( std::out_of_range ( "boost::string_ref::at" ) ); |
115 | return ptr_[pos]; |
116 | } |
117 | |
118 | BOOST_CONSTEXPR const charT& front() const { return ptr_[0]; } |
119 | BOOST_CONSTEXPR const charT& back() const { return ptr_[len_-1]; } |
120 | BOOST_CONSTEXPR const charT* data() const { return ptr_; } |
121 | |
122 | // modifiers |
123 | void clear() { len_ = 0; } |
124 | void remove_prefix(size_type n) { |
125 | if ( n > len_ ) |
126 | n = len_; |
127 | ptr_ += n; |
128 | len_ -= n; |
129 | } |
130 | |
131 | void remove_suffix(size_type n) { |
132 | if ( n > len_ ) |
133 | n = len_; |
134 | len_ -= n; |
135 | } |
136 | |
137 | |
138 | // basic_string_ref string operations |
139 | basic_string_ref substr(size_type pos, size_type n=npos) const { |
140 | if ( pos > size()) |
141 | BOOST_THROW_EXCEPTION( std::out_of_range ( "string_ref::substr" ) ); |
142 | if ( n == npos || pos + n > size()) |
143 | n = size () - pos; |
144 | return basic_string_ref ( data() + pos, n ); |
145 | } |
146 | |
147 | int compare(basic_string_ref x) const { |
148 | const int cmp = traits::compare ( ptr_, x.ptr_, (std::min)(len_, x.len_)); |
149 | return cmp != 0 ? cmp : ( len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1 ); |
150 | } |
151 | |
152 | bool starts_with(charT c) const { return !empty() && traits::eq ( c, front()); } |
153 | bool starts_with(basic_string_ref x) const { |
154 | return len_ >= x.len_ && traits::compare ( ptr_, x.ptr_, x.len_ ) == 0; |
155 | } |
156 | |
157 | bool ends_with(charT c) const { return !empty() && traits::eq ( c, back()); } |
158 | bool ends_with(basic_string_ref x) const { |
159 | return len_ >= x.len_ && traits::compare ( ptr_ + len_ - x.len_, x.ptr_, x.len_ ) == 0; |
160 | } |
161 | |
162 | size_type find(basic_string_ref s) const { |
163 | const_iterator iter = std::search ( this->cbegin (), this->cend (), |
164 | s.cbegin (), s.cend (), traits::eq ); |
165 | return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); |
166 | } |
167 | |
168 | size_type find(charT c) const { |
169 | const_iterator iter = std::find_if ( this->cbegin (), this->cend (), |
170 | detail::string_ref_traits_eq<charT, traits> ( c )); |
171 | return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); |
172 | } |
173 | |
174 | size_type rfind(basic_string_ref s) const { |
175 | const_reverse_iterator iter = std::search ( this->crbegin (), this->crend (), |
176 | s.crbegin (), s.crend (), traits::eq ); |
177 | return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); |
178 | } |
179 | |
180 | size_type rfind(charT c) const { |
181 | const_reverse_iterator iter = std::find_if ( this->crbegin (), this->crend (), |
182 | detail::string_ref_traits_eq<charT, traits> ( c )); |
183 | return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); |
184 | } |
185 | |
186 | size_type find_first_of(charT c) const { return find (c); } |
187 | size_type find_last_of (charT c) const { return rfind (c); } |
188 | |
189 | size_type find_first_of(basic_string_ref s) const { |
190 | const_iterator iter = std::find_first_of |
191 | ( this->cbegin (), this->cend (), s.cbegin (), s.cend (), traits::eq ); |
192 | return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); |
193 | } |
194 | |
195 | size_type find_last_of(basic_string_ref s) const { |
196 | const_reverse_iterator iter = std::find_first_of |
197 | ( this->crbegin (), this->crend (), s.cbegin (), s.cend (), traits::eq ); |
198 | return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter); |
199 | } |
200 | |
201 | size_type find_first_not_of(basic_string_ref s) const { |
202 | const_iterator iter = find_not_of ( this->cbegin (), this->cend (), s ); |
203 | return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); |
204 | } |
205 | |
206 | size_type find_first_not_of(charT c) const { |
207 | for ( const_iterator iter = this->cbegin (); iter != this->cend (); ++iter ) |
208 | if ( !traits::eq ( c, *iter )) |
209 | return std::distance ( this->cbegin (), iter ); |
210 | return npos; |
211 | } |
212 | |
213 | size_type find_last_not_of(basic_string_ref s) const { |
214 | const_reverse_iterator iter = find_not_of ( this->crbegin (), this->crend (), s ); |
215 | return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); |
216 | } |
217 | |
218 | size_type find_last_not_of(charT c) const { |
219 | for ( const_reverse_iterator iter = this->crbegin (); iter != this->crend (); ++iter ) |
220 | if ( !traits::eq ( c, *iter )) |
221 | return reverse_distance ( this->crbegin (), iter ); |
222 | return npos; |
223 | } |
224 | |
225 | private: |
226 | template <typename r_iter> |
227 | size_type reverse_distance ( r_iter first, r_iter last ) const { |
228 | return len_ - 1 - std::distance ( first, last ); |
229 | } |
230 | |
231 | template <typename Iterator> |
232 | Iterator find_not_of ( Iterator first, Iterator last, basic_string_ref s ) const { |
233 | for ( ; first != last ; ++first ) |
234 | if ( 0 == traits::find ( s.ptr_, s.len_, *first )) |
235 | return first; |
236 | return last; |
237 | } |
238 | |
239 | |
240 | |
241 | const charT *ptr_; |
242 | std::size_t len_; |
243 | }; |
244 | |
245 | |
246 | // Comparison operators |
247 | // Equality |
248 | template<typename charT, typename traits> |
249 | inline bool operator==(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { |
250 | if ( x.size () != y.size ()) return false; |
251 | return x.compare(y) == 0; |
252 | } |
253 | |
254 | template<typename charT, typename traits, typename Allocator> |
255 | inline bool operator==(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { |
256 | return x == basic_string_ref<charT, traits>(y); |
257 | } |
258 | |
259 | template<typename charT, typename traits, typename Allocator> |
260 | inline bool operator==(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { |
261 | return basic_string_ref<charT, traits>(x) == y; |
262 | } |
263 | |
264 | template<typename charT, typename traits> |
265 | inline bool operator==(basic_string_ref<charT, traits> x, const charT * y) { |
266 | return x == basic_string_ref<charT, traits>(y); |
267 | } |
268 | |
269 | template<typename charT, typename traits> |
270 | inline bool operator==(const charT * x, basic_string_ref<charT, traits> y) { |
271 | return basic_string_ref<charT, traits>(x) == y; |
272 | } |
273 | |
274 | // Inequality |
275 | template<typename charT, typename traits> |
276 | inline bool operator!=(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { |
277 | if ( x.size () != y.size ()) return true; |
278 | return x.compare(y) != 0; |
279 | } |
280 | |
281 | template<typename charT, typename traits, typename Allocator> |
282 | inline bool operator!=(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { |
283 | return x != basic_string_ref<charT, traits>(y); |
284 | } |
285 | |
286 | template<typename charT, typename traits, typename Allocator> |
287 | inline bool operator!=(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { |
288 | return basic_string_ref<charT, traits>(x) != y; |
289 | } |
290 | |
291 | template<typename charT, typename traits> |
292 | inline bool operator!=(basic_string_ref<charT, traits> x, const charT * y) { |
293 | return x != basic_string_ref<charT, traits>(y); |
294 | } |
295 | |
296 | template<typename charT, typename traits> |
297 | inline bool operator!=(const charT * x, basic_string_ref<charT, traits> y) { |
298 | return basic_string_ref<charT, traits>(x) != y; |
299 | } |
300 | |
301 | // Less than |
302 | template<typename charT, typename traits> |
303 | inline bool operator<(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { |
304 | return x.compare(y) < 0; |
305 | } |
306 | |
307 | template<typename charT, typename traits, typename Allocator> |
308 | inline bool operator<(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { |
309 | return x < basic_string_ref<charT, traits>(y); |
310 | } |
311 | |
312 | template<typename charT, typename traits, typename Allocator> |
313 | inline bool operator<(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { |
314 | return basic_string_ref<charT, traits>(x) < y; |
315 | } |
316 | |
317 | template<typename charT, typename traits> |
318 | inline bool operator<(basic_string_ref<charT, traits> x, const charT * y) { |
319 | return x < basic_string_ref<charT, traits>(y); |
320 | } |
321 | |
322 | template<typename charT, typename traits> |
323 | inline bool operator<(const charT * x, basic_string_ref<charT, traits> y) { |
324 | return basic_string_ref<charT, traits>(x) < y; |
325 | } |
326 | |
327 | // Greater than |
328 | template<typename charT, typename traits> |
329 | inline bool operator>(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { |
330 | return x.compare(y) > 0; |
331 | } |
332 | |
333 | template<typename charT, typename traits, typename Allocator> |
334 | inline bool operator>(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { |
335 | return x > basic_string_ref<charT, traits>(y); |
336 | } |
337 | |
338 | template<typename charT, typename traits, typename Allocator> |
339 | inline bool operator>(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { |
340 | return basic_string_ref<charT, traits>(x) > y; |
341 | } |
342 | |
343 | template<typename charT, typename traits> |
344 | inline bool operator>(basic_string_ref<charT, traits> x, const charT * y) { |
345 | return x > basic_string_ref<charT, traits>(y); |
346 | } |
347 | |
348 | template<typename charT, typename traits> |
349 | inline bool operator>(const charT * x, basic_string_ref<charT, traits> y) { |
350 | return basic_string_ref<charT, traits>(x) > y; |
351 | } |
352 | |
353 | // Less than or equal to |
354 | template<typename charT, typename traits> |
355 | inline bool operator<=(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { |
356 | return x.compare(y) <= 0; |
357 | } |
358 | |
359 | template<typename charT, typename traits, typename Allocator> |
360 | inline bool operator<=(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { |
361 | return x <= basic_string_ref<charT, traits>(y); |
362 | } |
363 | |
364 | template<typename charT, typename traits, typename Allocator> |
365 | inline bool operator<=(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { |
366 | return basic_string_ref<charT, traits>(x) <= y; |
367 | } |
368 | |
369 | template<typename charT, typename traits> |
370 | inline bool operator<=(basic_string_ref<charT, traits> x, const charT * y) { |
371 | return x <= basic_string_ref<charT, traits>(y); |
372 | } |
373 | |
374 | template<typename charT, typename traits> |
375 | inline bool operator<=(const charT * x, basic_string_ref<charT, traits> y) { |
376 | return basic_string_ref<charT, traits>(x) <= y; |
377 | } |
378 | |
379 | // Greater than or equal to |
380 | template<typename charT, typename traits> |
381 | inline bool operator>=(basic_string_ref<charT, traits> x, basic_string_ref<charT, traits> y) { |
382 | return x.compare(y) >= 0; |
383 | } |
384 | |
385 | template<typename charT, typename traits, typename Allocator> |
386 | inline bool operator>=(basic_string_ref<charT, traits> x, const std::basic_string<charT, traits, Allocator> & y) { |
387 | return x >= basic_string_ref<charT, traits>(y); |
388 | } |
389 | |
390 | template<typename charT, typename traits, typename Allocator> |
391 | inline bool operator>=(const std::basic_string<charT, traits, Allocator> & x, basic_string_ref<charT, traits> y) { |
392 | return basic_string_ref<charT, traits>(x) >= y; |
393 | } |
394 | |
395 | template<typename charT, typename traits> |
396 | inline bool operator>=(basic_string_ref<charT, traits> x, const charT * y) { |
397 | return x >= basic_string_ref<charT, traits>(y); |
398 | } |
399 | |
400 | template<typename charT, typename traits> |
401 | inline bool operator>=(const charT * x, basic_string_ref<charT, traits> y) { |
402 | return basic_string_ref<charT, traits>(x) >= y; |
403 | } |
404 | |
405 | namespace detail { |
406 | |
407 | template<class charT, class traits> |
408 | inline void insert_fill_chars(std::basic_ostream<charT, traits>& os, std::size_t n) { |
409 | enum { chunk_size = 8 }; |
410 | charT fill_chars[chunk_size]; |
411 | std::fill_n(fill_chars, static_cast< std::size_t >(chunk_size), os.fill()); |
412 | for (; n >= chunk_size && os.good(); n -= chunk_size) |
413 | os.write(fill_chars, static_cast< std::size_t >(chunk_size)); |
414 | if (n > 0 && os.good()) |
415 | os.write(fill_chars, n); |
416 | } |
417 | |
418 | template<class charT, class traits> |
419 | void insert_aligned(std::basic_ostream<charT, traits>& os, const basic_string_ref<charT,traits>& str) { |
420 | const std::size_t size = str.size(); |
421 | const std::size_t alignment_size = static_cast< std::size_t >(os.width()) - size; |
422 | const bool align_left = (os.flags() & std::basic_ostream<charT, traits>::adjustfield) == std::basic_ostream<charT, traits>::left; |
423 | if (!align_left) { |
424 | detail::insert_fill_chars(os, alignment_size); |
425 | if (os.good()) |
426 | os.write(str.data(), size); |
427 | } |
428 | else { |
429 | os.write(str.data(), size); |
430 | if (os.good()) |
431 | detail::insert_fill_chars(os, alignment_size); |
432 | } |
433 | } |
434 | |
435 | } // namespace detail |
436 | |
437 | // Inserter |
438 | template<class charT, class traits> |
439 | inline std::basic_ostream<charT, traits>& |
440 | operator<<(std::basic_ostream<charT, traits>& os, const basic_string_ref<charT,traits>& str) { |
441 | if (os.good()) { |
442 | const std::size_t size = str.size(); |
443 | const std::size_t w = static_cast< std::size_t >(os.width()); |
444 | if (w <= size) |
445 | os.write(str.data(), size); |
446 | else |
447 | detail::insert_aligned(os, str); |
448 | os.width(0); |
449 | } |
450 | return os; |
451 | } |
452 | |
453 | #if 0 |
454 | // numeric conversions |
455 | // |
456 | // These are short-term implementations. |
457 | // In a production environment, I would rather avoid the copying. |
458 | // |
459 | inline int stoi (string_ref str, size_t* idx=0, int base=10) { |
460 | return std::stoi ( std::string(str), idx, base ); |
461 | } |
462 | |
463 | inline long stol (string_ref str, size_t* idx=0, int base=10) { |
464 | return std::stol ( std::string(str), idx, base ); |
465 | } |
466 | |
467 | inline unsigned long stoul (string_ref str, size_t* idx=0, int base=10) { |
468 | return std::stoul ( std::string(str), idx, base ); |
469 | } |
470 | |
471 | inline long long stoll (string_ref str, size_t* idx=0, int base=10) { |
472 | return std::stoll ( std::string(str), idx, base ); |
473 | } |
474 | |
475 | inline unsigned long long stoull (string_ref str, size_t* idx=0, int base=10) { |
476 | return std::stoull ( std::string(str), idx, base ); |
477 | } |
478 | |
479 | inline float stof (string_ref str, size_t* idx=0) { |
480 | return std::stof ( std::string(str), idx ); |
481 | } |
482 | |
483 | inline double stod (string_ref str, size_t* idx=0) { |
484 | return std::stod ( std::string(str), idx ); |
485 | } |
486 | |
487 | inline long double stold (string_ref str, size_t* idx=0) { |
488 | return std::stold ( std::string(str), idx ); |
489 | } |
490 | |
491 | inline int stoi (wstring_ref str, size_t* idx=0, int base=10) { |
492 | return std::stoi ( std::wstring(str), idx, base ); |
493 | } |
494 | |
495 | inline long stol (wstring_ref str, size_t* idx=0, int base=10) { |
496 | return std::stol ( std::wstring(str), idx, base ); |
497 | } |
498 | |
499 | inline unsigned long stoul (wstring_ref str, size_t* idx=0, int base=10) { |
500 | return std::stoul ( std::wstring(str), idx, base ); |
501 | } |
502 | |
503 | inline long long stoll (wstring_ref str, size_t* idx=0, int base=10) { |
504 | return std::stoll ( std::wstring(str), idx, base ); |
505 | } |
506 | |
507 | inline unsigned long long stoull (wstring_ref str, size_t* idx=0, int base=10) { |
508 | return std::stoull ( std::wstring(str), idx, base ); |
509 | } |
510 | |
511 | inline float stof (wstring_ref str, size_t* idx=0) { |
512 | return std::stof ( std::wstring(str), idx ); |
513 | } |
514 | |
515 | inline double stod (wstring_ref str, size_t* idx=0) { |
516 | return std::stod ( std::wstring(str), idx ); |
517 | } |
518 | |
519 | inline long double stold (wstring_ref str, size_t* idx=0) { |
520 | return std::stold ( std::wstring(str), idx ); |
521 | } |
522 | #endif |
523 | |
524 | } |
525 | |
526 | #if 0 |
527 | namespace std { |
528 | // Hashing |
529 | template<> struct hash<boost::string_ref>; |
530 | template<> struct hash<boost::u16string_ref>; |
531 | template<> struct hash<boost::u32string_ref>; |
532 | template<> struct hash<boost::wstring_ref>; |
533 | } |
534 | #endif |
535 | |
536 | #endif |
537 | |