7 #include <boost/variant.hpp>
14 #include <type_traits>
18 using std::string, std::optional, std::exception, std::unique_ptr, std::vector, std::any, std::make_shared;
19 namespace fs = std::filesystem;
21 using ptr = std::shared_ptr<T>;
27 #define JSON_BASE_TYPES std::nullptr_t, const char *, char *, bool, unsigned, int, long long, unsigned long long, string, float, double
29 struct JsonSerializableData : boost::variant<JSON_BASE_TYPES, vector<JsonSerializableData>, map<string, JsonSerializableData>> {
30 using Vector = vector<JsonSerializableData>;
31 using Map = map<string, JsonSerializableData>;
32 using Base = boost::variant<JSON_BASE_TYPES, Vector, Map>;
35 using Base::operator=;
40 string vectorToJson(
const vector<JsonSerializableData> &list,
bool noNewLines =
false);
41 string mapToJson(
const map<string, JsonSerializableData> &entries,
bool noNewLines =
false);
42 string pairsToJson(
const vector<pair<string, JsonSerializableData>> &entries,
bool noNewLines =
false);
45 template <
class TValue>
47 vector<JsonSerializableData> vectorCopy;
48 for (
auto entry : theVector) {
49 vectorCopy.push_back(entry);
54 template <
class TValue>
56 std::map<std::string, JsonSerializableData> mapCopy;
57 for (
auto entry : map) {
58 mapCopy[entry.first] = entry.second;
69 const char *
what()
const throw() {
70 return message.c_str();
83 ASSERT(
"given value is not numeric - " +
to_string(yyjson_get_type(jsonValue)), yyjson_get_type(jsonValue) == YYJSON_TYPE_NUM);
84 switch (yyjson_get_subtype(jsonValue)) {
85 case YYJSON_SUBTYPE_UINT:
86 return (T)yyjson_get_uint(jsonValue);
87 case YYJSON_SUBTYPE_SINT:
88 return (T)yyjson_get_sint(jsonValue);
90 case YYJSON_SUBTYPE_REAL:
91 return (T)yyjson_get_real(jsonValue);
107 bool hasKey(
const string &key);
112 bool isArray(
const string &key);
122 bool isNull(
const string &key);
234 optional<vector<T>> value = getArrayValue<T>(key);
235 if (!value.has_value()) {
239 return value.value();
250 }
catch (
const std::invalid_argument e) {
251 LOG_WARN(key +
" cannot be read as array: " +
string(e.what()));
261 optional<T> result = {};
264 if (value !=
nullptr) {
265 yyjson_val *itemValue = yyjson_arr_get(value,
index);
266 if (itemValue !=
nullptr) {
270 }
catch (
const std::invalid_argument e) {
271 LOG_WARN(
"cannot getArrayItemValue " + arrayKey +
" : " +
string(e.what()));
280 optional<T> value = getArrayItemValue<T>(arrayKey,
index);
281 if (!value.has_value()) {
285 return value.value();
334 const bool doNotReleaseYyjsonObjects;
336 optional<any> jsonValueToAny(yyjson_val *jsonValue);
340 if constexpr (std::is_arithmetic<T>::value) {
343 if constexpr (std::is_same<T, string>::value) {
344 const char *valueChars = yyjson_get_str(
yyjsonValue);
345 return string(valueChars);
347 if constexpr (std::is_same_v<T, const CscJsonObjectReader *> || std::is_same_v<T, CscJsonObjectReader *>) {
351 return std::make_shared<CscJsonObjectReader>(jsonDoc,
yyjsonValue,
true);
353 throw new std::invalid_argument(
354 "unsupported data type " +
string(
typeid(T).name()) +
" for array " +
359 static optional<vector<T>> toArrayValue(yyjson_val *arrayJsonValue,
ptr<yyjson_doc> jsonDoc) {
361 if (arrayJsonValue !=
nullptr && yyjson_get_type(arrayJsonValue) == YYJSON_TYPE_ARR) {
364 string ss =
string(yyjson_val_write(arrayJsonValue, YYJSON_WRITE_NOFLAG, NULL));
366 yyjson_val *arrayItem;
367 yyjson_arr_iter iter = yyjson_arr_iter_with(arrayJsonValue);
368 while ((arrayItem = yyjson_arr_iter_next(&iter))) {
369 items.push_back(toValue<T>(arrayItem, jsonDoc));
374 }
catch (
const std::invalid_argument e) {
375 LOG_WARN(
string(arrayJsonValue !=
nullptr ?
string(yyjson_get_raw(arrayJsonValue)) :
"?") +
" cannot be read as array: " +
string(e.what()));
404 CscJsonObject(yyjson_mut_doc *existingDoc, yyjson_mut_val *existingValue,
bool doNotReleaseYyjsonObjects =
false,
CscJsonObject *lookupParent =
nullptr);
455 CscJsonObject *
set(
const string &propertyPath,
const map<string, string> &value);
477 void saveToFile(
const fs::path &outPath,
bool lineBreakAndTabulation =
false);
525 bool doNotReleaseYyjsonObjects =
false;
570 void mergeObjects(yyjson_mut_val *thisObj, yyjson_mut_val *otherObj,
bool deep);
575 template <IsString T>
576 yyjson_mut_val *
toJsonValue(
const T &value, yyjson_mut_doc *doc) {
577 char *stringCopy = strdup(value.c_str());
578 return yyjson_mut_str(doc, stringCopy);
583 template <IsNotString T>
584 yyjson_mut_val *
toJsonValue(
const T &value, yyjson_mut_doc *doc);
586 inline yyjson_mut_val *
mapToJsonObject(
const map<string, string> &map, yyjson_mut_doc *doc) {
587 yyjson_mut_val *mapJsonValue = yyjson_mut_obj(doc);
589 for (
auto [key, value] : map) {
590 yyjson_mut_val *keyJsonValue =
toJsonValue(key, doc);
591 yyjson_mut_val *valueJsonValue =
toJsonValue(value, doc);
592 yyjson_mut_obj_put(mapJsonValue, keyJsonValue, valueJsonValue);
598 template <IsNotString T>
601 if constexpr (std::is_arithmetic<T>::value) {
602 if constexpr (std::is_unsigned<T>::value) {
603 return yyjson_mut_uint(doc, value);
604 }
else if constexpr (std::is_floating_point<T>::value) {
605 return yyjson_mut_real(doc, value);
607 return yyjson_mut_sint(doc, value);
610 }
else if constexpr (std::is_same_v<T, bool>) {
611 return yyjson_mut_bool(doc, value);
614 return yyjson_mut_val_mut_copy(doc, value->getLowLevelMutableObject());
616 }
else if constexpr (std::is_same_v<CscJsonObject, T>) {
617 return yyjson_mut_val_mut_copy(doc, value.getLowLevelMutableObject());
619 }
else if constexpr (std::is_same_v<CscJsonObject *, T> || std::is_same_v<const CscJsonObject *, T>) {
620 return yyjson_mut_val_mut_copy(doc, value->getLowLevelMutableObject());
622 }
else if constexpr (std::is_same_v<map<string, string>, T>) {
625 throw runtime_error(
"unsupported type ");
630 yyjson_mut_val *
toJsonValue(
const vector<T> &valueList, yyjson_mut_doc *doc,
bool clone =
false) {
631 yyjson_mut_val *arrayValue = yyjson_mut_arr(doc);
632 for (T value : valueList) {
633 yyjson_mut_val *jsonValue = toJsonValue<T>(value, doc);
634 yyjson_mut_val *newValue = jsonValue;
636 newValue = yyjson_mut_val_mut_copy(doc, jsonValue);
638 bool success = yyjson_mut_arr_append(arrayValue, newValue);
640 throw runtime_error(
"cannot add item to array");