OpenTTD Source 20260108-master-g8ba1860eaa
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
10#ifndef STRING_CONSUMER_HPP
11#define STRING_CONSUMER_HPP
12
13#include <charconv>
14#include "format.hpp"
15
26public:
27 using size_type = std::string_view::size_type;
28
32 static constexpr size_type npos = std::string_view::npos;
33
38 static const std::string_view WHITESPACE_NO_NEWLINE;
43 static const std::string_view WHITESPACE_OR_NEWLINE;
44
45private:
46 std::string_view src;
47 size_type position = 0;
48
49 static void LogError(std::string &&msg);
50
51public:
55 explicit StringConsumer(std::string_view src) : src(src) {}
59 explicit StringConsumer(const std::string &src) : src(src) {}
63 explicit StringConsumer(std::span<const char> src) : src(src.data(), src.size()) {}
64
68 [[nodiscard]] bool AnyBytesLeft() const noexcept { return this->position < this->src.size(); }
72 [[nodiscard]] size_type GetBytesLeft() const noexcept { return this->src.size() - this->position; }
73
77 [[nodiscard]] bool AnyBytesRead() const noexcept { return this->position > 0; }
81 [[nodiscard]] size_type GetBytesRead() const noexcept { return this->position; }
82
86 [[nodiscard]] std::string_view GetOrigData() const noexcept { return this->src; }
90 [[nodiscard]] std::string_view GetReadData() const noexcept { return this->src.substr(0, this->position); }
94 [[nodiscard]] std::string_view GetLeftData() const noexcept { return this->src.substr(this->position); }
95
99 void SkipAll() { this->position = this->src.size(); }
100
105 [[nodiscard]] std::optional<uint8_t> PeekUint8() const;
109 [[nodiscard]] std::optional<uint8_t> TryReadUint8()
110 {
111 auto value = this->PeekUint8();
112 if (value.has_value()) this->SkipUint8();
113 return value;
114 }
120 [[nodiscard]] uint8_t ReadUint8(uint8_t def = 0)
121 {
122 auto value = this->PeekUint8();
123 this->SkipUint8(); // always advance
124 return value.value_or(def);
125 }
129 void SkipUint8() { this->Skip(1); }
130
135 [[nodiscard]] std::optional<int8_t> PeekSint8() const
136 {
137 auto result = PeekUint8();
138 if (!result.has_value()) return std::nullopt;
139 return static_cast<int8_t>(*result);
140 }
144 [[nodiscard]] std::optional<int8_t> TryReadSint8()
145 {
146 auto value = this->PeekSint8();
147 if (value.has_value()) this->SkipSint8();
148 return value;
149 }
155 [[nodiscard]] int8_t ReadSint8(int8_t def = 0)
156 {
157 auto value = this->PeekSint8();
158 this->SkipSint8(); // always advance
159 return value.value_or(def);
160 }
164 void SkipSint8() { this->Skip(1); }
165
170 [[nodiscard]] std::optional<uint16_t> PeekUint16LE() const;
174 [[nodiscard]] std::optional<uint16_t> TryReadUint16LE()
175 {
176 auto value = this->PeekUint16LE();
177 if (value.has_value()) this->SkipUint16LE();
178 return value;
179 }
186 [[nodiscard]] uint16_t ReadUint16LE(uint16_t def = 0)
187 {
188 auto value = this->PeekUint16LE();
189 this->SkipUint16LE(); // always advance
190 return value.value_or(def);
191 }
196 void SkipUint16LE() { this->Skip(2); }
197
202 [[nodiscard]] std::optional<int16_t> PeekSint16LE() const
203 {
204 auto result = PeekUint16LE();
205 if (!result.has_value()) return std::nullopt;
206 return static_cast<int16_t>(*result);
207 }
211 [[nodiscard]] std::optional<int16_t> TryReadSint16LE()
212 {
213 auto value = this->PeekSint16LE();
214 if (value.has_value()) this->SkipSint16LE();
215 return value;
216 }
223 [[nodiscard]] int16_t ReadSint16LE(int16_t def = 0)
224 {
225 auto value = this->PeekSint16LE();
226 this->SkipSint16LE(); // always advance
227 return value.value_or(def);
228 }
233 void SkipSint16LE() { this->Skip(2); }
234
239 [[nodiscard]] std::optional<uint32_t> PeekUint32LE() const;
243 [[nodiscard]] std::optional<uint32_t> TryReadUint32LE()
244 {
245 auto value = this->PeekUint32LE();
246 if (value.has_value()) this->SkipUint32LE();
247 return value;
248 }
255 [[nodiscard]] uint32_t ReadUint32LE(uint32_t def = 0)
256 {
257 auto value = this->PeekUint32LE();
258 this->SkipUint32LE(); // always advance
259 return value.value_or(def);
260 }
265 void SkipUint32LE() { this->Skip(4); }
266
271 [[nodiscard]] std::optional<int32_t> PeekSint32LE() const
272 {
273 auto result = PeekUint32LE();
274 if (!result.has_value()) return std::nullopt;
275 return static_cast<int32_t>(*result);
276 }
280 [[nodiscard]] std::optional<int32_t> TryReadSint32LE()
281 {
282 auto value = this->PeekSint32LE();
283 if (value.has_value()) this->SkipSint32LE();
284 return value;
285 }
292 [[nodiscard]] int32_t ReadSint32LE(int32_t def = 0)
293 {
294 auto value = this->PeekSint32LE();
295 this->SkipSint32LE(); // always advance
296 return value.value_or(def);
297 }
302 void SkipSint32LE() { this->Skip(4); }
303
308 [[nodiscard]] std::optional<uint64_t> PeekUint64LE() const;
312 [[nodiscard]] std::optional<uint64_t> TryReadUint64LE()
313 {
314 auto value = this->PeekUint64LE();
315 if (value.has_value()) this->SkipUint64LE();
316 return value;
317 }
324 [[nodiscard]] uint64_t ReadUint64LE(uint64_t def = 0)
325 {
326 auto value = this->PeekUint64LE();
327 this->SkipUint64LE(); // always advance
328 return value.value_or(def);
329 }
334 void SkipUint64LE() { this->Skip(8); }
335
340 [[nodiscard]] std::optional<int64_t> PeekSint64LE() const
341 {
342 auto result = PeekUint64LE();
343 if (!result.has_value()) return std::nullopt;
344 return static_cast<int64_t>(*result);
345 }
349 [[nodiscard]] std::optional<int64_t> TryReadSint64LE()
350 {
351 auto value = this->PeekSint64LE();
352 if (value.has_value()) this->SkipSint64LE();
353 return value;
354 }
361 [[nodiscard]] int64_t ReadSint64LE(int64_t def = 0)
362 {
363 auto value = this->PeekSint64LE();
364 this->SkipSint64LE(); // always advance
365 return value.value_or(def);
366 }
371 void SkipSint64LE() { this->Skip(8); }
372
377 [[nodiscard]] std::optional<char> PeekChar() const;
381 [[nodiscard]] std::optional<char> TryReadChar()
382 {
383 auto value = this->PeekChar();
384 if (value.has_value()) this->SkipChar();
385 return value;
386 }
392 [[nodiscard]] char ReadChar(char def = '?') {
393 auto value = this->PeekChar();
394 this->SkipChar(); // always advance
395 return value.value_or(def);
396 }
400 void SkipChar() { this->Skip(1); }
401
406 [[nodiscard]] std::pair<size_type, char32_t> PeekUtf8() const;
410 [[nodiscard]] std::optional<char32_t> TryReadUtf8()
411 {
412 auto [len, value] = this->PeekUtf8();
413 if (len == 0) return std::nullopt;
414 this->Skip(len);
415 return value;
416 }
423 [[nodiscard]] char32_t ReadUtf8(char32_t def = '?')
424 {
425 auto [len, value] = this->PeekUtf8();
426 this->Skip(len > 0 ? len : 1); // advance at least one byte
427 return len > 0 ? value : def;
428 }
436 void SkipUtf8()
437 {
438 auto len = this->PeekUtf8().first;
439 this->Skip(len > 0 ? len : 1); // advance at least one byte
440 }
441
445 [[nodiscard]] bool PeekIf(std::string_view str) const
446 {
447 return this->src.compare(this->position, str.size(), str) == 0;
448 }
452 [[nodiscard]] bool ReadIf(std::string_view str)
453 {
454 bool result = this->PeekIf(str);
455 if (result) this->Skip(str.size());
456 return result;
457 }
461 void SkipIf(std::string_view str)
462 {
463 if (this->PeekIf(str)) this->Skip(str.size());
464 }
465
469 [[nodiscard]] bool PeekCharIf(char c) const
470 {
471 return this->PeekIf({&c, 1});
472 }
476 [[nodiscard]] bool ReadCharIf(char c)
477 {
478 return this->ReadIf({&c, 1});
479 }
483 void SkipCharIf(char c)
484 {
485 return this->SkipIf({&c, 1});
486 }
487
491 [[nodiscard]] bool PeekUtf8If(char32_t c) const
492 {
493 auto [len, result] = this->PeekUtf8();
494 return len > 0 && result == c;
495 }
499 [[nodiscard]] bool ReadUtf8If(char32_t c)
500 {
501 auto [len, result] = this->PeekUtf8();
502 if (len == 0 || result != c) return false;
503 this->Skip(len);
504 return true;
505 }
509 void SkipUtf8If(char32_t c)
510 {
511 auto [len, result] = this->PeekUtf8();
512 if (len > 0 && result == c) {
513 this->Skip(len);
514 }
515 }
516
522 [[nodiscard]] std::string_view Peek(size_type len) const;
528 [[nodiscard]] std::string_view Read(size_type len)
529 {
530 auto result = this->Peek(len);
531 if (len != npos && len != result.size()) {
532 LogError(fmt::format("Source buffer too short: {} > {}", len, result.size()));
533 }
534 this->Skip(result.size());
535 return result;
536 }
541 void Skip(size_type len);
542
547 [[nodiscard]] size_type Find(std::string_view str) const;
552 [[nodiscard]] size_type FindChar(char c) const
553 {
554 return this->Find({&c, 1});
555 }
560 [[nodiscard]] size_type FindUtf8(char32_t c) const;
561
566 [[nodiscard]] size_type FindCharIn(std::string_view chars) const;
571 [[nodiscard]] size_type FindCharNotIn(std::string_view chars) const;
572
577 [[nodiscard]] std::optional<char> PeekCharIfIn(std::string_view chars) const
578 {
579 assert(!chars.empty());
580 std::optional<char> c = this->PeekChar();
581 if (c.has_value() && chars.find(*c) != std::string_view::npos) return c;
582 return std::nullopt;
583 }
588 [[nodiscard]] std::optional<char> ReadCharIfIn(std::string_view chars)
589 {
590 auto result = this->PeekCharIfIn(chars);
591 if (result.has_value()) this->Skip(1);
592 return result;
593 }
597 void SkipCharIfIn(std::string_view chars)
598 {
599 auto result = this->PeekCharIfIn(chars);
600 if (result.has_value()) this->Skip(1);
601 }
602
607 [[nodiscard]] std::optional<char> PeekCharIfNotIn(std::string_view chars) const
608 {
609 assert(!chars.empty());
610 std::optional<char> c = this->PeekChar();
611 if (c.has_value() && chars.find(*c) == std::string_view::npos) return c;
612 return std::nullopt;
613 }
618 [[nodiscard]] std::optional<char> ReadCharIfNotIn(std::string_view chars)
619 {
620 auto result = this->PeekCharIfNotIn(chars);
621 if (result.has_value()) this->Skip(1);
622 return result;
623 }
627 void SkipCharIfNotIn(std::string_view chars)
628 {
629 auto result = this->PeekCharIfNotIn(chars);
630 if (result.has_value()) this->Skip(1);
631 }
632
637 [[nodiscard]] std::string_view PeekUntilCharIn(std::string_view chars) const
638 {
639 size_type len = this->FindCharIn(chars);
640 return this->Peek(len);
641 }
646 [[nodiscard]] std::string_view ReadUntilCharIn(std::string_view chars)
647 {
648 size_type len = this->FindCharIn(chars);
649 return this->Read(len);
650 }
654 void SkipUntilCharIn(std::string_view chars)
655 {
656 size_type len = this->FindCharIn(chars);
657 this->Skip(len);
658 }
659
664 [[nodiscard]] std::string_view PeekUntilCharNotIn(std::string_view chars) const
665 {
666 size_type len = this->FindCharNotIn(chars);
667 return this->Peek(len);
668 }
673 [[nodiscard]] std::string_view ReadUntilCharNotIn(std::string_view chars)
674 {
675 size_type len = this->FindCharNotIn(chars);
676 return this->Read(len);
677 }
681 void SkipUntilCharNotIn(std::string_view chars)
682 {
683 size_type len = this->FindCharNotIn(chars);
684 this->Skip(len);
685 }
686
697
703 [[nodiscard]] std::string_view PeekUntil(std::string_view str, SeparatorUsage sep) const;
709 [[nodiscard]] std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
710 {
711 assert(!str.empty());
712 auto result = this->PeekUntil(str, sep);
713 this->Skip(result.size());
714 switch (sep) {
715 default:
716 break;
718 this->SkipIf(str);
719 break;
721 while (this->ReadIf(str)) {}
722 break;
723 }
724 return result;
725 }
731 void SkipUntil(std::string_view str, SeparatorUsage sep)
732 {
733 assert(!str.empty());
734 this->Skip(this->Find(str));
735 switch (sep) {
736 default:
737 break;
740 this->SkipIf(str);
741 break;
744 while (this->ReadIf(str)) {}
745 break;
746 }
747 }
748
754 [[nodiscard]] std::string_view PeekUntilChar(char c, SeparatorUsage sep) const
755 {
756 return this->PeekUntil({&c, 1}, sep);
757 }
763 [[nodiscard]] std::string_view ReadUntilChar(char c, SeparatorUsage sep)
764 {
765 return this->ReadUntil({&c, 1}, sep);
766 }
773 {
774 this->SkipUntil({&c, 1}, sep);
775 }
776
782 [[nodiscard]] std::string_view PeekUntilUtf8(char32_t c, SeparatorUsage sep) const;
788 [[nodiscard]] std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep);
794 void SkipUntilUtf8(char32_t c, SeparatorUsage sep);
795
796private:
797 template <class T>
798 [[nodiscard]] static std::pair<size_type, T> ParseIntegerBase(std::string_view src, int base, bool clamp, bool log_errors)
799 {
800 if (base == 0) {
801 /* Try positive hex */
802 if (src.starts_with("0x") || src.starts_with("0X")) {
803 auto [len, value] = ParseIntegerBase<T>(src.substr(2), 16, clamp, log_errors);
804 if (len == 0) return {};
805 return {len + 2, value};
806 }
807
808 /* Try negative hex */
809 if (std::is_signed_v<T> && (src.starts_with("-0x") || src.starts_with("-0X"))) {
810 using Unsigned = std::make_unsigned_t<T>;
811 auto [len, uvalue] = ParseIntegerBase<Unsigned>(src.substr(3), 16, clamp, log_errors);
812 if (len == 0) return {};
813 T value = static_cast<T>(0 - uvalue);
814 if (value > 0) {
815 if (!clamp) {
816 if (log_errors) LogError(fmt::format("Integer out of range: '{}'", src.substr(0, len + 3)));
817 return {};
818 }
819 value = std::numeric_limits<T>::lowest();
820 }
821 return {len + 3, value};
822 }
823
824 /* Try decimal */
825 return ParseIntegerBase<T>(src, 10, clamp, log_errors);
826 }
827
828 T value{};
829 assert(base == 8 || base == 10 || base == 16); // we only support these bases when skipping
830 auto result = std::from_chars(src.data(), src.data() + src.size(), value, base);
831 auto len = result.ptr - src.data();
832 if (result.ec == std::errc::result_out_of_range) {
833 if (!clamp) {
834 if (log_errors) LogError(fmt::format("Integer out of range: '{}'+'{}'", src.substr(0, len), src.substr(len, 4)));
835 return {};
836 }
837 if (src.starts_with("-")) {
838 value = std::numeric_limits<T>::lowest();
839 } else {
840 value = std::numeric_limits<T>::max();
841 }
842 } else if (result.ec != std::errc{}) {
843 if (log_errors) LogError(fmt::format("Cannot parse integer: '{}'+'{}'", src.substr(0, len), src.substr(len, 4)));
844 return {};
845 }
846 return {len, value};
847 }
848
849public:
858 template <class T>
859 [[nodiscard]] std::pair<size_type, T> PeekIntegerBase(int base, bool clamp = false) const
860 {
861 return ParseIntegerBase<T>(this->src.substr(this->position), base, clamp, false);
862 }
871 template <class T>
872 [[nodiscard]] std::optional<T> TryReadIntegerBase(int base, bool clamp = false)
873 {
874 auto [len, value] = this->PeekIntegerBase<T>(base, clamp);
875 if (len == 0) return std::nullopt;
876 this->SkipIntegerBase(base);
877 return value;
878 }
888 template <class T>
889 [[nodiscard]] T ReadIntegerBase(int base, T def = 0, bool clamp = false)
890 {
891 auto [len, value] = ParseIntegerBase<T>(this->src.substr(this->position), base, clamp, true);
892 this->SkipIntegerBase(base); // always advance
893 return len > 0 ? value : def;
894 }
901 void SkipIntegerBase(int base);
902};
903
914template <class T = uint32_t>
915static inline std::optional<T> ParseInteger(std::string_view arg, int base = 10, bool clamp = false)
916{
917 StringConsumer consumer{arg};
919 auto result = consumer.TryReadIntegerBase<T>(base, clamp);
920 consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE);
921 if (consumer.AnyBytesLeft()) return std::nullopt;
922 return result;
923}
924
925#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.
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.
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.
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.
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.
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.