OpenTTD Source 20250529-master-g10c159a79f
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 <http://www.gnu.org/licenses/>.
6 */
7
12#ifndef STRING_CONSUMER_HPP
13#define STRING_CONSUMER_HPP
14
15#include <charconv>
16#include "format.hpp"
17
28public:
29 using size_type = std::string_view::size_type;
30
34 static constexpr size_type npos = std::string_view::npos;
35
40 static const std::string_view WHITESPACE_NO_NEWLINE;
45 static const std::string_view WHITESPACE_OR_NEWLINE;
46
47private:
48 std::string_view src;
49 size_type position = 0;
50
51 static void LogError(std::string &&msg);
52
53public:
57 explicit StringConsumer(std::string_view src) : src(src) {}
61 explicit StringConsumer(const std::string &src) : src(src) {}
65 explicit StringConsumer(std::span<const char> src) : src(src.data(), src.size()) {}
66
70 [[nodiscard]] bool AnyBytesLeft() const noexcept { return this->position < this->src.size(); }
74 [[nodiscard]] size_type GetBytesLeft() const noexcept { return this->src.size() - this->position; }
75
79 [[nodiscard]] bool AnyBytesRead() const noexcept { return this->position > 0; }
83 [[nodiscard]] size_type GetBytesRead() const noexcept { return this->position; }
84
88 [[nodiscard]] std::string_view GetOrigData() const noexcept { return this->src; }
92 [[nodiscard]] std::string_view GetReadData() const noexcept { return this->src.substr(0, this->position); }
96 [[nodiscard]] std::string_view GetLeftData() const noexcept { return this->src.substr(this->position); }
97
101 void SkipAll() { this->position = this->src.size(); }
102
107 [[nodiscard]] std::optional<uint8_t> PeekUint8() const;
111 [[nodiscard]] std::optional<uint8_t> TryReadUint8()
112 {
113 auto value = this->PeekUint8();
114 if (value.has_value()) this->SkipUint8();
115 return value;
116 }
122 [[nodiscard]] uint8_t ReadUint8(uint8_t def = 0)
123 {
124 auto value = this->PeekUint8();
125 this->SkipUint8(); // always advance
126 return value.value_or(def);
127 }
131 void SkipUint8() { this->Skip(1); }
132
137 [[nodiscard]] std::optional<int8_t> PeekSint8() const
138 {
139 auto result = PeekUint8();
140 if (!result.has_value()) return std::nullopt;
141 return static_cast<int8_t>(*result);
142 }
146 [[nodiscard]] std::optional<int8_t> TryReadSint8()
147 {
148 auto value = this->PeekSint8();
149 if (value.has_value()) this->SkipSint8();
150 return value;
151 }
157 [[nodiscard]] int8_t ReadSint8(int8_t def = 0)
158 {
159 auto value = this->PeekSint8();
160 this->SkipSint8(); // always advance
161 return value.value_or(def);
162 }
166 void SkipSint8() { this->Skip(1); }
167
172 [[nodiscard]] std::optional<uint16_t> PeekUint16LE() const;
176 [[nodiscard]] std::optional<uint16_t> TryReadUint16LE()
177 {
178 auto value = this->PeekUint16LE();
179 if (value.has_value()) this->SkipUint16LE();
180 return value;
181 }
188 [[nodiscard]] uint16_t ReadUint16LE(uint16_t def = 0)
189 {
190 auto value = this->PeekUint16LE();
191 this->SkipUint16LE(); // always advance
192 return value.value_or(def);
193 }
198 void SkipUint16LE() { this->Skip(2); }
199
204 [[nodiscard]] std::optional<int16_t> PeekSint16LE() const
205 {
206 auto result = PeekUint16LE();
207 if (!result.has_value()) return std::nullopt;
208 return static_cast<int16_t>(*result);
209 }
213 [[nodiscard]] std::optional<int16_t> TryReadSint16LE()
214 {
215 auto value = this->PeekSint16LE();
216 if (value.has_value()) this->SkipSint16LE();
217 return value;
218 }
225 [[nodiscard]] int16_t ReadSint16LE(int16_t def = 0)
226 {
227 auto value = this->PeekSint16LE();
228 this->SkipSint16LE(); // always advance
229 return value.value_or(def);
230 }
235 void SkipSint16LE() { this->Skip(2); }
236
241 [[nodiscard]] std::optional<uint32_t> PeekUint32LE() const;
245 [[nodiscard]] std::optional<uint32_t> TryReadUint32LE()
246 {
247 auto value = this->PeekUint32LE();
248 if (value.has_value()) this->SkipUint32LE();
249 return value;
250 }
257 [[nodiscard]] uint32_t ReadUint32LE(uint32_t def = 0)
258 {
259 auto value = this->PeekUint32LE();
260 this->SkipUint32LE(); // always advance
261 return value.value_or(def);
262 }
267 void SkipUint32LE() { this->Skip(4); }
268
273 [[nodiscard]] std::optional<int32_t> PeekSint32LE() const
274 {
275 auto result = PeekUint32LE();
276 if (!result.has_value()) return std::nullopt;
277 return static_cast<int32_t>(*result);
278 }
282 [[nodiscard]] std::optional<int32_t> TryReadSint32LE()
283 {
284 auto value = this->PeekSint32LE();
285 if (value.has_value()) this->SkipSint32LE();
286 return value;
287 }
294 [[nodiscard]] int32_t ReadSint32LE(int32_t def = 0)
295 {
296 auto value = this->PeekSint32LE();
297 this->SkipSint32LE(); // always advance
298 return value.value_or(def);
299 }
304 void SkipSint32LE() { this->Skip(4); }
305
310 [[nodiscard]] std::optional<uint64_t> PeekUint64LE() const;
314 [[nodiscard]] std::optional<uint64_t> TryReadUint64LE()
315 {
316 auto value = this->PeekUint64LE();
317 if (value.has_value()) this->SkipUint64LE();
318 return value;
319 }
326 [[nodiscard]] uint64_t ReadUint64LE(uint64_t def = 0)
327 {
328 auto value = this->PeekUint64LE();
329 this->SkipUint64LE(); // always advance
330 return value.value_or(def);
331 }
336 void SkipUint64LE() { this->Skip(8); }
337
342 [[nodiscard]] std::optional<int64_t> PeekSint64LE() const
343 {
344 auto result = PeekUint64LE();
345 if (!result.has_value()) return std::nullopt;
346 return static_cast<int64_t>(*result);
347 }
351 [[nodiscard]] std::optional<int64_t> TryReadSint64LE()
352 {
353 auto value = this->PeekSint64LE();
354 if (value.has_value()) this->SkipSint64LE();
355 return value;
356 }
363 [[nodiscard]] int64_t ReadSint64LE(int64_t def = 0)
364 {
365 auto value = this->PeekSint64LE();
366 this->SkipSint64LE(); // always advance
367 return value.value_or(def);
368 }
373 void SkipSint64LE() { this->Skip(8); }
374
379 [[nodiscard]] std::optional<char> PeekChar() const;
383 [[nodiscard]] std::optional<char> TryReadChar()
384 {
385 auto value = this->PeekChar();
386 if (value.has_value()) this->SkipChar();
387 return value;
388 }
394 [[nodiscard]] char ReadChar(char def = '?') {
395 auto value = this->PeekChar();
396 this->SkipChar(); // always advance
397 return value.value_or(def);
398 }
402 void SkipChar() { this->Skip(1); }
403
408 [[nodiscard]] std::pair<size_type, char32_t> PeekUtf8() const;
412 [[nodiscard]] std::optional<char32_t> TryReadUtf8()
413 {
414 auto [len, value] = this->PeekUtf8();
415 if (len == 0) return std::nullopt;
416 this->Skip(len);
417 return value;
418 }
425 [[nodiscard]] char32_t ReadUtf8(char32_t def = '?')
426 {
427 auto [len, value] = this->PeekUtf8();
428 this->Skip(len > 0 ? len : 1); // advance at least one byte
429 return len > 0 ? value : def;
430 }
438 void SkipUtf8()
439 {
440 auto len = this->PeekUtf8().first;
441 this->Skip(len > 0 ? len : 1); // advance at least one byte
442 }
443
447 [[nodiscard]] bool PeekIf(std::string_view str) const
448 {
449 return this->src.compare(this->position, str.size(), str) == 0;
450 }
454 [[nodiscard]] bool ReadIf(std::string_view str)
455 {
456 bool result = this->PeekIf(str);
457 if (result) this->Skip(str.size());
458 return result;
459 }
463 void SkipIf(std::string_view str)
464 {
465 if (this->PeekIf(str)) this->Skip(str.size());
466 }
467
471 [[nodiscard]] bool PeekCharIf(char c) const
472 {
473 return this->PeekIf({&c, 1});
474 }
478 [[nodiscard]] bool ReadCharIf(char c)
479 {
480 return this->ReadIf({&c, 1});
481 }
485 void SkipCharIf(char c)
486 {
487 return this->SkipIf({&c, 1});
488 }
489
493 [[nodiscard]] bool PeekUtf8If(char32_t c) const
494 {
495 auto [len, result] = this->PeekUtf8();
496 return len > 0 && result == c;
497 }
501 [[nodiscard]] bool ReadUtf8If(char32_t c)
502 {
503 auto [len, result] = this->PeekUtf8();
504 if (len == 0 || result != c) return false;
505 this->Skip(len);
506 return true;
507 }
511 void SkipUtf8If(char32_t c)
512 {
513 auto [len, result] = this->PeekUtf8();
514 if (len > 0 && result == c) {
515 this->Skip(len);
516 }
517 }
518
524 [[nodiscard]] std::string_view Peek(size_type len) const;
530 [[nodiscard]] std::string_view Read(size_type len)
531 {
532 auto result = this->Peek(len);
533 if (len != npos && len != result.size()) {
534 LogError(fmt::format("Source buffer too short: {} > {}", len, result.size()));
535 }
536 this->Skip(result.size());
537 return result;
538 }
543 void Skip(size_type len);
544
549 [[nodiscard]] size_type Find(std::string_view str) const;
554 [[nodiscard]] size_type FindChar(char c) const
555 {
556 return this->Find({&c, 1});
557 }
562 [[nodiscard]] size_type FindUtf8(char32_t c) const;
563
568 [[nodiscard]] size_type FindCharIn(std::string_view chars) const;
573 [[nodiscard]] size_type FindCharNotIn(std::string_view chars) const;
574
579 [[nodiscard]] std::optional<char> PeekCharIfIn(std::string_view chars) const
580 {
581 assert(!chars.empty());
582 std::optional<char> c = this->PeekChar();
583 if (c.has_value() && chars.find(*c) != std::string_view::npos) return c;
584 return std::nullopt;
585 }
590 [[nodiscard]] std::optional<char> ReadCharIfIn(std::string_view chars)
591 {
592 auto result = this->PeekCharIfIn(chars);
593 if (result.has_value()) this->Skip(1);
594 return result;
595 }
599 void SkipCharIfIn(std::string_view chars)
600 {
601 auto result = this->PeekCharIfIn(chars);
602 if (result.has_value()) this->Skip(1);
603 }
604
609 [[nodiscard]] std::optional<char> PeekCharIfNotIn(std::string_view chars) const
610 {
611 assert(!chars.empty());
612 std::optional<char> c = this->PeekChar();
613 if (c.has_value() && chars.find(*c) == std::string_view::npos) return c;
614 return std::nullopt;
615 }
620 [[nodiscard]] std::optional<char> ReadCharIfNotIn(std::string_view chars)
621 {
622 auto result = this->PeekCharIfNotIn(chars);
623 if (result.has_value()) this->Skip(1);
624 return result;
625 }
629 void SkipCharIfNotIn(std::string_view chars)
630 {
631 auto result = this->PeekCharIfNotIn(chars);
632 if (result.has_value()) this->Skip(1);
633 }
634
639 [[nodiscard]] std::string_view PeekUntilCharIn(std::string_view chars) const
640 {
641 size_type len = this->FindCharIn(chars);
642 return this->Peek(len);
643 }
648 [[nodiscard]] std::string_view ReadUntilCharIn(std::string_view chars)
649 {
650 size_type len = this->FindCharIn(chars);
651 return this->Read(len);
652 }
656 void SkipUntilCharIn(std::string_view chars)
657 {
658 size_type len = this->FindCharIn(chars);
659 this->Skip(len);
660 }
661
666 [[nodiscard]] std::string_view PeekUntilCharNotIn(std::string_view chars) const
667 {
668 size_type len = this->FindCharNotIn(chars);
669 return this->Peek(len);
670 }
675 [[nodiscard]] std::string_view ReadUntilCharNotIn(std::string_view chars)
676 {
677 size_type len = this->FindCharNotIn(chars);
678 return this->Read(len);
679 }
683 void SkipUntilCharNotIn(std::string_view chars)
684 {
685 size_type len = this->FindCharNotIn(chars);
686 this->Skip(len);
687 }
688
699
705 [[nodiscard]] std::string_view PeekUntil(std::string_view str, SeparatorUsage sep) const;
711 [[nodiscard]] std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
712 {
713 assert(!str.empty());
714 auto result = this->PeekUntil(str, sep);
715 this->Skip(result.size());
716 switch (sep) {
717 default:
718 break;
720 this->SkipIf(str);
721 break;
723 while (this->ReadIf(str)) {}
724 break;
725 }
726 return result;
727 }
733 void SkipUntil(std::string_view str, SeparatorUsage sep)
734 {
735 assert(!str.empty());
736 this->Skip(this->Find(str));
737 switch (sep) {
738 default:
739 break;
742 this->SkipIf(str);
743 break;
746 while (this->ReadIf(str)) {}
747 break;
748 }
749 }
750
756 [[nodiscard]] std::string_view PeekUntilChar(char c, SeparatorUsage sep) const
757 {
758 return this->PeekUntil({&c, 1}, sep);
759 }
765 [[nodiscard]] std::string_view ReadUntilChar(char c, SeparatorUsage sep)
766 {
767 return this->ReadUntil({&c, 1}, sep);
768 }
775 {
776 this->SkipUntil({&c, 1}, sep);
777 }
778
784 [[nodiscard]] std::string_view PeekUntilUtf8(char32_t c, SeparatorUsage sep) const;
790 [[nodiscard]] std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep);
796 void SkipUntilUtf8(char32_t c, SeparatorUsage sep);
797
798private:
799 template <class T>
800 [[nodiscard]] static std::pair<size_type, T> ParseIntegerBase(std::string_view src, int base, bool clamp, bool log_errors)
801 {
802 if (base == 0) {
803 /* Try positive hex */
804 if (src.starts_with("0x") || src.starts_with("0X")) {
805 auto [len, value] = ParseIntegerBase<T>(src.substr(2), 16, clamp, log_errors);
806 if (len == 0) return {};
807 return {len + 2, value};
808 }
809
810 /* Try negative hex */
811 if (std::is_signed_v<T> && (src.starts_with("-0x") || src.starts_with("-0X"))) {
812 using Unsigned = std::make_unsigned_t<T>;
813 auto [len, uvalue] = ParseIntegerBase<Unsigned>(src.substr(3), 16, clamp, log_errors);
814 if (len == 0) return {};
815 T value = static_cast<T>(0 - uvalue);
816 if (value > 0) {
817 if (!clamp) {
818 if (log_errors) LogError(fmt::format("Integer out of range: '{}'", src.substr(0, len + 3)));
819 return {};
820 }
821 value = std::numeric_limits<T>::lowest();
822 }
823 return {len + 3, value};
824 }
825
826 /* Try decimal */
827 return ParseIntegerBase<T>(src, 10, clamp, log_errors);
828 }
829
830 T value{};
831 assert(base == 8 || base == 10 || base == 16); // we only support these bases when skipping
832 auto result = std::from_chars(src.data(), src.data() + src.size(), value, base);
833 auto len = result.ptr - src.data();
834 if (result.ec == std::errc::result_out_of_range) {
835 if (!clamp) {
836 if (log_errors) LogError(fmt::format("Integer out of range: '{}'+'{}'", src.substr(0, len), src.substr(len, 4)));
837 return {};
838 }
839 if (src.starts_with("-")) {
840 value = std::numeric_limits<T>::lowest();
841 } else {
842 value = std::numeric_limits<T>::max();
843 }
844 } else if (result.ec != std::errc{}) {
845 if (log_errors) LogError(fmt::format("Cannot parse integer: '{}'+'{}'", src.substr(0, len), src.substr(len, 4)));
846 return {};
847 }
848 return {len, value};
849 }
850
851public:
860 template <class T>
861 [[nodiscard]] std::pair<size_type, T> PeekIntegerBase(int base, bool clamp = false) const
862 {
863 return ParseIntegerBase<T>(this->src.substr(this->position), base, clamp, false);
864 }
873 template <class T>
874 [[nodiscard]] std::optional<T> TryReadIntegerBase(int base, bool clamp = false)
875 {
876 auto [len, value] = this->PeekIntegerBase<T>(base, clamp);
877 if (len == 0) return std::nullopt;
878 this->SkipIntegerBase(base);
879 return value;
880 }
890 template <class T>
891 [[nodiscard]] T ReadIntegerBase(int base, T def = 0, bool clamp = false)
892 {
893 auto [len, value] = ParseIntegerBase<T>(this->src.substr(this->position), base, clamp, true);
894 this->SkipIntegerBase(base); // always advance
895 return len > 0 ? value : def;
896 }
903 void SkipIntegerBase(int base);
904};
905
916template <class T = uint32_t>
917static inline std::optional<T> ParseInteger(std::string_view arg, int base = 10, bool clamp = false)
918{
919 StringConsumer consumer{arg};
921 auto result = consumer.TryReadIntegerBase<T>(base, clamp);
922 consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE);
923 if (consumer.AnyBytesLeft()) return std::nullopt;
924 return result;
925}
926
927#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 occurence 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 wheter 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 occurence 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 occurence 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 occurence 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 occurence 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.