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);
211 bool hasKey(
const string &key);
216 bool isArray(
const string &key);
264 bool isNull(
const string &key);
364 map<string, optional<any>>
asMap();
387 optional<vector<T>> value = getArrayValue<T>(key);
388 if (!value.has_value()) {
392 return value.value();
403 }
catch (
const std::invalid_argument e) {
404 LOG_WARN(key +
" cannot be read as array: " +
string(e.what()));
414 optional<T> result = {};
417 if (value !=
nullptr) {
418 yyjson_val *itemValue = yyjson_arr_get(value, index);
419 if (itemValue !=
nullptr) {
423 }
catch (
const std::invalid_argument e) {
424 LOG_WARN(
"cannot getArrayItemValue " + arrayKey +
" : " +
string(e.what()));
433 optional<T> value = getArrayItemValue<T>(arrayKey, index);
434 if (!value.has_value()) {
438 return value.value();
487 const bool doNotReleaseYyjsonObjects;
489 optional<any> jsonValueToAny(yyjson_val *jsonValue);
493 if constexpr (std::is_arithmetic<T>::value) {
496 if constexpr (std::is_same<T, string>::value) {
497 const char *valueChars = yyjson_get_str(
yyjsonValue);
498 return string(valueChars);
500 if constexpr (std::is_same_v<T, const CscJsonObjectReader *> || std::is_same_v<T, CscJsonObjectReader *>) {
504 return std::make_shared<CscJsonObjectReader>(jsonDoc,
yyjsonValue,
true);
506 throw new std::invalid_argument(
507 "unsupported data type " +
string(
typeid(T).name()) +
" for array " +
512 static optional<vector<T>> toArrayValue(yyjson_val *arrayJsonValue,
ptr<yyjson_doc> jsonDoc) {
514 if (arrayJsonValue !=
nullptr && yyjson_get_type(arrayJsonValue) == YYJSON_TYPE_ARR) {
517 string ss =
string(yyjson_val_write(arrayJsonValue, YYJSON_WRITE_NOFLAG, NULL));
519 yyjson_val *arrayItem;
520 yyjson_arr_iter iter = yyjson_arr_iter_with(arrayJsonValue);
521 while ((arrayItem = yyjson_arr_iter_next(&iter))) {
522 items.push_back(toValue<T>(arrayItem, jsonDoc));
527 }
catch (
const std::invalid_argument e) {
528 LOG_WARN(
string(arrayJsonValue !=
nullptr ?
string(yyjson_get_raw(arrayJsonValue)) :
"?") +
" cannot be read as array: " +
string(e.what()));
557 CscJsonObject(yyjson_mut_doc *existingDoc, yyjson_mut_val *existingValue,
bool doNotReleaseYyjsonObjects =
false,
CscJsonObject *lookupParent =
nullptr);
608 CscJsonObject *
set(
const string &propertyPath,
const map<string, string> &value);
630 void saveToFile(
const fs::path &outPath,
bool lineBreakAndTabulation =
false);
678 bool doNotReleaseYyjsonObjects =
false;
723 void mergeObjects(yyjson_mut_val *thisObj, yyjson_mut_val *otherObj,
bool deep);
728 template <IsString T>
729 yyjson_mut_val *
toJsonValue(
const T &value, yyjson_mut_doc *doc) {
730 char *stringCopy = strdup(value.c_str());
731 return yyjson_mut_str(doc, stringCopy);
736 template <IsNotString T>
737 yyjson_mut_val *
toJsonValue(
const T &value, yyjson_mut_doc *doc);
739 inline yyjson_mut_val *
mapToJsonObject(
const map<string, string> &map, yyjson_mut_doc *doc) {
740 yyjson_mut_val *mapJsonValue = yyjson_mut_obj(doc);
742 for (
auto [key, value] : map) {
743 yyjson_mut_val *keyJsonValue =
toJsonValue(key, doc);
744 yyjson_mut_val *valueJsonValue =
toJsonValue(value, doc);
745 yyjson_mut_obj_put(mapJsonValue, keyJsonValue, valueJsonValue);
751 template <IsNotString T>
754 if constexpr (std::is_arithmetic<T>::value) {
755 if constexpr (std::is_unsigned<T>::value) {
756 return yyjson_mut_uint(doc, value);
757 }
else if constexpr (std::is_floating_point<T>::value) {
758 return yyjson_mut_real(doc, value);
760 return yyjson_mut_sint(doc, value);
763 }
else if constexpr (std::is_same_v<T, bool>) {
764 return yyjson_mut_bool(doc, value);
767 return yyjson_mut_val_mut_copy(doc, value->getLowLevelMutableObject());
769 }
else if constexpr (std::is_same_v<CscJsonObject, T>) {
770 return yyjson_mut_val_mut_copy(doc, value.getLowLevelMutableObject());
772 }
else if constexpr (std::is_same_v<CscJsonObject *, T> || std::is_same_v<const CscJsonObject *, T>) {
773 return yyjson_mut_val_mut_copy(doc, value->getLowLevelMutableObject());
775 }
else if constexpr (std::is_same_v<map<string, string>, T>) {
778 throw runtime_error(
"unsupported type ");
783 yyjson_mut_val *
toJsonValue(
const vector<T> &valueList, yyjson_mut_doc *doc,
bool clone =
false) {
784 yyjson_mut_val *arrayValue = yyjson_mut_arr(doc);
785 for (T value : valueList) {
786 yyjson_mut_val *jsonValue = toJsonValue<T>(value, doc);
787 yyjson_mut_val *newValue = jsonValue;
789 newValue = yyjson_mut_val_mut_copy(doc, jsonValue);
791 bool success = yyjson_mut_arr_append(arrayValue, newValue);
793 throw runtime_error(
"cannot add item to array");