From 9be045c7da5d2985d54ba536f1bcbbc85710c4d5 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 13:14:01 +0200 Subject: [PATCH] feat: build out Json --- core/src/Json.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/core/src/Json.cpp b/core/src/Json.cpp index a4bd20c..1553af0 100644 --- a/core/src/Json.cpp +++ b/core/src/Json.cpp @@ -468,3 +468,163 @@ private: } }; +std::string formatNumber(const JsonValue& value) { + if (value.isInteger()) return std::to_string(value.intValue()); + double raw = value.numberValue(); + if (!std::isfinite(raw)) return "0"; + char buffer[48]; + for (int precision = 15; precision <= 17; ++precision) { + std::snprintf(buffer, sizeof buffer, "%.*g", precision, raw); + if (std::strtod(buffer, nullptr) == raw) break; + } + std::string text(buffer); + // A double that prints without a fraction would come back as an integer and + // print differently the next time round, so the writer keeps it a double. + if (text.find_first_of(".eE") == std::string::npos) text += ".0"; + return text; +} + +} // namespace + +JsonValue JsonValue::makeNull() { return JsonValue(); } + +JsonValue JsonValue::makeBool(bool value) { + JsonValue made; + made.type = JsonType::Bool; + made.boolPayload = value; + return made; +} + +JsonValue JsonValue::makeNumber(double value) { + JsonValue made; + made.type = JsonType::Number; + made.numberPayload = value; + return made; +} + +JsonValue JsonValue::makeInt(long long value) { + JsonValue made; + made.type = JsonType::Number; + made.integral = true; + made.integerPayload = value; + made.numberPayload = static_cast(value); + return made; +} + +JsonValue JsonValue::makeString(std::string value) { + JsonValue made; + made.type = JsonType::String; + made.stringPayload = std::move(value); + return made; +} + +JsonValue JsonValue::makeArray() { + JsonValue made; + made.type = JsonType::Array; + return made; +} + +JsonValue JsonValue::makeObject() { + JsonValue made; + made.type = JsonType::Object; + return made; +} + +double JsonValue::numberValue() const { + if (type != JsonType::Number) return 0.0; + return integral ? static_cast(integerPayload) : numberPayload; +} + +long long JsonValue::intValue() const { + if (type != JsonType::Number) return 0; + if (integral) return integerPayload; + double rounded = numberPayload < 0.0 ? std::ceil(numberPayload - 0.5) + : std::floor(numberPayload + 0.5); + if (rounded >= 9223372036854775296.0) return 9223372036854775807ll; + if (rounded <= -9223372036854775296.0) return -9223372036854775807ll - 1ll; + return static_cast(rounded); +} + +std::size_t JsonValue::size() const { + if (type == JsonType::Array) return arrayPayload.size(); + if (type == JsonType::Object) return objectPayload.size(); + return 0u; +} + +void JsonValue::push(JsonValue value) { + if (type != JsonType::Array) { + *this = makeArray(); + } + arrayPayload.push_back(std::move(value)); +} + +void JsonValue::set(const std::string& key, JsonValue value) { + if (type != JsonType::Object) { + *this = makeObject(); + } + for (Member& member : objectPayload) { + if (member.first == key) { + member.second = std::move(value); + return; + } + } + objectPayload.emplace_back(key, std::move(value)); +} + +bool JsonValue::erase(const std::string& key) { + for (std::size_t i = 0u; i < objectPayload.size(); ++i) { + if (objectPayload[i].first == key) { + objectPayload.erase(objectPayload.begin() + static_cast(i)); + return true; + } + } + return false; +} + +const JsonValue* JsonValue::find(const std::string& key) const { + for (const Member& member : objectPayload) + if (member.first == key) return &member.second; + return nullptr; +} + +JsonValue* JsonValue::find(const std::string& key) { + for (Member& member : objectPayload) + if (member.first == key) return &member.second; + return nullptr; +} + +const JsonValue* JsonValue::at(std::size_t index) const { + if (type != JsonType::Array || index >= arrayPayload.size()) return nullptr; + return &arrayPayload[index]; +} + +bool JsonValue::boolOr(bool fallback) const { return isBool() ? boolPayload : fallback; } + +double JsonValue::numberOr(double fallback) const { return isNumber() ? numberValue() : fallback; } + +long long JsonValue::intOr(long long fallback) const { return isNumber() ? intValue() : fallback; } + +std::string JsonValue::stringOr(const std::string& fallback) const { + return isString() ? stringPayload : fallback; +} + +bool JsonValue::boolOr(const std::string& key, bool fallback) const { + const JsonValue* member = find(key); + return member ? member->boolOr(fallback) : fallback; +} + +double JsonValue::numberOr(const std::string& key, double fallback) const { + const JsonValue* member = find(key); + return member ? member->numberOr(fallback) : fallback; +} + +long long JsonValue::intOr(const std::string& key, long long fallback) const { + const JsonValue* member = find(key); + return member ? member->intOr(fallback) : fallback; +} + +std::string JsonValue::stringOr(const std::string& key, const std::string& fallback) const { + const JsonValue* member = find(key); + return member ? member->stringOr(fallback) : fallback; +} +