feat: build out Json
This commit is contained in:
1 parent
2c183a8071
commit
9be045c7da
1 file changed
+160
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user