#pragma once #include "commons/commons_byteparser.h" #include "commons/commons_base.h" #include INLINE auto IsNumber(uint8_t ch) -> bool { return ch >= '0' && ch <= '9'; } INLINE auto IsAlpha(uint8_t ch) -> bool { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } INLINE auto IsWhitespace(uint8_t ch) -> bool { switch (ch) { case ' ': case '\n': case '\r': case '\t': return true; default: return false; } } INLINE void StringParser_SkipWhitespace(byte_parser& self) { while (IsWhitespace(ByteParser_Peek(self))) ByteParser_Advance(self); } enum StringParser_ParseNumberResult { Double, Long, }; inline auto StringParser_ParseDoubleFromBytes(const uint8_t* data, uint64_t size) -> double { char buf[1024]; ASSERT(size < sizeof(buf)); for (uint64_t i = 0; i < size; ++i) buf[i] = (char)data[i]; buf[size] = '\0'; return ::strtod(buf, nullptr); } inline auto StringParser_ParseDecimal(byte_parser& self, double& outDouble, int64_t& outLong) -> StringParser_ParseNumberResult { const uint8_t* start = self.at; bool negative = false; if (ByteParser_HasNext(self) && ByteParser_Peek(self) == '-') { negative = true; ByteParser_Advance(self); } uint64_t mantissa = 0; int32_t digitCount = 0; bool overflow = false; while (ByteParser_HasNext(self) && IsNumber(ByteParser_Peek(self))) { uint8_t digit = ByteParser_Read(self) - '0'; if (digitCount < 19) { mantissa = mantissa * 10 + digit; ++digitCount; } else { overflow = true; } } bool hasDot = false; if (ByteParser_HasNext(self) && ByteParser_Peek(self) == '.') { hasDot = true; ByteParser_Advance(self); while (ByteParser_HasNext(self) && IsNumber(ByteParser_Peek(self))) ByteParser_Advance(self); } bool hasExp = false; if (ByteParser_HasNext(self) && (ByteParser_Peek(self) == 'e' || ByteParser_Peek(self) == 'E')) { hasExp = true; ByteParser_Advance(self); if (ByteParser_HasNext(self) && (ByteParser_Peek(self) == '+' || ByteParser_Peek(self) == '-')) ByteParser_Advance(self); while (ByteParser_HasNext(self) && IsNumber(ByteParser_Peek(self))) ByteParser_Advance(self); } uint64_t int64AbsLimit; if (negative) int64AbsLimit = (uint64_t)INT64_MAX + 1; else int64AbsLimit = (uint64_t)INT64_MAX; if (hasDot || hasExp || overflow || mantissa > int64AbsLimit) { outDouble = StringParser_ParseDoubleFromBytes(start, (uint64_t)(self.at - start)); return StringParser_ParseNumberResult::Double; } else { if (negative) outLong = (int64_t)(0u - mantissa); else outLong = (int64_t)mantissa; return StringParser_ParseNumberResult::Long; } } INLINE auto StringParser_ParseLong(byte_parser& self) -> int64_t { double d; int64_t l; const StringParser_ParseNumberResult res = StringParser_ParseDecimal(self, d, l); ASSERT(res == StringParser_ParseNumberResult::Long); return l; }