From c0146c3de6297156038a1778a8fe58f2cf5cdc18 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Thu, 17 Jul 2025 22:13:08 +0000 Subject: [PATCH 1/3] :art: Committing clang-format changes --- include/json2cpp/json2cpp.hpp | 258 +++++++++++++++++----------------- src/json2cpp.cpp | 174 ++++++++++++----------- 2 files changed, 220 insertions(+), 212 deletions(-) diff --git a/include/json2cpp/json2cpp.hpp b/include/json2cpp/json2cpp.hpp index a32d6c4..d71296f 100644 --- a/include/json2cpp/json2cpp.hpp +++ b/include/json2cpp/json2cpp.hpp @@ -37,151 +37,155 @@ namespace json2cpp { template struct basic_json; -template struct pair { - F first; - [[no_unique_address]] S second; +template struct pair +{ + F first; + [[no_unique_address]] S second; }; template using basic_value_pair_t = pair, basic_json>; template using basic_object_t = std::span>; template using basic_array_t = std::span>; -template struct basic_json { +template struct basic_json +{ private: - enum class Type : uint8_t { Null, Boolean, String, Integer, UInteger, Float, Array, Object }; - - static constexpr size_t TYPE_SHIFT = sizeof(size_t) * 8 - 4; - static constexpr size_t LENGTH_MASK = (1ULL << TYPE_SHIFT) - 1; - static constexpr size_t capacity = sizeof(CharType *) / sizeof(CharType); - - size_t type_and_length_ = 0; - - union Data { - const basic_json *array_value; - const basic_value_pair_t *object_value; - const CharType *long_data; - std::array short_data{}; - int64_t int_value; - uint64_t uint_value; - double float_value; - bool boolean_value; - } data_; - - constexpr void set_type_and_length(Type t, size_t len) noexcept { - type_and_length_ = (static_cast(t) << TYPE_SHIFT) | (len & LENGTH_MASK); - } - - constexpr Type type() const noexcept { return static_cast(type_and_length_ >> TYPE_SHIFT); } - - constexpr const CharType *string_data() const noexcept { - return size() <= capacity ? data_.short_data.data() : data_.long_data; - } + enum class Type : uint8_t { Null, Boolean, String, Integer, UInteger, Float, Array, Object }; - constexpr basic_array_t array_data() const { - return { data_.array_value, size() }; - } - - constexpr basic_object_t object_data() const { - return { data_.object_value, size() }; - } + static constexpr size_t TYPE_SHIFT = sizeof(size_t) * 8 - 4; + static constexpr size_t LENGTH_MASK = (1ULL << TYPE_SHIFT) - 1; + static constexpr size_t capacity = sizeof(CharType *) / sizeof(CharType); - constexpr const basic_json* find_value(std::basic_string_view key) const noexcept { - if (!is_object()) return nullptr; - const auto obj = object_data(); - for (const auto& pair : obj) { - if (pair.first == key) return &pair.second; - } - return nullptr; - } + size_t type_and_length_ = 0; - constexpr void check_bounds(size_t index) const { - if (index >= size()) throw std::runtime_error("Index out of range"); - } + union Data { + const basic_json *array_value; + const basic_value_pair_t *object_value; + const CharType *long_data; + std::array short_data{}; + int64_t int_value; + uint64_t uint_value; + double float_value; + bool boolean_value; + } data_; -public: - constexpr basic_json() noexcept { set_type_and_length(Type::Null, 0); } - constexpr basic_json(std::nullptr_t) noexcept { set_type_and_length(Type::Null, 0); } - constexpr basic_json(bool v) noexcept : data_{ .boolean_value = v } { set_type_and_length(Type::Boolean, 0); } - constexpr basic_json(basic_array_t v) noexcept : data_{ .array_value = v.data() } { - set_type_and_length(Type::Array, v.size()); - } - constexpr basic_json(basic_object_t v) noexcept : data_{ .object_value = v.data() } { - set_type_and_length(Type::Object, v.size()); - } - constexpr basic_json(int64_t v) noexcept : data_{ .int_value = v } { set_type_and_length(Type::Integer, 0); } - constexpr basic_json(uint64_t v) noexcept : data_{ .uint_value = v } { set_type_and_length(Type::UInteger, 0); } - constexpr basic_json(double v) noexcept : data_{ .float_value = v } { set_type_and_length(Type::Float, 0); } - constexpr basic_json(std::basic_string_view v) noexcept { - const size_t len = v.size(); - set_type_and_length(Type::String, len); - if (len <= capacity) { - std::ranges::copy(v, data_.short_data.begin()); - } else { - data_.long_data = v.data(); - } - } + constexpr void set_type_and_length(Type t, size_t len) noexcept + { + type_and_length_ = (static_cast(t) << TYPE_SHIFT) | (len & LENGTH_MASK); + } - constexpr size_t size() const noexcept { return type_and_length_ & LENGTH_MASK; } - constexpr bool empty() const noexcept { return size() == 0; } + constexpr Type type() const noexcept { return static_cast(type_and_length_ >> TYPE_SHIFT); } - constexpr bool is_object() const noexcept { return type() == Type::Object; } - constexpr bool is_array() const noexcept { return type() == Type::Array; } - constexpr bool is_string() const noexcept { return type() == Type::String; } - constexpr bool is_number() const noexcept { return type() >= Type::Integer && type() <= Type::Float; } - constexpr bool is_boolean() const noexcept { return type() == Type::Boolean; } - constexpr bool is_null() const noexcept { return type() == Type::Null; } + constexpr const CharType *string_data() const noexcept + { + return size() <= capacity ? data_.short_data.data() : data_.long_data; + } - constexpr const basic_json &operator[](std::basic_string_view key) const { - return at(key); - } + constexpr basic_array_t array_data() const { return { data_.array_value, size() }; } - constexpr const basic_json &operator[](size_t index) const { return at(index); } + constexpr basic_object_t object_data() const { return { data_.object_value, size() }; } - template - constexpr bool operator==(const ValueType &other) const { - return is_string() && size() == other.length() && - std::equal(string_data(), string_data() + size(), other.data()); + constexpr const basic_json *find_value(std::basic_string_view key) const noexcept + { + if (!is_object()) return nullptr; + const auto obj = object_data(); + for (const auto &pair : obj) { + if (pair.first == key) return &pair.second; } + return nullptr; + } - constexpr const basic_json &at(size_t index) const { - check_bounds(index); - return is_array() ? array_data()[index] : object_data()[index].second; - } - - constexpr const basic_json &at(std::basic_string_view key) const { - const auto* result = find_value(key); - if (!result) throw std::out_of_range("Key not found"); - return *result; - } - - constexpr bool contains(std::basic_string_view key) const noexcept { - return find_value(key) != nullptr; - } - - constexpr basic_object_t items() const { return object_data(); } - constexpr auto begin() const { return array_data().begin(); } - constexpr auto end() const { return array_data().end(); } + constexpr void check_bounds(size_t index) const + { + if (index >= size()) throw std::runtime_error("Index out of range"); + } - constexpr std::basic_string_view getString() const { return { string_data(), size() }; } - - constexpr double getNumber() const { - return type() == Type::UInteger ? static_cast(data_.uint_value) : - type() == Type::Integer ? static_cast(data_.int_value) : - type() == Type::Float ? data_.float_value : - throw std::runtime_error("Not a number"); - } - - template constexpr T get() const { - if constexpr (std::is_same_v>) { - return getString(); - } else if constexpr (std::is_same_v) { - return data_.boolean_value; - } else if constexpr (std::is_arithmetic_v) { - return static_cast(getNumber()); - } else if constexpr (std::is_same_v) { - return nullptr; - } - } +public: + constexpr basic_json() noexcept { set_type_and_length(Type::Null, 0); } + constexpr basic_json(std::nullptr_t) noexcept { set_type_and_length(Type::Null, 0); } + constexpr basic_json(bool v) noexcept : data_{ .boolean_value = v } { set_type_and_length(Type::Boolean, 0); } + constexpr basic_json(basic_array_t v) noexcept : data_{ .array_value = v.data() } + { + set_type_and_length(Type::Array, v.size()); + } + constexpr basic_json(basic_object_t v) noexcept : data_{ .object_value = v.data() } + { + set_type_and_length(Type::Object, v.size()); + } + constexpr basic_json(int64_t v) noexcept : data_{ .int_value = v } { set_type_and_length(Type::Integer, 0); } + constexpr basic_json(uint64_t v) noexcept : data_{ .uint_value = v } { set_type_and_length(Type::UInteger, 0); } + constexpr basic_json(double v) noexcept : data_{ .float_value = v } { set_type_and_length(Type::Float, 0); } + constexpr basic_json(std::basic_string_view v) noexcept + { + const size_t len = v.size(); + set_type_and_length(Type::String, len); + if (len <= capacity) { + std::ranges::copy(v, data_.short_data.begin()); + } else { + data_.long_data = v.data(); + } + } + + constexpr size_t size() const noexcept { return type_and_length_ & LENGTH_MASK; } + constexpr bool empty() const noexcept { return size() == 0; } + + constexpr bool is_object() const noexcept { return type() == Type::Object; } + constexpr bool is_array() const noexcept { return type() == Type::Array; } + constexpr bool is_string() const noexcept { return type() == Type::String; } + constexpr bool is_number() const noexcept { return type() >= Type::Integer && type() <= Type::Float; } + constexpr bool is_boolean() const noexcept { return type() == Type::Boolean; } + constexpr bool is_null() const noexcept { return type() == Type::Null; } + + constexpr const basic_json &operator[](std::basic_string_view key) const { return at(key); } + + constexpr const basic_json &operator[](size_t index) const { return at(index); } + + template constexpr bool operator==(const ValueType &other) const + { + return is_string() && size() == other.length() && std::equal(string_data(), string_data() + size(), other.data()); + } + + constexpr const basic_json &at(size_t index) const + { + check_bounds(index); + return is_array() ? array_data()[index] : object_data()[index].second; + } + + constexpr const basic_json &at(std::basic_string_view key) const + { + const auto *result = find_value(key); + if (!result) throw std::out_of_range("Key not found"); + return *result; + } + + constexpr bool contains(std::basic_string_view key) const noexcept { return find_value(key) != nullptr; } + + constexpr basic_object_t items() const { return object_data(); } + constexpr auto begin() const { return array_data().begin(); } + constexpr auto end() const { return array_data().end(); } + + constexpr std::basic_string_view getString() const { return { string_data(), size() }; } + + constexpr double getNumber() const + { + return type() == Type::UInteger ? static_cast(data_.uint_value) + : type() == Type::Integer ? static_cast(data_.int_value) + : type() == Type::Float ? data_.float_value + : throw std::runtime_error("Not a number"); + } + + template constexpr T get() const + { + if constexpr (std::is_same_v>) { + return getString(); + } else if constexpr (std::is_same_v) { + return data_.boolean_value; + } else if constexpr (std::is_arithmetic_v) { + return static_cast(getNumber()); + } else if constexpr (std::is_same_v) { + return nullptr; + } + } }; #ifdef JSON2CPP_USE_UTF16 @@ -195,6 +199,6 @@ using array_t = basic_array_t; using object_t = basic_object_t; using value_pair_t = basic_value_pair_t; -} +}// namespace json2cpp #endif diff --git a/src/json2cpp.cpp b/src/json2cpp.cpp index 33a6f22..82bc87b 100644 --- a/src/json2cpp.cpp +++ b/src/json2cpp.cpp @@ -25,10 +25,10 @@ SOFTWARE. #include "json2cpp.hpp" #include #include -#include -#include #include +#include #include +#include std::string format_json_string(const std::string &str) { @@ -84,55 +84,46 @@ struct StringDuplicateTracker } }; -struct DuplicateTracker { - std::unordered_map counts; - std::unordered_map signature_to_var; - std::set processed_signatures; - std::size_t counter = 0; - const std::string prefix; +struct DuplicateTracker +{ + std::unordered_map counts; + std::unordered_map signature_to_var; + std::set processed_signatures; + std::size_t counter = 0; + const std::string prefix; - DuplicateTracker(std::string p) : prefix(std::move(p)) {} + DuplicateTracker(std::string p) : prefix(std::move(p)) {} - void track(const nlohmann::ordered_json& value) { - counts[value.dump()]++; - } + void track(const nlohmann::ordered_json &value) { counts[value.dump()]++; } - void prepare_variables() { - for(const auto& [signature, count] : counts) { - if (count > 1) { - signature_to_var[signature] = fmt::format("shared_{}_{}", prefix, counter++); - } - } + void prepare_variables() + { + for (const auto &[signature, count] : counts) { + if (count > 1) { signature_to_var[signature] = fmt::format("shared_{}_{}", prefix, counter++); } } + } - bool is_shared(const std::string& signature) const { - return signature_to_var.count(signature); - } + bool is_shared(const std::string &signature) const { return signature_to_var.count(signature); } - bool is_processed(const std::string& signature) const { - return processed_signatures.count(signature); - } - - void mark_as_processed(const std::string& signature) { - processed_signatures.insert(signature); - } - - std::size_t get_reused_count() const { return signature_to_var.size(); } + bool is_processed(const std::string &signature) const { return processed_signatures.count(signature); } - int32_t get_total_references_saved() const { - int32_t total = 0; - for (const auto& [sig, var] : signature_to_var) { - total += counts.at(sig) - 1; - } - return total; - } + void mark_as_processed(const std::string &signature) { processed_signatures.insert(signature); } + + std::size_t get_reused_count() const { return signature_to_var.size(); } + + int32_t get_total_references_saved() const + { + int32_t total = 0; + for (const auto &[sig, var] : signature_to_var) { total += counts.at(sig) - 1; } + return total; + } }; void analyze_for_duplicates(const nlohmann::ordered_json &value, - StringDuplicateTracker &string_tracker, - DuplicateTracker &object_tracker, - DuplicateTracker &array_tracker, - DuplicateTracker &pair_tracker) + StringDuplicateTracker &string_tracker, + DuplicateTracker &object_tracker, + DuplicateTracker &array_tracker, + DuplicateTracker &pair_tracker) { if (value.is_object()) { object_tracker.track(value); @@ -145,7 +136,9 @@ void analyze_for_duplicates(const nlohmann::ordered_json &value, } } else if (value.is_array()) { array_tracker.track(value); - for (const auto &item : value) { analyze_for_duplicates(item, string_tracker, object_tracker, array_tracker, pair_tracker); } + for (const auto &item : value) { + analyze_for_duplicates(item, string_tracker, object_tracker, array_tracker, pair_tracker); + } } else if (value.is_string()) { string_tracker.count_string(value.get()); } @@ -172,42 +165,47 @@ std::string generate_node_body(const nlohmann::ordered_json &value, if (value.is_object()) { std::vector pairs; for (auto itr = value.begin(); itr != value.end(); ++itr) { - nlohmann::ordered_json pair_rep; - pair_rep[itr.key()] = *itr; - std::string pair_signature = pair_rep.dump(); - - if (pair_tracker.is_shared(pair_signature)) { - auto var_name = pair_tracker.signature_to_var.at(pair_signature); - if (!pair_tracker.is_processed(pair_signature)) { - pair_tracker.mark_as_processed(pair_signature); - const auto key_repr = string_tracker.get_string_representation(itr.key()); - const auto val_repr = compile_dispatch(*itr, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); - lines.emplace_back(fmt::format("inline constexpr auto {} = value_pair_t{{{}, {}}};", var_name, key_repr, val_repr)); - } - pairs.emplace_back(fmt::format("{},", var_name)); - } else { - const auto key_repr = string_tracker.get_string_representation(itr.key()); - pairs.emplace_back(fmt::format("value_pair_t{{{}, {}}},", key_repr, compile_dispatch(*itr, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker))); + nlohmann::ordered_json pair_rep; + pair_rep[itr.key()] = *itr; + std::string pair_signature = pair_rep.dump(); + + if (pair_tracker.is_shared(pair_signature)) { + auto var_name = pair_tracker.signature_to_var.at(pair_signature); + if (!pair_tracker.is_processed(pair_signature)) { + pair_tracker.mark_as_processed(pair_signature); + const auto key_repr = string_tracker.get_string_representation(itr.key()); + const auto val_repr = + compile_dispatch(*itr, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); + lines.emplace_back( + fmt::format("inline constexpr auto {} = value_pair_t{{{}, {}}};", var_name, key_repr, val_repr)); } + pairs.emplace_back(fmt::format("{},", var_name)); + } else { + const auto key_repr = string_tracker.get_string_representation(itr.key()); + pairs.emplace_back(fmt::format("value_pair_t{{{}, {}}},", + key_repr, + compile_dispatch(*itr, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker))); + } } lines.emplace_back(fmt::format( "inline constexpr std::array object_data_{} = {{{{", pairs.size(), current_object_number)); - for (const auto& pair : pairs) { lines.emplace_back(fmt::format(" {}", pair)); } + for (const auto &pair : pairs) { lines.emplace_back(fmt::format(" {}", pair)); } lines.emplace_back("}};"); return fmt::format("object_t{{object_data_{}}}", current_object_number); } else if (value.is_array()) { std::vector entries; - for (const auto& child : value) { - entries.emplace_back(fmt::format("{{{}}},", compile_dispatch(child, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker))); + for (const auto &child : value) { + entries.emplace_back(fmt::format("{{{}}},", + compile_dispatch(child, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker))); } lines.emplace_back(fmt::format( "inline constexpr std::array object_data_{} = {{{{", entries.size(), current_object_number)); - for (const auto& entry : entries) { lines.emplace_back(fmt::format(" {}", entry)); } + for (const auto &entry : entries) { lines.emplace_back(fmt::format(" {}", entry)); } lines.emplace_back("}};"); return fmt::format("array_t{{object_data_{}}}", current_object_number); } - + return ""; } @@ -221,31 +219,29 @@ std::string compile_dispatch(const nlohmann::ordered_json &value, DuplicateTracker &pair_tracker) { std::string signature = value.dump(); - + if (value.is_object() && object_tracker.is_shared(signature)) { auto var_name = object_tracker.signature_to_var.at(signature); - if (object_tracker.is_processed(signature)) { - return var_name; - } + if (object_tracker.is_processed(signature)) { return var_name; } object_tracker.mark_as_processed(signature); - auto body = generate_node_body(value, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); + auto body = + generate_node_body(value, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); lines.emplace_back(fmt::format("inline constexpr auto {} = json{{{{{}}}}};", var_name, body)); return var_name; } - + if (value.is_array() && array_tracker.is_shared(signature)) { auto var_name = array_tracker.signature_to_var.at(signature); - if (array_tracker.is_processed(signature)) { - return var_name; - } + if (array_tracker.is_processed(signature)) { return var_name; } array_tracker.mark_as_processed(signature); - auto body = generate_node_body(value, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); + auto body = + generate_node_body(value, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); lines.emplace_back(fmt::format("inline constexpr auto {} = json{{{{{}}}}};", var_name, body)); return var_name; } if (value.is_object() || value.is_array()) { - return generate_node_body(value, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); + return generate_node_body(value, obj_count, lines, string_tracker, object_tracker, array_tracker, pair_tracker); } else if (value.is_number_float()) { return fmt::format("double{{{}}}", value.get()); } else if (value.is_number_unsigned()) { @@ -270,7 +266,7 @@ compile_results compile(const std::string_view document_name, const nlohmann::or DuplicateTracker array_tracker("arr"); DuplicateTracker pair_tracker("pair"); compile_results results; - + analyze_for_duplicates(json, string_tracker, object_tracker, array_tracker, pair_tracker); string_tracker.generate_definitions(); object_tracker.prepare_variables(); @@ -303,29 +299,36 @@ namespace compiled_json::{}::impl {{ using array_t = json2cpp::basic_array_t; using object_t = json2cpp::basic_object_t; using value_pair_t = json2cpp::basic_value_pair_t; - )", document_name)); + )", + document_name)); const auto &string_defs = string_tracker.get_definitions(); results.impl.insert(results.impl.end(), string_defs.begin(), string_defs.end()); - + std::size_t obj_count = 0; - const auto last_obj_name = compile_dispatch(json, obj_count, results.impl, string_tracker, object_tracker, array_tracker, pair_tracker); + const auto last_obj_name = + compile_dispatch(json, obj_count, results.impl, string_tracker, object_tracker, array_tracker, pair_tracker); results.impl.emplace_back(fmt::format(R"( inline constexpr auto document = json{{{{{}}}}}; }} -#endif)", last_obj_name)); +#endif)", + last_obj_name)); spdlog::info("{} JSON objects processed.", obj_count); spdlog::info("{} duplicate strings reused, saving {} string definitions.", - string_tracker.get_reused_count(), string_tracker.get_total_references_saved()); + string_tracker.get_reused_count(), + string_tracker.get_total_references_saved()); spdlog::info("{} duplicate arrays reused, saving {} references.", - array_tracker.get_reused_count(), array_tracker.get_total_references_saved()); + array_tracker.get_reused_count(), + array_tracker.get_total_references_saved()); spdlog::info("{} duplicate objects reused, saving {} references.", - object_tracker.get_reused_count(), object_tracker.get_total_references_saved()); + object_tracker.get_reused_count(), + object_tracker.get_total_references_saved()); spdlog::info("{} duplicate key-value pairs reused, saving {} references.", - pair_tracker.get_reused_count(), pair_tracker.get_total_references_saved()); - + pair_tracker.get_reused_count(), + pair_tracker.get_total_references_saved()); + return results; } @@ -358,7 +361,8 @@ void write_compilation([[maybe_unused]] std::string_view document_name, cpp << fmt::format("#include \"{}\"\n", impl_name.filename().string()); cpp << fmt::format( "namespace compiled_json::{} {{\nconst json2cpp::json &get() {{ return compiled_json::{}::impl::document; }}\n}}\n", - document_name, document_name); + document_name, + document_name); } void compile_to(const std::string_view document_name, From 15a1c88ca69c0bcd017d651f53180833c0ed2f8b Mon Sep 17 00:00:00 2001 From: reg31 <37986256+reg31@users.noreply.github.com> Date: Sat, 9 Aug 2025 15:21:26 +0100 Subject: [PATCH 2/3] support array in contains() --- include/json2cpp/json2cpp.hpp | 270 +++++++++++++++++----------------- 1 file changed, 138 insertions(+), 132 deletions(-) diff --git a/include/json2cpp/json2cpp.hpp b/include/json2cpp/json2cpp.hpp index d71296f..88aa289 100644 --- a/include/json2cpp/json2cpp.hpp +++ b/include/json2cpp/json2cpp.hpp @@ -37,155 +37,161 @@ namespace json2cpp { template struct basic_json; -template struct pair -{ - F first; - [[no_unique_address]] S second; +template struct pair { + F first; + [[no_unique_address]] S second; }; template using basic_value_pair_t = pair, basic_json>; template using basic_object_t = std::span>; template using basic_array_t = std::span>; -template struct basic_json -{ +template struct basic_json { private: - enum class Type : uint8_t { Null, Boolean, String, Integer, UInteger, Float, Array, Object }; + enum class Type : uint8_t { Null, Boolean, String, Integer, UInteger, Float, Array, Object }; + + static constexpr size_t TYPE_SHIFT = sizeof(size_t) * 8 - 4; + static constexpr size_t LENGTH_MASK = (1ULL << TYPE_SHIFT) - 1; + static constexpr size_t capacity = sizeof(CharType *) / sizeof(CharType); + + size_t type_and_length_ = 0; + + union Data { + const basic_json *array_value; + const basic_value_pair_t *object_value; + const CharType *long_data; + std::array short_data{}; + int64_t int_value; + uint64_t uint_value; + double float_value; + bool boolean_value; + } data_; + + constexpr void set_type_and_length(Type t, size_t len) noexcept { + type_and_length_ = (static_cast(t) << TYPE_SHIFT) | (len & LENGTH_MASK); + } + + constexpr Type type() const noexcept { return static_cast(type_and_length_ >> TYPE_SHIFT); } + + constexpr const CharType *string_data() const noexcept { + return size() <= capacity ? data_.short_data.data() : data_.long_data; + } + + constexpr basic_array_t array_data() const { + return { data_.array_value, size() }; + } + + constexpr basic_object_t object_data() const { + return { data_.object_value, size() }; + } - static constexpr size_t TYPE_SHIFT = sizeof(size_t) * 8 - 4; - static constexpr size_t LENGTH_MASK = (1ULL << TYPE_SHIFT) - 1; - static constexpr size_t capacity = sizeof(CharType *) / sizeof(CharType); + inline constexpr const basic_json* find_value(std::basic_string_view key) const noexcept { + if (is_object()) { + const auto obj = object_data(); + const auto it = std::ranges::find_if(obj, [key](const auto& pair) { + return pair.first.getString() == key; + }); + return (it != obj.end()) ? &it->second : nullptr; + } else if (is_array()) { + const auto arr = array_data(); + const auto it = std::ranges::find_if(arr, [key](const auto& element) { + return element.is_string() && element.getString() == key; + }); + return (it != arr.end()) ? &(*it) : nullptr; + } + return nullptr; + } + + inline constexpr void check_bounds(size_t index) const { + if (index >= size()) throw std::runtime_error("Index out of range"); + } + +public: + constexpr basic_json() noexcept { set_type_and_length(Type::Null, 0); } + constexpr basic_json(std::nullptr_t) noexcept { set_type_and_length(Type::Null, 0); } + constexpr basic_json(bool v) noexcept : data_{ .boolean_value = v } { set_type_and_length(Type::Boolean, 0); } + constexpr basic_json(basic_array_t v) noexcept : data_{ .array_value = v.data() } { + set_type_and_length(Type::Array, v.size()); + } + constexpr basic_json(basic_object_t v) noexcept : data_{ .object_value = v.data() } { + set_type_and_length(Type::Object, v.size()); + } + constexpr basic_json(int64_t v) noexcept : data_{ .int_value = v } { set_type_and_length(Type::Integer, 0); } + constexpr basic_json(uint64_t v) noexcept : data_{ .uint_value = v } { set_type_and_length(Type::UInteger, 0); } + constexpr basic_json(double v) noexcept : data_{ .float_value = v } { set_type_and_length(Type::Float, 0); } + + inline constexpr basic_json(std::basic_string_view v) noexcept { + const size_t len = v.size(); + set_type_and_length(Type::String, len); + + if (len <= capacity) + std::ranges::copy(v, data_.short_data.begin()); + else + data_.long_data = v.data(); + } - size_t type_and_length_ = 0; + constexpr size_t size() const noexcept { return type_and_length_ & LENGTH_MASK; } + constexpr bool empty() const noexcept { return size() == 0; } - union Data { - const basic_json *array_value; - const basic_value_pair_t *object_value; - const CharType *long_data; - std::array short_data{}; - int64_t int_value; - uint64_t uint_value; - double float_value; - bool boolean_value; - } data_; + constexpr bool is_object() const noexcept { return type() == Type::Object; } + constexpr bool is_array() const noexcept { return type() == Type::Array; } + constexpr bool is_string() const noexcept { return type() == Type::String; } + constexpr bool is_number() const noexcept { return type() >= Type::Integer && type() <= Type::Float; } + constexpr bool is_boolean() const noexcept { return type() == Type::Boolean; } + constexpr bool is_null() const noexcept { return type() == Type::Null; } - constexpr void set_type_and_length(Type t, size_t len) noexcept - { - type_and_length_ = (static_cast(t) << TYPE_SHIFT) | (len & LENGTH_MASK); - } + constexpr const basic_json &operator[](std::basic_string_view key) const { + return at(key); + } - constexpr Type type() const noexcept { return static_cast(type_and_length_ >> TYPE_SHIFT); } + constexpr const basic_json &operator[](size_t index) const { return at(index); } - constexpr const CharType *string_data() const noexcept - { - return size() <= capacity ? data_.short_data.data() : data_.long_data; - } + template + inline constexpr bool operator==(const ValueType &other) const { + return is_string() && size() == other.length() && + std::equal(string_data(), string_data() + size(), other.data()); + } - constexpr basic_array_t array_data() const { return { data_.array_value, size() }; } + constexpr const basic_json &at(size_t index) const { + check_bounds(index); + return is_array() ? array_data()[index] : object_data()[index].second; + } - constexpr basic_object_t object_data() const { return { data_.object_value, size() }; } + inline constexpr const basic_json &at(std::basic_string_view key) const { + const auto* result = find_value(key); + if (!result) throw std::out_of_range("Key not found"); + return *result; + } - constexpr const basic_json *find_value(std::basic_string_view key) const noexcept - { - if (!is_object()) return nullptr; - const auto obj = object_data(); - for (const auto &pair : obj) { - if (pair.first == key) return &pair.second; + constexpr bool contains(std::basic_string_view key) const noexcept { + return find_value(key) != nullptr; } - return nullptr; - } - constexpr void check_bounds(size_t index) const - { - if (index >= size()) throw std::runtime_error("Index out of range"); - } + constexpr basic_object_t items() const { return object_data(); } + constexpr auto begin() const { return array_data().begin(); } + constexpr auto end() const { return array_data().end(); } -public: - constexpr basic_json() noexcept { set_type_and_length(Type::Null, 0); } - constexpr basic_json(std::nullptr_t) noexcept { set_type_and_length(Type::Null, 0); } - constexpr basic_json(bool v) noexcept : data_{ .boolean_value = v } { set_type_and_length(Type::Boolean, 0); } - constexpr basic_json(basic_array_t v) noexcept : data_{ .array_value = v.data() } - { - set_type_and_length(Type::Array, v.size()); - } - constexpr basic_json(basic_object_t v) noexcept : data_{ .object_value = v.data() } - { - set_type_and_length(Type::Object, v.size()); - } - constexpr basic_json(int64_t v) noexcept : data_{ .int_value = v } { set_type_and_length(Type::Integer, 0); } - constexpr basic_json(uint64_t v) noexcept : data_{ .uint_value = v } { set_type_and_length(Type::UInteger, 0); } - constexpr basic_json(double v) noexcept : data_{ .float_value = v } { set_type_and_length(Type::Float, 0); } - constexpr basic_json(std::basic_string_view v) noexcept - { - const size_t len = v.size(); - set_type_and_length(Type::String, len); - if (len <= capacity) { - std::ranges::copy(v, data_.short_data.begin()); - } else { - data_.long_data = v.data(); - } - } - - constexpr size_t size() const noexcept { return type_and_length_ & LENGTH_MASK; } - constexpr bool empty() const noexcept { return size() == 0; } - - constexpr bool is_object() const noexcept { return type() == Type::Object; } - constexpr bool is_array() const noexcept { return type() == Type::Array; } - constexpr bool is_string() const noexcept { return type() == Type::String; } - constexpr bool is_number() const noexcept { return type() >= Type::Integer && type() <= Type::Float; } - constexpr bool is_boolean() const noexcept { return type() == Type::Boolean; } - constexpr bool is_null() const noexcept { return type() == Type::Null; } - - constexpr const basic_json &operator[](std::basic_string_view key) const { return at(key); } - - constexpr const basic_json &operator[](size_t index) const { return at(index); } - - template constexpr bool operator==(const ValueType &other) const - { - return is_string() && size() == other.length() && std::equal(string_data(), string_data() + size(), other.data()); - } - - constexpr const basic_json &at(size_t index) const - { - check_bounds(index); - return is_array() ? array_data()[index] : object_data()[index].second; - } - - constexpr const basic_json &at(std::basic_string_view key) const - { - const auto *result = find_value(key); - if (!result) throw std::out_of_range("Key not found"); - return *result; - } - - constexpr bool contains(std::basic_string_view key) const noexcept { return find_value(key) != nullptr; } - - constexpr basic_object_t items() const { return object_data(); } - constexpr auto begin() const { return array_data().begin(); } - constexpr auto end() const { return array_data().end(); } - - constexpr std::basic_string_view getString() const { return { string_data(), size() }; } - - constexpr double getNumber() const - { - return type() == Type::UInteger ? static_cast(data_.uint_value) - : type() == Type::Integer ? static_cast(data_.int_value) - : type() == Type::Float ? data_.float_value - : throw std::runtime_error("Not a number"); - } - - template constexpr T get() const - { - if constexpr (std::is_same_v>) { - return getString(); - } else if constexpr (std::is_same_v) { - return data_.boolean_value; - } else if constexpr (std::is_arithmetic_v) { - return static_cast(getNumber()); - } else if constexpr (std::is_same_v) { - return nullptr; - } - } + constexpr std::basic_string_view getString() const { return { string_data(), size() }; } + + inline constexpr double getNumber() const { + return type() == Type::UInteger ? static_cast(data_.uint_value) : + type() == Type::Integer ? static_cast(data_.int_value) : + type() == Type::Float ? data_.float_value : + throw std::runtime_error("Not a number"); + } + + template + inline constexpr T get() const { + if constexpr (std::is_same_v>) { + return getString(); + } else if constexpr (std::is_same_v) { + return data_.boolean_value; + } else if constexpr (std::is_arithmetic_v) { + return static_cast(getNumber()); + } else if constexpr (std::is_same_v) { + return nullptr; + } + } }; #ifdef JSON2CPP_USE_UTF16 @@ -199,6 +205,6 @@ using array_t = basic_array_t; using object_t = basic_object_t; using value_pair_t = basic_value_pair_t; -}// namespace json2cpp +} -#endif +#endi From ee8ca10c677f92fa43967dbbb6ead93216f961e7 Mon Sep 17 00:00:00 2001 From: reg31 <37986256+reg31@users.noreply.github.com> Date: Sat, 9 Aug 2025 15:21:54 +0100 Subject: [PATCH 3/3] Bump version to 3.3 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2927b2c..d810162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ set(CMAKE_CXX_EXTENSIONS ON) # Set the project name and language project( json2cpp - VERSION 3.2 + VERSION 3.3 DESCRIPTION "" HOMEPAGE_URL "%%myurl%%" LANGUAGES CXX C)