feat: build out Json

This commit is contained in:
dualfroz committed 2026-09-08 13:14:01 +02:00
1 parent 2c183a8071
commit 9be045c7da
1 file changed
+160
+160
View File
@@ -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<double>(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<double>(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<long long>(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<std::ptrdiff_t>(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;
}