OpenTTD Source 20260218-master-g2123fca5ea
string_consumer.hpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#ifndef STRING_CONSUMER_HPP
11#define STRING_CONSUMER_HPP
12
13#include <charconv>
14#include "format.hpp"
15
26public:
28 using size_type = std::string_view::size_type;
29
33 static constexpr size_type npos = std::string_view::npos;
34
39 static const std::string_view WHITESPACE_NO_NEWLINE;
44 static const std::string_view WHITESPACE_OR_NEWLINE;
45
46private:
47 std::string_view src;
49
50 static void LogError(std::string &&msg);
51
52public:
57 explicit StringConsumer(std::string_view src) : src(src) {}
62 explicit StringConsumer(const std::string &src) : src(src) {}
67 explicit StringConsumer(std::span<const char> src) : src(src.data(), src.size()) {}
68
73 [[nodiscard]] bool AnyBytesLeft() const noexcept { return this->position < this->src.size(); }
78 [[nodiscard]] size_type GetBytesLeft() const noexcept { return this->src.size() - this->position; }
79
84 [[nodiscard]] bool AnyBytesRead() const noexcept { return this->position > 0; }
89 [[nodiscard]] size_type GetBytesRead() const noexcept { return this->position; }
90
95 [[nodiscard]] std::string_view GetOrigData() const noexcept { return this->src; }
100 [[nodiscard]] std::string_view GetReadData() const noexcept { return this->src.substr(0, this->position); }
105 [[nodiscard]] std::string_view GetLeftData() const noexcept { return this->src.substr(this->position); }
106
110 void SkipAll() { this->position = this->src.size(); }
111
116 [[nodiscard]] std::optional<uint8_t> PeekUint8() const;
121 [[nodiscard]] std::optional<uint8_t> TryReadUint8()
122 {
123 auto value = this->PeekUint8();
124 if (value.has_value()) this->SkipUint8();
125 return value;
126 }
127
132 [[nodiscard]] uint8_t ReadUint8(uint8_t def = 0)
133 {
134 auto value = this->PeekUint8();
135 this->SkipUint8(); // always advance
136 return value.value_or(def);
137 }
138
141 void SkipUint8() { this->Skip(1); }
142
147 [[nodiscard]] std::optional<int8_t> PeekSint8() const
148 {
149 auto result = PeekUint8();
150 if (!result.has_value()) return std::nullopt;
151 return static_cast<int8_t>(*result);
152 }
153
157 [[nodiscard]] std::optional<int8_t> TryReadSint8()
158 {
159 auto value = this->PeekSint8();
160 if (value.has_value()) this->SkipSint8();
161 return value;
162 }
163
168 [[nodiscard]] int8_t ReadSint8(int8_t def = 0)
169 {
170 auto value = this->PeekSint8();
171 this->SkipSint8(); // always advance
172 return value.value_or(def);
173 }
174
177 void SkipSint8() { this->Skip(1); }
178
183 [[nodiscard]] std::optional<uint16_t> PeekUint16LE() const;
188 [[nodiscard]] std::optional<uint16_t> TryReadUint16LE()
189 {
190 auto value = this->PeekUint16LE();
191 if (value.has_value()) this->SkipUint16LE();
192 return value;
193 }
194
200 [[nodiscard]] uint16_t ReadUint16LE(uint16_t def = 0)
201 {
202 auto value = this->PeekUint16LE();
203 this->SkipUint16LE(); // always advance
204 return value.value_or(def);
205 }
206
210 void SkipUint16LE() { this->Skip(2); }
211
216 [[nodiscard]] std::optional<int16_t> PeekSint16LE() const
217 {
218 auto result = PeekUint16LE();
219 if (!result.has_value()) return std::nullopt;
220 return static_cast<int16_t>(*result);
221 }
222
226 [[nodiscard]] std::optional<int16_t> TryReadSint16LE()
227 {
228 auto value = this->PeekSint16LE();
229 if (value.has_value()) this->SkipSint16LE();
230 return value;
231 }
232
238 [[nodiscard]] int16_t ReadSint16LE(int16_t def = 0)
239 {
240 auto value = this->PeekSint16LE();
241 this->SkipSint16LE(); // always advance
242 return value.value_or(def);
243 }
244
248 void SkipSint16LE() { this->Skip(2); }
249
254 [[nodiscard]] std::optional<uint32_t> PeekUint32LE() const;
259 [[nodiscard]] std::optional<uint32_t> TryReadUint32LE()
260 {
261 auto value = this->PeekUint32LE();
262 if (value.has_value()) this->SkipUint32LE();
263 return value;
264 }
265
271 [[nodiscard]] uint32_t ReadUint32LE(uint32_t def = 0)
272 {
273 auto value = this->PeekUint32LE();
274 this->SkipUint32LE(); // always advance
275 return value.value_or(def);
276 }
277
281 void SkipUint32LE() { this->Skip(4); }
282
287 [[nodiscard]] std::optional<int32_t> PeekSint32LE() const
288 {
289 auto result = PeekUint32LE();
290 if (!result.has_value()) return std::nullopt;
291 return static_cast<int32_t>(*result);
292 }
293
297 [[nodiscard]] std::optional<int32_t> TryReadSint32LE()
298 {
299 auto value = this->PeekSint32LE();
300 if (value.has_value()) this->SkipSint32LE();
301 return value;
302 }
303
309 [[nodiscard]] int32_t ReadSint32LE(int32_t def = 0)
310 {
311 auto value = this->PeekSint32LE();
312 this->SkipSint32LE(); // always advance
313 return value.value_or(def);
314 }
315
319 void SkipSint32LE() { this->Skip(4); }
320
325 [[nodiscard]] std::optional<uint64_t> PeekUint64LE() const;
330 [[nodiscard]] std::optional<uint64_t> TryReadUint64LE()
331 {
332 auto value = this->PeekUint64LE();
333 if (value.has_value()) this->SkipUint64LE();
334 return value;
335 }
336
342 [[nodiscard]] uint64_t ReadUint64LE(uint64_t def = 0)
343 {
344 auto value = this->PeekUint64LE();
345 this->SkipUint64LE(); // always advance
346 return value.value_or(def);
347 }
348
352 void SkipUint64LE() { this->Skip(8); }
353
358 [[nodiscard]] std::optional<int64_t> PeekSint64LE() const
359 {
360 auto result = PeekUint64LE();
361 if (!result.has_value()) return std::nullopt;
362 return static_cast<int64_t>(*result);
363 }
364
368 [[nodiscard]] std::optional<int64_t> TryReadSint64LE()
369 {
370 auto value = this->PeekSint64LE();
371 if (value.has_value()) this->SkipSint64LE();
372 return value;
373 }
374
380 [[nodiscard]] int64_t ReadSint64LE(int64_t def = 0)
381 {
382 auto value = this->PeekSint64LE();
383 this->SkipSint64LE(); // always advance
384 return value.value_or(def);
385 }
386
390 void SkipSint64LE() { this->Skip(8); }
391
396 [[nodiscard]] std::optional<char> PeekChar() const;
401 [[nodiscard]] std::optional<char> TryReadChar()
402 {
403 auto value = this->PeekChar();
404 if (value.has_value()) this->SkipChar();
405 return value;
406 }
407
412 [[nodiscard]] char ReadChar(char def = '?') {
413 auto value = this->PeekChar();
414 this->SkipChar(); // always advance
415 return value.value_or(def);
416 }
417
420 void SkipChar() { this->Skip(1); }
421
426 [[nodiscard]] std::pair<size_type, char32_t> PeekUtf8() const;
431 [[nodiscard]] std::optional<char32_t> TryReadUtf8()
432 {
433 auto [len, value] = this->PeekUtf8();
434 if (len == 0) return std::nullopt;
435 this->Skip(len);
436 return value;
437 }
438
444 [[nodiscard]] char32_t ReadUtf8(char32_t def = '?')
445 {
446 auto [len, value] = this->PeekUtf8();
447 this->Skip(len > 0 ? len : 1); // advance at least one byte
448 return len > 0 ? value : def;
449 }
450
457 void SkipUtf8()
458 {
459 auto len = this->PeekUtf8().first;
460 this->Skip(len > 0 ? len : 1); // advance at least one byte
461 }
462
468 [[nodiscard]] bool PeekIf(std::string_view str) const
469 {
470 return this->src.compare(this->position, str.size(), str) == 0;
471 }
472
477 [[nodiscard]] bool ReadIf(std::string_view str)
478 {
479 bool result = this->PeekIf(str);
480 if (result) this->Skip(str.size());
481 return result;
482 }
483
487 void SkipIf(std::string_view str)
488 {
489 if (this->PeekIf(str)) this->Skip(str.size());
490 }
491
497 [[nodiscard]] bool PeekCharIf(char c) const
498 {
499 return this->PeekIf({&c, 1});
500 }
501
506 [[nodiscard]] bool ReadCharIf(char c)
507 {
508 return this->ReadIf({&c, 1});
509 }
510
514 void SkipCharIf(char c)
515 {
516 return this->SkipIf({&c, 1});
517 }
518
524 [[nodiscard]] bool PeekUtf8If(char32_t c) const
525 {
526 auto [len, result] = this->PeekUtf8();
527 return len > 0 && result == c;
528 }
529
534 [[nodiscard]] bool ReadUtf8If(char32_t c)
535 {
536 auto [len, result] = this->PeekUtf8();
537 if (len == 0 || result != c) return false;
538 this->Skip(len);
539 return true;
540 }
541
545 void SkipUtf8If(char32_t c)
546 {
547 auto [len, result] = this->PeekUtf8();
548 if (len > 0 && result == c) {
549 this->Skip(len);
550 }
551 }
552
558 [[nodiscard]] std::string_view Peek(size_type len) const;
564 [[nodiscard]] std::string_view Read(size_type len)
565 {
566 auto result = this->Peek(len);
567 if (len != npos && len != result.size()) {
568 LogError(fmt::format("Source buffer too short: {} > {}", len, result.size()));
569 }
570 this->Skip(result.size());
571 return result;
572 }
573
577 void Skip(size_type len);
578
584 [[nodiscard]] size_type Find(std::string_view str) const;
590 [[nodiscard]] size_type FindChar(char c) const
591 {
592 return this->Find({&c, 1});
593 }
594
599 [[nodiscard]] size_type FindUtf8(char32_t c) const;
600
606 [[nodiscard]] size_type FindCharIn(std::string_view chars) const;
612 [[nodiscard]] size_type FindCharNotIn(std::string_view chars) const;
613
619 [[nodiscard]] std::optional<char> PeekCharIfIn(std::string_view chars) const
620 {
621 assert(!chars.empty());
622 std::optional<char> c = this->PeekChar();
623 if (c.has_value() && chars.find(*c) != std::string_view::npos) return c;
624 return std::nullopt;
625 }
626
631 [[nodiscard]] std::optional<char> ReadCharIfIn(std::string_view chars)
632 {
633 auto result = this->PeekCharIfIn(chars);
634 if (result.has_value()) this->Skip(1);
635 return result;
636 }
637
641 void SkipCharIfIn(std::string_view chars)
642 {
643 auto result = this->PeekCharIfIn(chars);
644 if (result.has_value()) this->Skip(1);
645 }
646
652 [[nodiscard]] std::optional<char> PeekCharIfNotIn(std::string_view chars) const
653 {
654 assert(!chars.empty());
655 std::optional<char> c = this->PeekChar();
656 if (c.has_value() && chars.find(*c) == std::string_view::npos) return c;
657 return std::nullopt;
658 }
659
664 [[nodiscard]] std::optional<char> ReadCharIfNotIn(std::string_view chars)
665 {
666 auto result = this->PeekCharIfNotIn(chars);
667 if (result.has_value()) this->Skip(1);
668 return result;
669 }
670
674 void SkipCharIfNotIn(std::string_view chars)
675 {
676 auto result = this->PeekCharIfNotIn(chars);
677 if (result.has_value()) this->Skip(1);
678 }
679
685 [[nodiscard]] std::string_view PeekUntilCharIn(std::string_view chars) const
686 {
687 size_type len = this->FindCharIn(chars);
688 return this->Peek(len);
689 }
690
695 [[nodiscard]] std::string_view ReadUntilCharIn(std::string_view chars)
696 {
697 size_type len = this->FindCharIn(chars);
698 return this->Read(len);
699 }
700
704 void SkipUntilCharIn(std::string_view chars)
705 {
706 size_type len = this->FindCharIn(chars);
707 this->Skip(len);
708 }
709
715 [[nodiscard]] std::string_view PeekUntilCharNotIn(std::string_view chars) const
716 {
717 size_type len = this->FindCharNotIn(chars);
718 return this->Peek(len);
719 }
720
725 [[nodiscard]] std::string_view ReadUntilCharNotIn(std::string_view chars)
726 {
727 size_type len = this->FindCharNotIn(chars);
728 return this->Read(len);
729 }
730
734 void SkipUntilCharNotIn(std::string_view chars)
735 {
736 size_type len = this->FindCharNotIn(chars);
737 this->Skip(len);
738 }
739
750
757 [[nodiscard]] std::string_view PeekUntil(std::string_view str, SeparatorUsage sep) const;
764 [[nodiscard]] std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
765 {
766 assert(!str.empty());
767 auto result = this->PeekUntil(str, sep);
768 this->Skip(result.size());
769 switch (sep) {
770 default:
771 break;
773 this->SkipIf(str);
774 break;
776 while (this->ReadIf(str)) {}
777 break;
778 }
779 return result;
780 }
781
786 void SkipUntil(std::string_view str, SeparatorUsage sep)
787 {
788 assert(!str.empty());
789 this->Skip(this->Find(str));
790 switch (sep) {
791 default:
792 break;
795 this->SkipIf(str);
796 break;
799 while (this->ReadIf(str)) {}
800 break;
801 }
802 }
803
810 [[nodiscard]] std::string_view PeekUntilChar(char c, SeparatorUsage sep) const
811 {
812 return this->PeekUntil({&c, 1}, sep);
813 }
814
820 [[nodiscard]] std::string_view ReadUntilChar(char c, SeparatorUsage sep)
821 {
822 return this->ReadUntil({&c, 1}, sep);
823 }
824
830 {
831 this->SkipUntil({&c, 1}, sep);
832 }
833
840 [[nodiscard]] std::string_view PeekUntilUtf8(char32_t c, SeparatorUsage sep) const;
847 [[nodiscard]] std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep);
853 void SkipUntilUtf8(char32_t c, SeparatorUsage sep);
854
855private:
865 template <class T>
866 [[nodiscard]] static std::pair<size_type, T> ParseIntegerBase(std::string_view src, int base, bool clamp, bool log_errors)
867 {
868 if (base == 0) {
869 /* Try positive hex */
870 if (src.starts_with("0x") || src.starts_with("0X")) {
871 auto [len, value] = ParseIntegerBase<T>(src.substr(2), 16, clamp, log_errors);
872 if (len == 0) return {};
873 return {len + 2, value};
874 }
875
876 /* Try negative hex */
877 if (std::is_signed_v<T> && (src.starts_with("-0x") || src.starts_with("-0X"))) {
878 using Unsigned = std::make_unsigned_t<T>;
879 auto [len, uvalue] = ParseIntegerBase<Unsigned>(src.substr(3), 16, clamp, log_errors);
880 if (len == 0) return {};
881 T value = static_cast<T>(0 - uvalue);
882 if (value > 0) {
883 if (!clamp) {
884 if (log_errors) LogError(fmt::format("Integer out of range: '{}'", src.substr(0, len + 3)));
885 return {};
886 }
887 value = std::numeric_limits<T>::lowest();
888 }
889 return {len + 3, value};
890 }
891
892 /* Try decimal */
893 return ParseIntegerBase<T>(src, 10, clamp, log_errors);
894 }
895
896 T value{};
897 assert(base == 8 || base == 10 || base == 16); // we only support these bases when skipping
898 auto result = std::from_chars(src.data(), src.data() + src.size(), value, base);
899 auto len = result.ptr - src.data();
900 if (result.ec == std::errc::result_out_of_range) {
901 if (!clamp) {
902 if (log_errors) LogError(fmt::format("Integer out of range: '{}'+'{}'", src.substr(0, len), src.substr(len, 4)));
903 return {};
904 }
905 if (src.starts_with("-")) {
906 value = std::numeric_limits<T>::lowest();
907 } else {
908 value = std::numeric_limits<T>::max();
909 }
910 } else if (result.ec != std::errc{}) {
911 if (log_errors) LogError(fmt::format("Cannot parse integer: '{}'+'{}'", src.substr(0, len), src.substr(len, 4)));
912 return {};
913 }
914 return {len, value};
915 }
916
917public:
927 template <class T>
928 [[nodiscard]] std::pair<size_type, T> PeekIntegerBase(int base, bool clamp = false) const
929 {
930 return ParseIntegerBase<T>(this->src.substr(this->position), base, clamp, false);
931 }
932
941 template <class T>
942 [[nodiscard]] std::optional<T> TryReadIntegerBase(int base, bool clamp = false)
943 {
944 auto [len, value] = this->PeekIntegerBase<T>(base, clamp);
945 if (len == 0) return std::nullopt;
946 this->SkipIntegerBase(base);
947 return value;
948 }
949
960 template <class T>
961 [[nodiscard]] T ReadIntegerBase(int base, T def = 0, bool clamp = false)
962 {
963 auto [len, value] = ParseIntegerBase<T>(this->src.substr(this->position), base, clamp, true);
964 this->SkipIntegerBase(base); // always advance
965 return len > 0 ? value : def;
966 }
967
974 void SkipIntegerBase(int base);
975};
976
987template <class T = uint32_t>
988static inline std::optional<T> ParseInteger(std::string_view arg, int base = 10, bool clamp = false)
989{
990 StringConsumer consumer{arg};
992 auto result = consumer.TryReadIntegerBase<T>(base, clamp);
994 if (consumer.AnyBytesLeft()) return std::nullopt;
995 return result;
996}
997
998#endif /* STRING_CONSUMER_HPP */
Parse data from a string / buffer.
bool ReadCharIf(char c)
Check whether the next 8-bit char matches 'c', and skip it.
std::string_view Peek(size_type len) const
Peek the next 'len' bytes.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
void SkipUint64LE()
Skip binary uint64, and advance reader.
bool PeekUtf8If(char32_t c) const
Check whether the next UTF-8 char matches 'c'.
std::string_view GetOrigData() const noexcept
Get the original data, as passed to the constructor.
void SkipCharIfIn(std::string_view chars)
If the next 8-bit char is in 'chars', skip it.
std::optional< uint32_t > TryReadUint32LE()
Try to read binary uint32, and then advance reader.
char32_t ReadUtf8(char32_t def='?')
Read UTF-8 character, and advance reader.
void SkipCharIf(char c)
If the next data matches the 8-bit char 'c', then skip it.
std::string_view ReadUntilChar(char c, SeparatorUsage sep)
Read data until the first occurrence of 8-bit char 'c', and advance reader.
size_type FindChar(char c) const
Find first occurrence of 8-bit char 'c'.
void SkipUntilChar(char c, SeparatorUsage sep)
Skip data until the first occurrence of 8-bit char 'c'.
SeparatorUsage
Treatment of separator characters.
@ READ_ALL_SEPARATORS
Read all consecutive separators, and include them all in the result.
@ READ_ONE_SEPARATOR
Read one separator, and include it in the result.
@ SKIP_ALL_SEPARATORS
Read and discard all consecutive separators, do not include any in the result.
@ SKIP_ONE_SEPARATOR
Read and discard one separator, do not include it in the result.
@ KEEP_SEPARATOR
Keep the separator in the data as next value to be read.
int16_t ReadSint16LE(int16_t def=0)
Read binary int16 using little endian, and advance reader.
void SkipUtf8()
Skip UTF-8 character, and advance reader.
std::optional< char > PeekCharIfIn(std::string_view chars) const
Check whether the next 8-bit char is in 'chars'.
StringConsumer(std::string_view src)
Construct parser with data from string.
char ReadChar(char def='?')
Read 8-bit character, and advance reader.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
uint8_t ReadUint8(uint8_t def=0)
Read binary uint8, and advance reader.
bool PeekCharIf(char c) const
Check whether the next 8-bit char matches 'c'.
std::optional< uint32_t > PeekUint32LE() const
Peek binary uint32 using little endian.
std::optional< uint16_t > TryReadUint16LE()
Try to read binary uint16, and then advance reader.
size_type GetBytesLeft() const noexcept
Get number of bytes left to read.
static std::pair< size_type, T > ParseIntegerBase(std::string_view src, int base, bool clamp, bool log_errors)
Parse an integer from the given string.
std::string_view ReadUntilCharNotIn(std::string_view chars)
Read 8-bit chars, while they are in 'chars', until they are not; and advance reader.
std::string_view PeekUntil(std::string_view str, SeparatorUsage sep) const
Peek data until the first occurrence of 'str'.
std::optional< char > PeekCharIfNotIn(std::string_view chars) const
Check whether the next 8-bit char is not in 'chars'.
void SkipUntilCharIn(std::string_view chars)
Skip 8-bit chars, while they are not in 'chars', until they are.
std::string_view::size_type size_type
The type of the size of our strings.
int8_t ReadSint8(int8_t def=0)
Read binary int8, and advance reader.
void SkipUint16LE()
Skip binary uint16, and advance reader.
std::optional< int8_t > PeekSint8() const
Peek binary int8.
uint16_t ReadUint16LE(uint16_t def=0)
Read binary uint16 using little endian, and advance reader.
void SkipChar()
Skip 8-bit character, and advance reader.
static const std::string_view WHITESPACE_OR_NEWLINE
ASCII whitespace characters, including new-line.
void SkipSint8()
Skip binary int8.
void SkipUint32LE()
Skip binary uint32, and advance reader.
std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
Read data until the first occurrence of 'str', and advance reader.
void SkipUntil(std::string_view str, SeparatorUsage sep)
Skip data until the first occurrence of 'str'.
int64_t ReadSint64LE(int64_t def=0)
Read binary int64 using little endian, and advance reader.
static const std::string_view WHITESPACE_NO_NEWLINE
ASCII whitespace characters, excluding new-line.
std::optional< char > PeekChar() const
Peek 8-bit character.
static void LogError(std::string &&msg)
Log an error in the processing (too small buffer, integer out of range, etc.).
std::optional< int16_t > PeekSint16LE() const
Peek binary int16 using little endian.
std::pair< size_type, T > PeekIntegerBase(int base, bool clamp=false) const
Peek and parse an integer in number 'base'.
std::optional< char > ReadCharIfIn(std::string_view chars)
Read next 8-bit char, check whether it is in 'chars', and advance reader.
std::optional< char > TryReadChar()
Try to read a 8-bit character, and then advance reader.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
std::string_view PeekUntilUtf8(char32_t c, SeparatorUsage sep) const
Peek data until the first occurrence of UTF-8 char 'c'.
std::optional< uint64_t > PeekUint64LE() const
Peek binary uint64 using little endian.
void SkipUntilCharNotIn(std::string_view chars)
Skip 8-bit chars, while they are in 'chars', until they are not.
bool AnyBytesRead() const noexcept
Check whether any bytes were already read.
std::optional< int32_t > TryReadSint32LE()
Try to read binary int32, and then advance reader.
void SkipUint8()
Skip binary uint8.
void SkipAll()
Discard all remaining data.
StringConsumer(const std::string &src)
Construct parser with data from string.
std::string_view ReadUntilCharIn(std::string_view chars)
Read 8-bit chars, while they are not in 'chars', until they are; and advance reader.
uint32_t ReadUint32LE(uint32_t def=0)
Read binary uint32 using little endian, and advance reader.
std::optional< int32_t > PeekSint32LE() const
Peek binary int32 using little endian.
std::optional< char32_t > TryReadUtf8()
Try to read a UTF-8 character, and then advance reader.
int32_t ReadSint32LE(int32_t def=0)
Read binary int32 using little endian, and advance reader.
void SkipCharIfNotIn(std::string_view chars)
If the next 8-bit char is not in 'chars', skip it.
size_type FindCharNotIn(std::string_view chars) const
Find first occurrence of any 8-bit char not in 'chars'.
void SkipIf(std::string_view str)
If the next data matches 'str', then skip it.
std::optional< uint16_t > PeekUint16LE() const
Peek binary uint16 using little endian.
std::optional< uint64_t > TryReadUint64LE()
Try to read binary uint64, and then advance reader.
size_type position
The current parsing position in the string.
std::optional< uint8_t > TryReadUint8()
Try to read binary uint8, and then advance reader.
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
std::string_view Read(size_type len)
Read the next 'len' bytes, and advance reader.
std::string_view src
The string to parse.
bool ReadUtf8If(char32_t c)
Check whether the next UTF-8 char matches 'c', and skip it.
void SkipIntegerBase(int base)
Skip an integer in number 'base'.
void SkipSint64LE()
Skip binary int64, and advance reader.
std::string_view GetReadData() const noexcept
Get already read data.
std::optional< int64_t > PeekSint64LE() const
Peek binary int64 using little endian.
static constexpr size_type npos
Special value for "end of data".
std::string_view GetLeftData() const noexcept
Get data left to read.
size_type GetBytesRead() const noexcept
Get number of already read bytes.
void Skip(size_type len)
Discard some bytes.
size_type Find(std::string_view str) const
Find first occurrence of 'str'.
bool PeekIf(std::string_view str) const
Check whether the next data matches 'str'.
std::optional< uint8_t > PeekUint8() const
Peek binary uint8.
std::string_view PeekUntilChar(char c, SeparatorUsage sep) const
Peek data until the first occurrence of 8-bit char 'c'.
void SkipUtf8If(char32_t c)
If the next data matches the UTF-8 char 'c', then skip it.
uint64_t ReadUint64LE(uint64_t def=0)
Read binary uint64 using little endian, and advance reader.
std::optional< int64_t > TryReadSint64LE()
Try to read binary int64, and then advance reader.
void SkipSint32LE()
Skip binary int32, and advance reader.
std::string_view PeekUntilCharIn(std::string_view chars) const
Peek 8-bit chars, while they are not in 'chars', until they are.
std::optional< char > ReadCharIfNotIn(std::string_view chars)
Read next 8-bit char, check whether it is not in 'chars', and advance reader.
void SkipUntilUtf8(char32_t c, SeparatorUsage sep)
Skip data until the first occurrence of UTF-8 char 'c'.
std::optional< int8_t > TryReadSint8()
Try to read binary int8, and then advance reader.
void SkipSint16LE()
Skip binary int16, and advance reader.
StringConsumer(std::span< const char > src)
Construct parser with data from span.
std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep)
Read data until the first occurrence of UTF-8 char 'c', and advance reader.
std::string_view PeekUntilCharNotIn(std::string_view chars) const
Peek 8-bit chars, while they are in 'chars', until they are not.
std::pair< size_type, char32_t > PeekUtf8() const
Peek UTF-8 character.
size_type FindCharIn(std::string_view chars) const
Find first occurrence of any 8-bit char in 'chars'.
std::optional< int16_t > TryReadSint16LE()
Try to read binary int16, and then advance reader.
size_type FindUtf8(char32_t c) const
Find first occurrence of UTF-8 char 'c'.
String formatting functions and helpers.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.