From 34a37fcf5badc56cab5eb152b1094aa880cfa043 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 20 Jan 2025 17:17:56 -0400 Subject: [PATCH] Consume `FlatMap` from Noa Signed-off-by: Juan Cruz Viotti --- .github/workflows/ci.yml | 6 + CMakeLists.txt | 1 - DEPENDENCIES | 2 +- Makefile | 4 + config.cmake.in | 1 + src/json/CMakeLists.txt | 5 +- .../sourcemeta/jsontoolkit/json_hash.h | 34 +- .../sourcemeta/jsontoolkit/json_object.h | 4 +- .../sourcemeta/jsontoolkit/json_value.h | 2 +- .../sourcemeta/jsontoolkit/jsonpointer.h | 5 +- .../jsontoolkit/jsonpointer_pointer.h | 42 +- .../jsontoolkit/jsonpointer_position.h | 2 +- .../jsontoolkit/jsonpointer_token.h | 6 +- src/jsonpointer/jsonpointer.cc | 10 +- test/json/CMakeLists.txt | 7 +- test/json/json_flat_map_test.cc | 292 -------- test/json/json_hash_test.cc | 231 +++--- test/json/json_object_test.cc | 9 +- vendor/noa/CMakeLists.txt | 64 ++ vendor/noa/LICENSE | 673 +----------------- vendor/noa/cmake/noa/compiler/options.cmake | 2 +- vendor/noa/cmake/noa/targets/library.cmake | 13 +- vendor/noa/config.cmake.in | 21 + vendor/noa/src/flat_map/CMakeLists.txt | 7 + .../include/sourcemeta/noa/flat_map.h | 29 +- vendor/noa/src/hash/CMakeLists.txt | 7 + .../src/hash/include/sourcemeta/noa/hash.h | 25 + 27 files changed, 373 insertions(+), 1131 deletions(-) delete mode 100644 test/json/json_flat_map_test.cc create mode 100644 vendor/noa/config.cmake.in create mode 100644 vendor/noa/src/flat_map/CMakeLists.txt rename src/json/include/sourcemeta/jsontoolkit/json_flat_map.h => vendor/noa/src/flat_map/include/sourcemeta/noa/flat_map.h (92%) create mode 100644 vendor/noa/src/hash/CMakeLists.txt create mode 100644 vendor/noa/src/hash/include/sourcemeta/noa/hash.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c34031cb..abc06c3de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,12 @@ jobs: ${{ matrix.platform.options }} - run: cmake --build ./build --config Release --target clang_format_test - run: cmake --build ./build --config Release --parallel 4 + - run: > + cmake --install ./build --prefix ./build/dist --config Release --verbose + --component sourcemeta_noa + - run: > + cmake --install ./build --prefix ./build/dist --config Release --verbose + --component sourcemeta_noa_dev - run: > cmake --install ./build --prefix ./build/dist --config Release --verbose --component sourcemeta_jsontoolkit diff --git a/CMakeLists.txt b/CMakeLists.txt index 6177d679c..b5d79899e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,6 @@ endif() if(PROJECT_IS_TOP_LEVEL) noa_target_clang_format(SOURCES - bindings/*.cc src/*.h src/*.cc benchmark/*.h benchmark/*.cc test/*.h test/*.cc) diff --git a/DEPENDENCIES b/DEPENDENCIES index 103ac981f..9db96a7f3 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,5 +1,5 @@ vendorpull https://github.com/sourcemeta/vendorpull 70342aaf458e6cb80baeb5b718901075fc42ede6 -noa https://github.com/sourcemeta/noa 3c8de8fb7f59448e110c332cee95815e074cb76d +noa https://github.com/sourcemeta/noa 7f32f55327d9679bf45e5c2831e9501175ad441e jsontestsuite https://github.com/nst/JSONTestSuite d64aefb55228d9584d3e5b2433f720ea8fd00c82 jsonschema-2020-12 https://github.com/json-schema-org/json-schema-spec 769daad75a9553562333a8937a187741cb708c72 jsonschema-2019-09 https://github.com/json-schema-org/json-schema-spec 41014ea723120ce70b314d72f863c6929d9f3cfd diff --git a/Makefile b/Makefile index 0139cf601..fc40e4de9 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,10 @@ configure: .always compile: .always $(CMAKE) --build ./build --config $(PRESET) --target clang_format $(CMAKE) --build ./build --config $(PRESET) --parallel 4 + $(CMAKE) --install ./build --prefix ./build/dist --config $(PRESET) --verbose \ + --component sourcemeta_noa + $(CMAKE) --install ./build --prefix ./build/dist --config $(PRESET) --verbose \ + --component sourcemeta_noa_dev $(CMAKE) --install ./build --prefix ./build/dist --config $(PRESET) --verbose \ --component sourcemeta_jsontoolkit $(CMAKE) --install ./build --prefix ./build/dist --config $(PRESET) --verbose \ diff --git a/config.cmake.in b/config.cmake.in index ade27e94b..b47094866 100644 --- a/config.cmake.in +++ b/config.cmake.in @@ -20,6 +20,7 @@ foreach(component ${JSONTOOLKIT_COMPONENTS}) find_dependency(uriparser) include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_uri.cmake") elseif(component STREQUAL "json") + find_dependency(noa) include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_json.cmake") elseif(component STREQUAL "regex") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_json.cmake") diff --git a/src/json/CMakeLists.txt b/src/json/CMakeLists.txt index 37fbb4d9c..bffa672f1 100644 --- a/src/json/CMakeLists.txt +++ b/src/json/CMakeLists.txt @@ -1,8 +1,11 @@ noa_library(NAMESPACE sourcemeta PROJECT jsontoolkit NAME json FOLDER "JSON Toolkit/JSON" - PRIVATE_HEADERS array.h error.h object.h value.h hash.h flat_map.h + PRIVATE_HEADERS array.h error.h object.h value.h hash.h SOURCES grammar.h parser.h stringify.h json.cc json_value.cc) if(JSONTOOLKIT_INSTALL) noa_library_install(NAMESPACE sourcemeta PROJECT jsontoolkit NAME json) endif() + +target_link_libraries(sourcemeta_jsontoolkit_json + PUBLIC sourcemeta::noa::flat_map) diff --git a/src/json/include/sourcemeta/jsontoolkit/json_hash.h b/src/json/include/sourcemeta/jsontoolkit/json_hash.h index abfa638f5..a8d9afe66 100644 --- a/src/json/include/sourcemeta/jsontoolkit/json_hash.h +++ b/src/json/include/sourcemeta/jsontoolkit/json_hash.h @@ -13,30 +13,29 @@ template struct FastHash { return value.fast_hash(); } - struct property_hash_type { + inline auto is_perfect(const hash_type) const noexcept -> bool { + return false; + } +}; + +/// @ingroup json +template struct KeyHash { + struct hash_type { using type = std::uint64_t; type a{0}; type b{0}; type c{0}; type d{0}; - inline auto operator==(const property_hash_type &other) const noexcept - -> bool { + inline auto operator==(const hash_type &other) const noexcept -> bool { return this->a == other.a && this->b == other.b && this->c == other.c && this->d == other.d; } - - inline auto is_perfect() const noexcept -> bool { - // If there is anything written past the first byte, - // then it is a perfect hash - return this->a > 255; - } }; - inline auto operator()(const typename T::String &value) const noexcept - -> property_hash_type { + inline auto operator()(const T &value) const noexcept -> hash_type { const auto size{value.size()}; - property_hash_type result; + hash_type result; if (size == 0) { return result; } else if (size <= 31) { @@ -47,13 +46,18 @@ template struct FastHash { // This case is specifically designed to be constant with regards to // string length, and to exploit the fact that most JSON objects don't // have a lot of entries, so hash collision is not as common - return {(size + - static_cast(value.front()) + - static_cast(value.back())) % + return {(size + static_cast(value.front()) + + static_cast(value.back())) % // Make sure the property hash can never exceed 8 bits 256}; } } + + inline auto is_perfect(const hash_type &hash) const noexcept -> bool { + // If there is anything written past the first byte, + // then it is a perfect hash + return hash.a > 255; + } }; } // namespace sourcemeta::jsontoolkit diff --git a/src/json/include/sourcemeta/jsontoolkit/json_object.h b/src/json/include/sourcemeta/jsontoolkit/json_object.h index a5d7396bd..d5082b93e 100644 --- a/src/json/include/sourcemeta/jsontoolkit/json_object.h +++ b/src/json/include/sourcemeta/jsontoolkit/json_object.h @@ -4,7 +4,7 @@ #include // std::equal_to, std::less #include // std::initializer_list -#include +#include namespace sourcemeta::jsontoolkit { @@ -12,7 +12,7 @@ namespace sourcemeta::jsontoolkit { template class JSONObject { public: // Constructors - using Container = FlatMap; + using Container = sourcemeta::noa::FlatMap; JSONObject() : data{} {} JSONObject(std::initializer_list values) diff --git a/src/json/include/sourcemeta/jsontoolkit/json_value.h b/src/json/include/sourcemeta/jsontoolkit/json_value.h index b883f7b1c..abe4b39e1 100644 --- a/src/json/include/sourcemeta/jsontoolkit/json_value.h +++ b/src/json/include/sourcemeta/jsontoolkit/json_value.h @@ -43,7 +43,7 @@ class SOURCEMETA_JSONTOOLKIT_JSON_EXPORT JSON { /// The array type used by the JSON document. using Array = JSONArray; /// The object type used by the JSON document. - using Object = JSONObject>; + using Object = JSONObject>; /* * Constructors diff --git a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h index 8236eb04e..67580384b 100644 --- a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h +++ b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h @@ -31,10 +31,11 @@ namespace sourcemeta::jsontoolkit { /// @ingroup jsonpointer -using Pointer = GenericPointer; +using Pointer = GenericPointer>; /// @ingroup jsonpointer -using WeakPointer = GenericPointer>; +using WeakPointer = GenericPointer, + KeyHash>; /// @ingroup jsonpointer /// A global constant instance of the empty JSON Pointer. diff --git a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h index 90759137e..c82840e11 100644 --- a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h +++ b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h @@ -17,7 +17,7 @@ namespace sourcemeta::jsontoolkit { /// @ingroup jsonpointer -template class GenericPointer { +template class GenericPointer { public: using Token = GenericToken; using Value = typename Token::Value; @@ -206,7 +206,7 @@ template class GenericPointer { /// assert(pointer.at(1).to_property() == "bar"); /// assert(pointer.at(2).to_property() == "baz"); /// ``` - auto push_back(const GenericPointer &other) -> void { + auto push_back(const GenericPointer &other) -> void { if (other.empty()) { return; } else if (other.size() == 1) { @@ -239,7 +239,7 @@ template class GenericPointer { /// assert(pointer.at(1).to_property() == "bar"); /// assert(pointer.at(2).to_property() == "baz"); /// ``` - auto push_back(GenericPointer &&other) -> void { + auto push_back(GenericPointer &&other) -> void { if (other.empty()) { return; } else if (other.size() == 1) { @@ -277,7 +277,7 @@ template class GenericPointer { template >>> - auto push_back(const GenericPointer &other) -> void { + auto push_back(const GenericPointer &other) -> void { if (other.empty()) { return; } else if (other.size() == 1) { @@ -422,9 +422,9 @@ template class GenericPointer { /// assert(pointer.at(1).is_property()); /// assert(pointer.at(1).to_property() == "bar"); /// ``` - [[nodiscard]] auto initial() const -> GenericPointer { + [[nodiscard]] auto initial() const -> GenericPointer { assert(!this->empty()); - GenericPointer result{*this}; + GenericPointer result{*this}; result.pop_back(); return result; } @@ -441,9 +441,9 @@ template class GenericPointer { /// assert(left.concat(right) == /// sourcemeta::jsontoolkit::Pointer{"foo", "bar", "baz"}); /// ``` - auto concat(const GenericPointer &other) const - -> GenericPointer { - GenericPointer result{*this}; + auto concat(const GenericPointer &other) const + -> GenericPointer { + GenericPointer result{*this}; result.push_back(other); return result; } @@ -459,7 +459,7 @@ template class GenericPointer { /// const sourcemeta::jsontoolkit::Pointer prefix{"foo", "bar"}; /// assert(pointer.starts_with(prefix)); /// ``` - auto starts_with(const GenericPointer &other) const -> bool { + auto starts_with(const GenericPointer &other) const -> bool { return other.data.size() <= this->data.size() && std::equal(other.data.cbegin(), other.data.cend(), this->data.cbegin()); @@ -477,7 +477,7 @@ template class GenericPointer { /// const sourcemeta::jsontoolkit::Pointer prefix{"foo", "bar", "baz"}; /// assert(pointer.starts_with(prefix, tail)); /// ``` - auto starts_with(const GenericPointer &other, + auto starts_with(const GenericPointer &other, const Token &tail) const -> bool { if (other.size() == this->size() + 1) { assert(!other.empty()); @@ -498,7 +498,7 @@ template class GenericPointer { /// const sourcemeta::jsontoolkit::Pointer prefix{"foo", "bar", "qux"}; /// assert(pointer.starts_with_initial(prefix)); /// ``` - auto starts_with_initial(const GenericPointer &other) const + auto starts_with_initial(const GenericPointer &other) const -> bool { const auto prefix_size{other.size()}; if (prefix_size == 0) { @@ -529,9 +529,9 @@ template class GenericPointer { /// assert(pointer.rebase(prefix, replacement) == /// sourcemeta::jsontoolkit::Pointer{"qux", "baz"}); /// ``` - auto rebase(const GenericPointer &prefix, - const GenericPointer &replacement) const - -> GenericPointer { + auto rebase(const GenericPointer &prefix, + const GenericPointer &replacement) const + -> GenericPointer { typename Container::size_type index{0}; while (index < prefix.size()) { if (index >= this->size() || prefix.data[index] != this->data[index]) { @@ -545,7 +545,7 @@ template class GenericPointer { assert(this->starts_with(prefix)); auto new_begin{this->data.cbegin()}; std::advance(new_begin, index); - GenericPointer result{replacement}; + GenericPointer result{replacement}; std::copy(new_begin, this->data.cend(), std::back_inserter(result.data)); return result; } @@ -564,8 +564,8 @@ template class GenericPointer { /// /// If the JSON Pointer is not relative to the base, a copy of the original /// input pointer is returned. - auto resolve_from(const GenericPointer &base) const - -> GenericPointer { + auto resolve_from(const GenericPointer &base) const + -> GenericPointer { typename Container::size_type index{0}; while (index < base.size()) { if (index >= this->size() || base.data[index] != this->data[index]) { @@ -578,20 +578,20 @@ template class GenericPointer { // Make a pointer from the remaining tokens auto new_begin{this->data.cbegin()}; std::advance(new_begin, index); - GenericPointer result; + GenericPointer result; std::copy(new_begin, this->data.cend(), std::back_inserter(result.data)); return result; } /// Compare JSON Pointer instances - auto operator==(const GenericPointer &other) const noexcept + auto operator==(const GenericPointer &other) const noexcept -> bool { return this->data == other.data; } /// Overload to support ordering of JSON Pointers. Typically for sorting /// reasons. - auto operator<(const GenericPointer &other) const noexcept + auto operator<(const GenericPointer &other) const noexcept -> bool { return this->data < other.data; } diff --git a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_position.h b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_position.h index 1d9893ee2..822985970 100644 --- a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_position.h +++ b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_position.h @@ -43,7 +43,7 @@ namespace sourcemeta::jsontoolkit { /// ``` class SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT PositionTracker { public: - using Pointer = GenericPointer; + using Pointer = GenericPointer>; using Position = std::tuple; auto operator()(const CallbackPhase phase, const JSON::Type, diff --git a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_token.h b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_token.h index 4b9eb2064..de27fa95b 100644 --- a/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_token.h +++ b/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_token.h @@ -18,7 +18,7 @@ template class GenericToken { /// precomputed hash. This is advanced functionality that should be used with /// care. GenericToken(const Property &value, - const typename Hash::property_hash_type property_hash) + const typename Hash::hash_type property_hash) : as_property{true}, property{value}, hash{property_hash}, index{0} {} /// This constructor creates an JSON Pointer token from a string. For @@ -172,7 +172,7 @@ template class GenericToken { /// assert(token.property_hash() >= 0); /// ``` [[nodiscard]] auto property_hash() const noexcept -> - typename Hash::property_hash_type { + typename Hash::hash_type { assert(this->is_property()); return this->hash; } @@ -271,7 +271,7 @@ template class GenericToken { bool as_property; Property property; - typename Hash::property_hash_type hash; + typename Hash::hash_type hash; Index index; }; diff --git a/src/jsonpointer/jsonpointer.cc b/src/jsonpointer/jsonpointer.cc index 623123933..f09b8605f 100644 --- a/src/jsonpointer/jsonpointer.cc +++ b/src/jsonpointer/jsonpointer.cc @@ -15,8 +15,9 @@ namespace { template