Files
shweets-sim/src/json.h
T

120 lines
3.7 KiB
C++

#pragma once
#include "common.h"
#include <simdjson.h>
#include <string>
#include <vector>
using simdjson::dom::array;
using simdjson::dom::element;
using simdjson::dom::object;
// A document holding an empty object and array, standing in for whatever's missing so lookups never fail.
inline element json_empty_get(const char* key)
{
static simdjson::padded_string text(std::string_view(R"({"o":{},"a":[]})"));
static simdjson::dom::parser parser;
static element document = parser.parse(text).value_unsafe();
return document[key].value_unsafe();
}
// A parsed JSON file. Its objects stay readable while it lives.
struct Json
{
simdjson::dom::parser parser;
object root = json_empty_get("o").get_object().value_unsafe();
bool isValid = false;
void load(const std::string& path)
{
isValid = !parser.load(path).get(root);
if (!isValid)
SDL_Log("Failed to load %s", path.c_str());
}
};
inline float json_float(object source, const char* key, float fallback = 0)
{
double value;
return source[key].get(value) ? fallback : (float)value;
}
inline int json_int(object source, const char* key, int fallback = 0)
{
return (int)json_float(source, key, (float)fallback);
}
inline bool json_is(object source, const char* key, bool fallback = false)
{
bool value;
return source[key].get(value) ? fallback : value;
}
inline std::string json_string(object source, const char* key, const std::string& fallback = "")
{
std::string_view value;
return source[key].get(value) ? fallback : std::string(value);
}
inline object json_object(object source, const char* key)
{
object value;
return source[key].get(value) ? json_empty_get("o").get_object().value_unsafe() : value;
}
inline array json_array(object source, const char* key)
{
array value;
return source[key].get(value) ? json_empty_get("a").get_array().value_unsafe() : value;
}
// A list of numbers read into values, keeping each fallback where the list stops short.
inline void json_floats(object source, const char* key, float* values, int count)
{
array list = json_array(source, key);
for (int i = 0; i < count; i++)
{
double value;
if (!list.at(i).get(value))
values[i] = (float)value;
}
}
inline Vec2 json_vec2(object source, const char* key, Vec2 fallback = {})
{
json_floats(source, key, &fallback.x, 2);
return fallback;
}
// A color as a list of three or four numbers, scaled down by divisor.
inline Color json_color(object source, const char* key, Color fallback = WHITE, float divisor = 1)
{
Color value = {fallback.r * divisor, fallback.g * divisor, fallback.b * divisor, fallback.a * divisor};
json_floats(source, key, &value.r, 4);
return {value.r / divisor, value.g / divisor, value.b / divisor, value.a / divisor};
}
// A list of strings, or one string as a list of it.
inline std::vector<std::string> json_strings(object source, const char* key)
{
std::vector<std::string> values;
std::string_view single;
if (!source[key].get(single))
return {std::string(single)};
for (element entry : json_array(source, key))
{
std::string_view value;
if (!entry.get(value))
values.emplace_back(value);
}
return values;
}
// Logs any key of an object its reader doesn't know (likely a typo), naming where it is.
inline void json_keys_check(object source, std::initializer_list<const char*> keys, const std::string& where)
{
for (auto [key, value] : source)
if (std::find_if(keys.begin(), keys.end(), [&](const char* known) { return key == known; }) == keys.end())
SDL_Log("Unknown key \"%s\" in %s", std::string(key).c_str(), where.c_str());
}