header_utils
Loading...
Searching...
No Matches
string_view.h
1#pragma once
2
3#ifndef DOXYGEN
6
7#pragma once
8
9#include <algorithm>
10#include <cassert>
11#include <iterator>
12#include <limits>
13#include <sstream>
14#include <stdexcept>
15#include <string>
16#include <type_traits>
17
18struct string_view
19{
20public:
21
22 typedef std::char_traits<char> traits_type;
23 typedef char value_type;
24
25 typedef char* pointer;
26 typedef char const* const_pointer;
27 typedef char& reference;
28 typedef char const& const_reference;
29
30 typedef const_pointer iterator;
31 typedef const_pointer const_iterator;
32 typedef std::reverse_iterator< const_iterator > reverse_iterator;
33 typedef std::reverse_iterator< const_iterator > const_reverse_iterator;
34
35 typedef std::size_t size_type;
36 typedef std::ptrdiff_t difference_type;
37
38 string_view() noexcept
39 : data_(nullptr)
40 , size_(0)
41 {}
42
43 string_view(string_view const& other) noexcept = default;
44
45 string_view(char const* s, size_type count) noexcept
46 : data_(s)
47 , size_(count)
48 {}
49
50 string_view(char const* s) noexcept
51 : data_(s)
52 , size_(traits_type::length(s))
53 {}
54
55 string_view(char const* s, char const* e) noexcept
56 : data_(s)
57 , size_(e - s)
58 {}
59
60 string_view(std::nullptr_t) noexcept = delete;
61
62 string_view& operator=(string_view const& other) noexcept = default;
63
64 const_iterator begin() const noexcept { return data_; }
65 const_iterator end() const noexcept { return data_ + size_; }
66
67 const_iterator cbegin() const noexcept { return begin(); }
68 const_iterator cend() const noexcept { return end(); }
69
70 const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
71 const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
72
73 const_reverse_iterator crbegin() const noexcept { return rbegin(); }
74 const_reverse_iterator crend() const noexcept { return rend(); }
75
76 size_type size() const noexcept { return size_; }
77 size_type length() const noexcept { return size_; }
78 size_type max_size() const noexcept { return (std::numeric_limits< size_type >::max)(); }
79
80 bool empty() const noexcept
81 {
82 return 0 == size_;
83 }
84
85 const_reference operator[](size_type pos) const
86 {
87 return data_at(pos);
88 }
89
90 const_reference at(size_type pos) const
91 {
92 if (pos >= size())
93 throw std::out_of_range("nonstring_view::at()");
94 return data_at(pos);
95 }
96
97 const_reference front() const { return data_at(0); }
98 const_reference back() const { return data_at(size() - 1); }
99
100 const_pointer data() const noexcept { return data_; }
101 const_pointer data_end() const noexcept { return data_ + size_; }
102
103 void remove_prefix(size_type n)
104 {
105 assert(n <= size());
106 data_ += n;
107 size_ -= n;
108 }
109
110 void remove_suffix(size_type n)
111 {
112 assert(n <= size());
113 size_ -= n;
114 }
115
116 void swap(string_view& other) noexcept
117 {
118 const string_view tmp(other);
119 other = *this;
120 *this = tmp;
121 }
122
123 size_type copy(char* dest, size_type n, size_type pos = 0) const
124 {
125 if (pos > size())
126 throw std::out_of_range("nonstring_view::copy()");
127
128 const size_type rlen = (std::min)(n, size() - pos);
129 (void)traits_type::copy(dest, data() + pos, rlen);
130 return rlen;
131 }
132
133 string_view substr(size_type pos = 0, size_type n = npos) const
134 {
135 if (pos > size())
136 throw std::out_of_range("nonstring_view::substr()");
137 return string_view{ data() + pos, (std::min)(n, size() - pos) };
138 }
139
140 // compare(), 6x:
141
142 int compare(string_view other) const noexcept // (1)
143 {
144 if (const int result = traits_type::compare(data(), other.data(), (std::min)(size(), other.size())))
145 return result;
146
147 return size() == other.size() ? 0 : size() < other.size() ? -1 : 1;
148 }
149
150 int compare(size_type pos1, size_type n1, string_view other) const // (2)
151 {
152 return substr(pos1, n1).compare(other);
153 }
154
155 int compare(size_type pos1, size_type n1, string_view other, size_type pos2, size_type n2) const // (3)
156 {
157 return substr(pos1, n1).compare(other.substr(pos2, n2));
158 }
159
160 int compare(char const* s) const
161 {
162 return compare(string_view{ s });
163 }
164
165 int compare(size_type pos1, size_type n1, char const* s) const
166 {
167 return substr(pos1, n1).compare(string_view{ s });
168 }
169
170 int compare(size_type pos1, size_type n1, char const* s, size_type n2) const
171 {
172 return substr(pos1, n1).compare(string_view{ s, n2 });
173 }
174
175 bool starts_with(string_view v) const noexcept
176 {
177 return size() >= v.size() && compare(0, v.size(), v) == 0;
178 }
179
180 bool starts_with(char c) const noexcept
181 {
182 return starts_with(string_view{ &c, 1 });
183 }
184
185 bool starts_with(char const* s) const
186 {
187 return starts_with(string_view{ s });
188 }
189
190 bool ends_with(string_view v) const noexcept
191 {
192 return size() >= v.size() && compare(size() - v.size(), npos, v) == 0;
193 }
194
195 bool ends_with(char c) const noexcept
196 {
197 return ends_with(string_view{ &c, 1 });
198 }
199
200 bool ends_with(char const* s) const
201 {
202 return ends_with(string_view{ s });
203 }
204
205 size_type find(string_view v, size_type pos = 0) const noexcept
206 {
207 return assert(v.size() == 0 || v.data() != nullptr)
208 , pos >= size()
209 ? npos : to_pos(
210 std::search(cbegin() + pos, cend(), v.cbegin(), v.cend(), traits_type::eq)
211 );
212 }
213
214 size_type find(char c, size_type pos = 0) const noexcept
215 {
216 return find(string_view{ &c, 1 }, pos);
217 }
218
219 size_type find(char const* s, size_type pos, size_type n) const
220 {
221 return find(string_view{ s, n }, pos);
222 }
223
224 size_type find(char const* s, size_type pos = 0) const
225 {
226 return find(string_view{ s }, pos);
227 }
228
229 size_type rfind(string_view v, size_type pos = npos) const noexcept
230 {
231 if (size() < v.size())
232 {
233 return npos;
234 }
235
236 if (v.empty())
237 {
238 return (std::min)(size(), pos);
239 }
240
241 const_iterator last = cbegin() + (std::min)(size() - v.size(), pos) + v.size();
242 const_iterator result = std::find_end(cbegin(), last, v.cbegin(), v.cend(), traits_type::eq);
243
244 return result != last ? size_type(result - cbegin()) : npos;
245 }
246
247 size_type rfind(char c, size_type pos = npos) const noexcept
248 {
249 return rfind(string_view{ &c, 1 }, pos);
250 }
251
252 size_type rfind(char const* s, size_type pos, size_type n) const
253 {
254 return rfind(string_view{ s, n }, pos);
255 }
256
257 size_type rfind(char const* s, size_type pos = npos) const
258 {
259 return rfind(string_view{ s }, pos);
260 }
261
262 size_type find_first_of(string_view v, size_type pos = 0) const noexcept
263 {
264 return pos >= size()
265 ? npos
266 : to_pos(std::find_first_of(cbegin() + pos, cend(), v.cbegin(), v.cend(), traits_type::eq));
267 }
268
269 size_type find_first_of(char c, size_type pos = 0) const noexcept
270 {
271 return find_first_of(string_view{ &c, 1 }, pos);
272 }
273
274 size_type find_first_of(char const* s, size_type pos, size_type n) const
275 {
276 return find_first_of(string_view{ s, n }, pos);
277 }
278
279 size_type find_first_of(char const* s, size_type pos = 0) const
280 {
281 return find_first_of(string_view{ s }, pos);
282 }
283
284 size_type find_last_of(string_view v, size_type pos = npos) const noexcept
285 {
286 return empty()
287 ? npos
288 : pos >= size()
289 ? find_last_of(v, size() - 1)
290 : to_pos(std::find_first_of(const_reverse_iterator(cbegin() + pos + 1), crend(), v.cbegin(), v.cend(), traits_type::eq));
291 }
292
293 size_type find_last_of(char c, size_type pos = npos) const noexcept
294 {
295 return find_last_of(string_view{ &c, 1 }, pos);
296 }
297
298 size_type find_last_of(char const* s, size_type pos, size_type count) const
299 {
300 return find_last_of(string_view{ s, count }, pos);
301 }
302
303 size_type find_last_of(char const* s, size_type pos = npos) const
304 {
305 return find_last_of(string_view{ s }, pos);
306 }
307
308 size_type find_first_not_of(string_view v, size_type pos = 0) const noexcept
309 {
310 return pos >= size()
311 ? npos
312 : to_pos(std::find_if(cbegin() + pos, cend(), not_in_view(v)));
313 }
314
315 size_type find_first_not_of(char c, size_type pos = 0) const noexcept
316 {
317 return find_first_not_of(string_view{ &c, 1 }, pos);
318 }
319
320 size_type find_first_not_of(char const* s, size_type pos, size_type count) const
321 {
322 return find_first_not_of(string_view{ s, count }, pos);
323 }
324
325 size_type find_first_not_of(char const* s, size_type pos = 0) const
326 {
327 return find_first_not_of(string_view{ s }, pos);
328 }
329
330 size_type find_last_not_of(string_view v, size_type pos = npos) const noexcept
331 {
332 return empty()
333 ? npos
334 : pos >= size()
335 ? find_last_not_of(v, size() - 1)
336 : to_pos(std::find_if(const_reverse_iterator(cbegin() + pos + 1), crend(), not_in_view(v)));
337 }
338
339 size_type find_last_not_of(char c, size_type pos = npos) const noexcept
340 {
341 return find_last_not_of(string_view{ &c, 1 }, pos);
342 }
343
344 size_type find_last_not_of(char const* s, size_type pos, size_type count) const
345 {
346 return find_last_not_of(string_view{ s, count }, pos);
347 }
348
349 size_type find_last_not_of(char const* s, size_type pos = npos) const
350 {
351 return find_last_not_of(string_view{ s }, pos);
352 }
353
354 bool contains(const string_view right) const noexcept { return find(right) != npos; }
355 bool contains(const char right) const noexcept { return find(right) != npos; }
356 bool contains(const char* const right) const { return find(right) != npos; }
357
358 enum : size_type { npos = size_type(-1) };
359
360private:
361 struct not_in_view
362 {
363 const string_view& v;
364
365 explicit not_in_view(string_view& v_) : v(v_) {}
366
367 bool operator()(char c) const
368 {
369 return npos == v.find_first_of(c);
370 }
371 };
372
373 size_type to_pos(const_iterator it) const
374 {
375 return it == cend() ? npos : size_type(it - cbegin());
376 }
377
378 size_type to_pos(const_reverse_iterator it) const
379 {
380 return it == crend() ? npos : size_type(crend() - it - 1);
381 }
382
383 const_reference data_at(size_type pos) const
384 {
385 return assert(pos < size()), data_[pos];
386 }
387
388private:
389 const_pointer data_;
390 size_type size_;
391
392public:
393
394 string_view(std::string const& s) noexcept
395 : data_(s.data())
396 , size_(s.size())
397 {}
398
399 explicit operator std::string() const
400 {
401 return to_string();
402 }
403
404 std::string to_string() const
405 {
406 return std::string(begin(), end());
407 }
408
410 bool is_inside(string_view bigger_string) const
411 {
412 return bigger_string.data() - this->data() >= 0 && this->data_end() - bigger_string.data_end() >= 0;
413 }
414};
415
416inline bool operator== (string_view lhs, string_view rhs) noexcept { return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; }
417inline bool operator!= (string_view lhs, string_view rhs) noexcept { return !(lhs == rhs); }
418inline bool operator< (string_view lhs, string_view rhs) noexcept { return lhs.compare(rhs) < 0; }
419inline bool operator<= (string_view lhs, string_view rhs) noexcept { return lhs.compare(rhs) <= 0; }
420inline bool operator> (string_view lhs, string_view rhs) noexcept { return lhs.compare(rhs) > 0; }
421inline bool operator>= (string_view lhs, string_view rhs) noexcept { return lhs.compare(rhs) >= 0; }
422
423inline std::string to_string(string_view v) { return { v.begin(), v.end() }; }
424
425namespace ascii
426{
427 constexpr bool isalpha(char32_t cp) noexcept { return (cp >= 65 && cp <= 90) || (cp >= 97 && cp <= 122); }
428 constexpr bool isdigit(char32_t cp) noexcept { return cp >= 48 && cp <= 57; }
429 constexpr bool isodigit(char32_t cp) noexcept { return cp >= 48 && cp <= 55; }
430 constexpr bool isxdigit(char32_t d) noexcept { return (d >= 48 && d <= 57) || (d >= 65 && d <= 70) || (d >= 97 && d <= 102); }
431 constexpr bool isalnum(char32_t cp) noexcept { return ascii::isdigit(cp) || ascii::isalpha(cp); }
432 constexpr bool isident(char32_t cp) noexcept { return ascii::isdigit(cp) || ascii::isalpha(cp) || cp == 95; }
433 constexpr bool isidentstart(char32_t cp) noexcept { return ascii::isalpha(cp) || cp == 95; }
434 constexpr bool isspace(char32_t cp) noexcept { return (cp >= 9 && cp <= 13) || cp == 32; }
435 constexpr bool ispunct(char32_t cp) noexcept { return (cp >= 33 && cp <= 47) || (cp >= 58 && cp <= 64) || (cp >= 91 && cp <= 96) || (cp >= 123 && cp <= 126); }
436 constexpr bool islower(char32_t cp) noexcept { return cp >= 97 && cp <= 122; }
437 constexpr bool isupper(char32_t cp) noexcept { return cp >= 65 && cp <= 90; }
438 constexpr bool iscntrl(char32_t cp) noexcept { return cp == 0x7F || cp < 0x20; }
439 constexpr bool isblank(char32_t cp) noexcept { return cp == 32 || cp == 9; }
440 constexpr bool isgraph(char32_t cp) noexcept { return cp >= 33 && cp <= 126; }
441 constexpr bool isprint(char32_t cp) noexcept { return cp >= 32 && cp <= 126; }
442
443 constexpr char32_t toupper(char32_t cp) noexcept { return (cp >= 97 && cp <= 122) ? (cp ^ 0b100000) : cp; }
444 constexpr char32_t tolower(char32_t cp) noexcept { return (cp >= 65 && cp <= 90) ? (cp | 0b100000) : cp; }
445
447 constexpr char32_t number_to_digit(int v) noexcept { return char32_t(v) + 48; }
449 constexpr char32_t number_to_xdigit(int v) noexcept { return (v > 9) ? (char32_t(v - 10) + 65) : (char32_t(v) + 48); }
450
452 constexpr int digit_to_number(char32_t cp) noexcept { return int(cp - 48); }
454 //constexpr int xdigit_to_number(char32_t cp) noexcept { return (cp >= 97 && cp <= 102) ? int(cp - 97) : int((cp >= 65 && cp <= 70) ? (cp - 55) : (cp - 48)); }
455 constexpr int xdigit_to_number(char32_t cp) noexcept { return isdigit(cp) ? int(cp - 48) : ((int(cp) & ~0b100000) - 55); }
456}
457
461
462inline string_view trimmed_whitespace_right(string_view str) noexcept { return string_view(str.begin(), std::find_if_not(str.rbegin(), str.rend(), ascii::isspace).base()); }
463inline string_view trimmed_whitespace_left(string_view str) noexcept { return string_view(std::find_if_not(str.begin(), str.end(), ascii::isspace), str.end()); }
464inline string_view trimmed_whitespace(string_view str) noexcept { return trimmed_whitespace_left(trimmed_whitespace_right(str)); }
465inline string_view trimmed_until(string_view str, char chr) noexcept { return string_view(std::find(str.begin(), str.end(), chr), str.end()); }
466inline string_view trimmed(string_view str, char chr) noexcept { return string_view(std::find_if_not(str.begin(), str.end(), [chr](char c) { return c == chr; }), str.end()); }
467
468inline std::string trimmed_whitespace_right(std::string str) noexcept { str.erase(std::find_if_not(str.rbegin(), str.rend(), ascii::isspace).base(), str.end()); return str; }
469inline std::string trimmed_whitespace_left(std::string str) noexcept { str.erase(str.begin(), std::find_if_not(str.begin(), str.end(), ascii::isspace)); return str; }
470inline std::string trimmed_whitespace(std::string str) noexcept { return trimmed_whitespace_left(trimmed_whitespace_right(std::move(str))); }
471inline std::string trimmed_until(std::string str, char chr) noexcept { str.erase(str.begin(), std::find(str.begin(), str.end(), chr)); return str; }
472inline std::string trimmed(std::string str, char chr) noexcept { str.erase(str.begin(), std::find_if_not(str.begin(), str.end(), [chr](char c) { return c == chr; })); return str; }
473template <typename FUNC>
474inline string_view trimmed_while(string_view str, FUNC&& func) noexcept { return ::ghassanpl::string_ops::string_view(std::find_if_not(str.begin(), str.end(), std::forward<FUNC>(func)), str.end()); }
475
476inline void trim_whitespace_right(string_view& str) noexcept { str = string_view(str.begin(), std::find_if_not(str.rbegin(), str.rend(), ascii::isspace).base()); }
477inline void trim_whitespace_left(string_view& str) noexcept { str = string_view(std::find_if_not(str.begin(), str.end(), ascii::isspace), str.end()); }
478inline void trim_whitespace(string_view& str) noexcept { trim_whitespace_left(str); trim_whitespace_right(str); }
479inline void trim_until(string_view& str, char chr) noexcept { str = trimmed_until(str, chr); }
480inline void trim(string_view& str, char chr) noexcept { str = trimmed(str, chr); }
481template <typename FUNC>
482inline void trim_while(string_view& str, FUNC&& func) noexcept { str = trimmed_while(str, std::forward<FUNC>(func)); }
483
485
491
493inline char consume(string_view& str)
494{
495 if (str.empty())
496 return {};
497 const auto result = str[0];
498 str.remove_prefix(1);
499 return result;
500}
501
504inline bool consume(string_view& str, char val)
505{
506 if (str.starts_with(val))
507 {
508 str.remove_prefix(1);
509 return true;
510 }
511 return false;
512}
513
516inline bool consume(string_view& str, string_view val)
517{
518 if (str.starts_with(val))
519 {
520 str.remove_prefix(val.size());
521 return true;
522 }
523 return false;
524}
525
528inline char consume_any(string_view& str, string_view chars)
529{
530 if (!str.empty() && chars.contains(str[0]))
531 {
532 const auto result = str[0];
533 str.remove_prefix(1);
534 return result;
535 }
536 return 0;
537}
538
541inline string_view consume_while_any(string_view& str, string_view chars)
542{
543 const auto start = str.begin();
544 while (!str.empty() && chars.contains(str[0]))
545 str.remove_prefix(1);
546 return string_view{ start, str.begin() };
547}
548
551template <typename PRED>
552inline char consume(string_view& str, PRED&& pred)
553{
554 if (!str.empty() && pred(str[0]))
555 {
556 const auto result = str[0];
557 str.remove_prefix(1);
558 return result;
559 }
560 return {};
561}
562
564inline char consume_or(string_view& str, char or_else)
565{
566 if (str.empty())
567 return or_else;
568 const auto result = str[0];
569 str.remove_prefix(1);
570 return result;
571}
572
576inline bool consume_at_end(string_view& str, char val)
577{
578 if (str.ends_with(val))
579 {
580 str.remove_suffix(1);
581 return true;
582 }
583 return false;
584}
585
586
590inline bool consume_at_end(string_view& str, string_view val)
591{
592 if (str.ends_with(val))
593 {
594 str.remove_suffix(val.size());
595 return true;
596 }
597 return false;
598}
599
602template <typename FUNC>
603inline string_view consume_while(string_view& str, FUNC&& pred)
604{
605 const auto start = str.begin();
606 while (!str.empty() && pred(str[0]))
607 str.remove_prefix(1);
608 return string_view(start, str.begin());
609}
610
613inline string_view consume_while(string_view& str, char c)
614{
615 const auto start = str.begin();
616 while (str.starts_with(c))
617 str.remove_prefix(1);
618 return string_view(start, str.begin());
619}
620
623template <typename FUNC>
624inline string_view consume_until(string_view& str, FUNC&& pred)
625{
626 const auto start = str.begin();
627 while (!str.empty() && !pred(str[0]))
628 str.remove_prefix(1);
629 return string_view(start, str.begin());
630}
631
634inline string_view consume_until(string_view& str, char c)
635{
636 const auto start = str.begin();
637 while (!str.empty() && str[0] != c)
638 str.remove_prefix(1);
639 return string_view(start, str.begin());
640}
641
644inline string_view consume_until(string_view& str, string_view end)
645{
646 const auto it = std::search(str.begin(), str.end(), end.begin(), end.end());
647 const auto result = string_view(str.begin(), it);
648 str = { it, str.end() };
649 return result;
650}
651
654inline string_view consume_until_delim(string_view& str, char c)
655{
657
658 const auto start = str.begin();
659 while (!str.empty() && str[0] != c)
660 str.remove_prefix(1);
661 (void)consume(str, c);
662 return string_view(start, str.begin());
663}
664
667inline string_view consume_n(string_view& str, size_t n)
668{
669 n = std::min(str.size(), n);
670 auto result = str.substr(0, n);
671 str.remove_prefix(n);
672 return result;
673}
674
677template <typename FUNC>
678inline string_view consume_n(string_view& str, size_t n, FUNC&& pred)
679{
680 n = std::min(str.size(), n);
681 const auto start = str.begin();
682 while (n-- && !str.empty() && pred(str[0]))
683 str.remove_prefix(1);
684 return string_view(start, str.begin());
685}
686
687
691
695template <typename FUNC>
696void split(string_view source, char delim, FUNC&& func)
697{
698 size_t next = 0;
699 while ((next = source.find_first_of(delim)) != std::string::npos)
700 {
701 func(source.substr(0, next), false);
702 source.remove_prefix(next + 1);
703 }
704 func(source, true);
705}
706
710template <typename FUNC>
711void split(string_view source, string_view delim, FUNC&& func)
712{
713 const size_t delim_size = delim.size();
714 if (delim_size == 0) return;
715
716 size_t next = 0;
717 while ((next = source.find(delim)) != std::string::npos)
718 {
719 func(source.substr(0, next), false);
720 source.remove_prefix(next + delim_size);
721 }
722 func(source, true);
723}
724
727inline std::pair<string_view, string_view> single_split(string_view src, char delim) noexcept
728{
729 size_t split_at = src.find_first_of(delim);
730 if (split_at == std::string::npos)
731 return { src, {} };
732 return { src.substr(0, split_at), src.substr(split_at + 1) };
733}
734
739inline bool single_split(string_view src, char delim, string_view* first, string_view* second) noexcept
740{
741 size_t split_at = src.find_first_of(delim);
742 if (split_at == std::string::npos)
743 return false;
744 if (first) *first = src.substr(0, split_at);
745 if (second) *second = src.substr(split_at + 1);
746 return true;
747}
748
750
751
752
758
760template <typename T>
761std::string join(T&& source)
762{
763 std::stringstream strm{};
764 for (auto&& p : std::forward<T>(source))
765 strm << p;
766 return strm.str();
767}
768
770template <typename T, typename DELIM>
771std::string join(T&& source, DELIM const& delim)
772{
773 std::stringstream strm{};
774 bool first = true;
775 for (auto&& p : std::forward<T>(source))
776 {
777 if (!first) strm << delim;
778 strm << p;
779 first = false;
780 }
781 return strm.str();
782}
783
787template <typename T, typename FUNC, typename DELIM>
788std::string join(T&& source, DELIM const& delim, FUNC&& transform_func)
789{
790 std::stringstream strm;
791 bool first = true;
792 for (auto&& p : source)
793 {
794 if (!first) strm << delim;
795 strm << transform_func(p);
796 first = false;
797 }
798 return strm.str();
799}
800
802
803namespace detail
804{
805 struct from_chars_result
806 {
807 const char* ptr = nullptr;
808 bool failed = false;
809 };
810
811 template <class T>
812 from_chars_result integer_from_chars(const char* const first, const char* const last, T& out_value, const int base) noexcept
813 {
814 assert(base >= 2 && base <= 36);
815
816 bool minus_sign = false;
817 const char* next = first;
818
819 if (std::is_signed<T>::value && next != last && *next == '-')
820 {
821 minus_sign = true;
822 ++next;
823 }
824
825 using unsigned_t = typename std::make_unsigned<T>::type;
826
827 const unsigned_t uint_max_val = static_cast<unsigned_t>(-1);
828 const unsigned_t int_max_val = static_cast<unsigned_t>(uint_max_val >> 1);
829 const unsigned_t abs_int_min_val = static_cast<unsigned_t>(int_max_val + 1);
830
831 unsigned_t risky_val{};
832 unsigned_t max_digit{};
833
834 if (std::is_signed<T>::value)
835 {
836 if (minus_sign)
837 {
838 risky_val = static_cast<unsigned_t>(abs_int_min_val / base);
839 max_digit = static_cast<unsigned_t>(abs_int_min_val % base);
840 }
841 else
842 {
843 risky_val = static_cast<unsigned_t>(int_max_val / base);
844 max_digit = static_cast<unsigned_t>(int_max_val % base);
845 }
846 }
847 else
848 {
849 risky_val = static_cast<unsigned_t>(uint_max_val / base);
850 max_digit = static_cast<unsigned_t>(uint_max_val % base);
851 }
852
853 unsigned_t value{};
854
855 bool overflowed = false;
856
857 for (; next != last; ++next)
858 {
859 const int digit = ascii::digit_to_number(static_cast<char32_t>(*next));
860
861 if (digit >= base)
862 break;
863
864 if (value < risky_val || (value == risky_val && static_cast<unsigned_t>(digit) <= max_digit))
865 {
866 value = static_cast<unsigned_t>(value * base + digit);
867 }
868 else
869 {
870 overflowed = true;
871 }
872 }
873
874 if (next - first == static_cast<ptrdiff_t>(minus_sign))
875 return { first, true };
876
877 if (overflowed)
878 return { next, true };
879
880 if (std::is_signed<T>::value && minus_sign)
881 value = static_cast<unsigned_t>(0 - value);
882
883 out_value = static_cast<T>(value);
884
885 return { next, false };
886 }
887
888 template <typename T>
889 T string_to_number(string_view str, size_t* idx = nullptr, int base = 10) noexcept
890 {
891 T value{};
892 const auto res = integer_from_chars(str.data(), str.data_end(), value, base);
893 if (idx && !res.failed)
894 *idx = size_t(res.ptr - str.data());
895 return value;
896 }
897
898 template <typename T>
899 inline T consume_num(string_view& str, int base = 10) noexcept
900 {
901 size_t idx = 0;
902 const T result = detail::string_to_number<T>(str, &idx, base);
903 str.remove_prefix(idx);
904 return result;
905 }
906}
907
911inline int stoi(string_view str, size_t* idx = nullptr, int base = 10) noexcept { return detail::string_to_number<int>(str, idx, base); }
912inline long stol(string_view str, size_t* idx = nullptr, int base = 10) noexcept { return detail::string_to_number<long>(str, idx, base); }
913inline long long stoll(string_view str, size_t* idx = nullptr, int base = 10) noexcept { return detail::string_to_number<long long>(str, idx, base); }
914inline unsigned long stoul(string_view str, size_t* idx = nullptr, int base = 10) noexcept { return detail::string_to_number<unsigned long>(str, idx, base); }
915inline unsigned long long stoull(string_view str, size_t* idx = nullptr, int base = 10) noexcept { return detail::string_to_number<unsigned long long>(str, idx, base); }
916
917inline int consume_int(string_view& str, int base = 10) noexcept { return detail::consume_num<int>(str, base); }
918inline long consume_long(string_view& str, int base = 10) noexcept { return detail::consume_num<long>(str, base); }
919inline long long consume_long_long(string_view& str, int base = 10) noexcept { return detail::consume_num<long long>(str, base); }
920inline unsigned long consume_unsigned_long(string_view& str, int base = 10) noexcept { return detail::consume_num<unsigned long>(str, base); }
921inline unsigned long long consume_usigned_long_long(string_view& str, int base = 10) noexcept { return detail::consume_num<unsigned long long>(str, base); }
922
923template <typename T>
924bool consume_num(string_view& str, T& out_val, int base = 10) noexcept
925{
926 const auto res = detail::integer_from_chars(str.data(), str.data_end(), value, base);
927 return !res.failed;
928}
930
931#endif
constexpr char32_t number_to_digit(int v) noexcept
Convert a number between 0 and 9 to its ASCII representation (only gives meaningful results with argu...
Definition string_ops.h:452
constexpr int digit_to_number(char32_t cp) noexcept
Convert an ASCII digit character to its numerical value (only gives meaningful results with valid dig...
Definition string_ops.h:457
constexpr char32_t number_to_xdigit(int v) noexcept
Convert a number between 0 and 15 to its ASCII representation (only gives meaningful results with arg...
Definition string_ops.h:454
constexpr int xdigit_to_number(char32_t cp) noexcept
Convert an ASCII xdigit to its numerical value (only gives meaningful results with valid xdigit argum...
Definition string_ops.h:460
constexpr auto join(std::array< T, Ns >... arrays)
Arrays.
Definition ranges.h:209
constexpr decltype(auto) at(random_access_range auto &range, std::integral auto index)
Returns a reference to the value at index of range
Definition ranges.h:59
constexpr std::pair< std::span< T >, std::span< T > > split_at(std::span< T, N > span, size_t index)
Span stuff.
Definition ranges.h:148
constexpr __contains_fn contains
contains(range, el)
Definition ranges.h:247
char consume_or(std::string_view &str, char or_else)
Consumes the first character from str, returning it, or or_else if string is empty.
Definition string_ops.h:715
std::string_view consume_while(std::string_view &str, FUNC &&pred)
Consumes characters from the beginning of str while they match pred(str[0]).
Definition string_ops.h:755
char consume_any(std::string_view &str, ARGS &&... args)
Consumes any of the characters in 'chars' if it's the first char of str.
Definition string_ops.h:688
std::string_view consume_until(std::string_view &str, FUNC &&pred)
Consumes characters from the beginning of str until one matches pred(str[0]), exclusive.
Definition string_ops.h:788
constexpr bool is_inside(std::string_view big_string, std::string_view smaller_string)
Checks if smaller_string is a true subset of big_string (true subset meaning they view over overlappi...
Definition string_ops.h:266
constexpr void split(std::string_view source, char delim, FUNC &&func) noexcept(noexcept(func(std::string_view{}, true)))
Performs a basic "split" operation, calling func for each part of source delimited by delim.
Definition string_ops.h:955
std::string_view consume_while_any(std::string_view &str, ARGS &&... args)
Consumes a run of any of the characters in 'chars' at the beginning of str.
Definition string_ops.h:776
char consume(std::string_view &str)
Consumes and returns the first character in the str, or \0 if no more characters.
Definition string_ops.h:652
std::string_view consume_until_delim(std::string_view &str, char c)
Consumes characters from the beginning of str until one is equal to c, inclusive.
Definition string_ops.h:844
constexpr std::pair< std::string_view, std::string_view > single_split(std::string_view src, char delim) noexcept
Splits src once on the first instance of delim
constexpr std::string_view back(std::string_view child_to_back_up, std::string_view parent, size_t n=1) noexcept
Creates a string_view with its beginning moved back by n characters, limited to a parent range.
Definition string_ops.h:241
bool consume_at_end(std::string_view &str, char val)
Consumes the last character from str if it matches val.
Definition string_ops.h:727
std::string_view substr(std::string_view str, intptr_t start, size_t count=std::string::npos) noexcept
Gets a substring of str starting at start and containing count characters.
Definition string_ops.h:559
std::string_view consume_n(std::string_view &str, size_t n)
Consumes at most n characters from the beginning of str.
Definition string_ops.h:857
The below code is based on Sun's libm library code, which is licensed under the following license: