12 #include <type_traits>
16 using std::string, std::optional, std::exception, std::unique_ptr, std::vector, std::any, std::make_shared;
17 namespace fs = std::filesystem;
19 using ptr = std::shared_ptr<T>;
25 #define JSON_BASE_TYPES std::nullptr_t, const char *, char *, bool, unsigned, int, long long, unsigned long long, string, float, double
27 struct JsonSerializableData;
29 using JsonArray = std::vector<JsonSerializableData>;
30 using JsonObject = std::map<std::string, JsonSerializableData>;
44 namespace typing_helper {
50 std::is_same_v<decay_t<T>, std::nullptr_t> ||
51 std::is_same_v<decay_t<T>,
const char*> ||
52 std::is_same_v<decay_t<T>,
char*> ||
53 std::is_same_v<decay_t<T>,
bool> ||
54 std::is_same_v<decay_t<T>,
unsigned> ||
55 std::is_same_v<decay_t<T>,
int> ||
56 std::is_same_v<decay_t<T>,
long long> ||
57 std::is_same_v<decay_t<T>,
unsigned long long> ||
58 std::is_same_v<decay_t<T>, std::string> ||
59 std::is_same_v<decay_t<T>,
float> ||
60 std::is_same_v<decay_t<T>,
double>;
65 std::is_same_v<decay_t<T>, JsonObject::value_type> ||
85 using U = std::underlying_type_t<typing_helper::decay_t<E>>;
86 if constexpr (std::is_signed_v<U>) {
87 value =
static_cast<long long>(
static_cast<U
>(e));
89 value =
static_cast<unsigned long long>(
static_cast<U
>(e));
96 typing_helper::is_scalar_json_v<T> &&
97 !typing_helper::excluded_v<T>)
133 string vectorToJson(
const vector<JsonSerializableData> &list,
bool noNewLines =
false);
135 std::initializer_list<JsonObject::value_type> init,
136 bool noNewLines =
false);
137 string mapToJson(
const map<string, JsonSerializableData> &entries,
bool noNewLines =
false);
138 string pairsToJson(
const vector<pair<string, JsonSerializableData>> &entries,
bool noNewLines =
false);
141 template <
class TValue>
144 out.reserve(theVector.size());
145 for (
const auto &v : theVector) {
146 out.emplace_back(
static_cast<TValue
>(v));
151 inline map<string, JsonSerializableData>
153 std::initializer_list<map<string, JsonSerializableData>::value_type> init) {
154 return map<string, JsonSerializableData>(init);
157 template <
class TValue>
159 map<string, JsonSerializableData> mapCopy;
160 for (
auto entry : theMap) {
161 mapCopy[entry.first] = entry.second;
172 const char *
what()
const throw() {
173 return message.c_str();
181 const string message;
186 ASSERT(
"given value is not numeric - " +
to_string(yyjson_get_type(jsonValue)), yyjson_get_type(jsonValue) == YYJSON_TYPE_NUM);
187 switch (yyjson_get_subtype(jsonValue)) {
188 case YYJSON_SUBTYPE_UINT:
189 return (T)yyjson_get_uint(jsonValue);
190 case YYJSON_SUBTYPE_SINT:
191 return (T)yyjson_get_sint(jsonValue);
193 case YYJSON_SUBTYPE_REAL:
194 return (T)yyjson_get_real(jsonValue);
210 bool hasKey(
const string &key);
215 bool isArray(
const string &key);
225 bool isNull(
const string &key);
337 optional<vector<T>> value = getArrayValue<T>(key);
338 if (!value.has_value()) {
342 return value.value();
353 }
catch (
const std::invalid_argument e) {
354 LOG_WARN(key +
" cannot be read as array: " +
string(e.what()));
364 optional<T> result = {};
367 if (value !=
nullptr) {
368 yyjson_val *itemValue = yyjson_arr_get(value,
index);
369 if (itemValue !=
nullptr) {
373 }
catch (
const std::invalid_argument e) {
374 LOG_WARN(
"cannot getArrayItemValue " + arrayKey +
" : " +
string(e.what()));
383 optional<T> value = getArrayItemValue<T>(arrayKey,
index);
384 if (!value.has_value()) {
388 return value.value();
437 const bool doNotReleaseYyjsonObjects;
439 optional<any> jsonValueToAny(yyjson_val *jsonValue);
443 if constexpr (std::is_arithmetic<T>::value) {
446 if constexpr (std::is_same<T, string>::value) {
447 const char *valueChars = yyjson_get_str(
yyjsonValue);
448 return string(valueChars);
450 if constexpr (std::is_same_v<T, const CscJsonObjectReader *> || std::is_same_v<T, CscJsonObjectReader *>) {
454 return std::make_shared<CscJsonObjectReader>(jsonDoc,
yyjsonValue,
true);
456 throw new std::invalid_argument(
457 "unsupported data type " +
string(
typeid(T).name()) +
" for array " +
462 static optional<vector<T>> toArrayValue(yyjson_val *arrayJsonValue,
ptr<yyjson_doc> jsonDoc) {
464 if (arrayJsonValue !=
nullptr && yyjson_get_type(arrayJsonValue) == YYJSON_TYPE_ARR) {
467 string ss =
string(yyjson_val_write(arrayJsonValue, YYJSON_WRITE_NOFLAG, NULL));
469 yyjson_val *arrayItem;
470 yyjson_arr_iter iter = yyjson_arr_iter_with(arrayJsonValue);
471 while ((arrayItem = yyjson_arr_iter_next(&iter))) {
472 items.push_back(toValue<T>(arrayItem, jsonDoc));
477 }
catch (
const std::invalid_argument e) {
478 LOG_WARN(
string(arrayJsonValue !=
nullptr ?
string(yyjson_get_raw(arrayJsonValue)) :
"?") +
" cannot be read as array: " +
string(e.what()));
507 CscJsonObject(yyjson_mut_doc *existingDoc, yyjson_mut_val *existingValue,
bool doNotReleaseYyjsonObjects =
false,
CscJsonObject *lookupParent =
nullptr);
558 CscJsonObject *
set(
const string &propertyPath,
const map<string, string> &value);
580 void saveToFile(
const fs::path &outPath,
bool lineBreakAndTabulation =
false);
628 bool doNotReleaseYyjsonObjects =
false;
673 void mergeObjects(yyjson_mut_val *thisObj, yyjson_mut_val *otherObj,
bool deep);
678 template <IsString T>
679 yyjson_mut_val *
toJsonValue(
const T &value, yyjson_mut_doc *doc) {
680 char *stringCopy = strdup(value.c_str());
681 return yyjson_mut_str(doc, stringCopy);
686 template <IsNotString T>
687 yyjson_mut_val *
toJsonValue(
const T &value, yyjson_mut_doc *doc);
689 inline yyjson_mut_val *
mapToJsonObject(
const map<string, string> &map, yyjson_mut_doc *doc) {
690 yyjson_mut_val *mapJsonValue = yyjson_mut_obj(doc);
692 for (
auto [key, value] : map) {
693 yyjson_mut_val *keyJsonValue =
toJsonValue(key, doc);
694 yyjson_mut_val *valueJsonValue =
toJsonValue(value, doc);
695 yyjson_mut_obj_put(mapJsonValue, keyJsonValue, valueJsonValue);
701 template <IsNotString T>
704 if constexpr (std::is_arithmetic<T>::value) {
705 if constexpr (std::is_unsigned<T>::value) {
706 return yyjson_mut_uint(doc, value);
707 }
else if constexpr (std::is_floating_point<T>::value) {
708 return yyjson_mut_real(doc, value);
710 return yyjson_mut_sint(doc, value);
713 }
else if constexpr (std::is_same_v<T, bool>) {
714 return yyjson_mut_bool(doc, value);
717 return yyjson_mut_val_mut_copy(doc, value->getLowLevelMutableObject());
719 }
else if constexpr (std::is_same_v<CscJsonObject, T>) {
720 return yyjson_mut_val_mut_copy(doc, value.getLowLevelMutableObject());
722 }
else if constexpr (std::is_same_v<CscJsonObject *, T> || std::is_same_v<const CscJsonObject *, T>) {
723 return yyjson_mut_val_mut_copy(doc, value->getLowLevelMutableObject());
725 }
else if constexpr (std::is_same_v<map<string, string>, T>) {
728 throw runtime_error(
"unsupported type ");
733 yyjson_mut_val *
toJsonValue(
const vector<T> &valueList, yyjson_mut_doc *doc,
bool clone =
false) {
734 yyjson_mut_val *arrayValue = yyjson_mut_arr(doc);
735 for (T value : valueList) {
736 yyjson_mut_val *jsonValue = toJsonValue<T>(value, doc);
737 yyjson_mut_val *newValue = jsonValue;
739 newValue = yyjson_mut_val_mut_copy(doc, jsonValue);
741 bool success = yyjson_mut_arr_append(arrayValue, newValue);
743 throw runtime_error(
"cannot add item to array");