Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consume FlatMap from Noa #1455

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
5 changes: 4 additions & 1 deletion src/json/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
34 changes: 19 additions & 15 deletions src/json/include/sourcemeta/jsontoolkit/json_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,29 @@ template <typename T> 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 <typename T> 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) {
Expand All @@ -47,13 +46,18 @@ template <typename T> 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<typename property_hash_type::type>(value.front()) +
static_cast<typename property_hash_type::type>(value.back())) %
return {(size + static_cast<typename hash_type::type>(value.front()) +
static_cast<typename hash_type::type>(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
Expand Down
4 changes: 2 additions & 2 deletions src/json/include/sourcemeta/jsontoolkit/json_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
#include <functional> // std::equal_to, std::less
#include <initializer_list> // std::initializer_list

#include <sourcemeta/jsontoolkit/json_flat_map.h>
#include <sourcemeta/noa/flat_map.h>

namespace sourcemeta::jsontoolkit {

/// @ingroup json
template <typename Key, typename Value, typename Hash> class JSONObject {
public:
// Constructors
using Container = FlatMap<Key, Value, Hash>;
using Container = sourcemeta::noa::FlatMap<Key, Value, Hash>;

JSONObject() : data{} {}
JSONObject(std::initializer_list<typename Container::value_type> values)
Expand Down
2 changes: 1 addition & 1 deletion src/json/include/sourcemeta/jsontoolkit/json_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class SOURCEMETA_JSONTOOLKIT_JSON_EXPORT JSON {
/// The array type used by the JSON document.
using Array = JSONArray<JSON>;
/// The object type used by the JSON document.
using Object = JSONObject<String, JSON, FastHash<JSON>>;
using Object = JSONObject<String, JSON, KeyHash<JSON::String>>;

/*
* Constructors
Expand Down
5 changes: 3 additions & 2 deletions src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
namespace sourcemeta::jsontoolkit {

/// @ingroup jsonpointer
using Pointer = GenericPointer<JSON::String>;
using Pointer = GenericPointer<JSON::String, KeyHash<JSON::String>>;

/// @ingroup jsonpointer
using WeakPointer = GenericPointer<std::reference_wrapper<const std::string>>;
using WeakPointer = GenericPointer<std::reference_wrapper<const std::string>,
KeyHash<JSON::String>>;

/// @ingroup jsonpointer
/// A global constant instance of the empty JSON Pointer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
namespace sourcemeta::jsontoolkit {

/// @ingroup jsonpointer
template <typename PropertyT> class GenericPointer {
template <typename PropertyT, typename Hash> class GenericPointer {
public:
using Token = GenericToken<PropertyT, Hash>;
using Value = typename Token::Value;
Expand Down Expand Up @@ -206,7 +206,7 @@ template <typename PropertyT> class GenericPointer {
/// assert(pointer.at(1).to_property() == "bar");
/// assert(pointer.at(2).to_property() == "baz");
/// ```
auto push_back(const GenericPointer<PropertyT> &other) -> void {
auto push_back(const GenericPointer<PropertyT, Hash> &other) -> void {
if (other.empty()) {
return;
} else if (other.size() == 1) {
Expand Down Expand Up @@ -239,7 +239,7 @@ template <typename PropertyT> class GenericPointer {
/// assert(pointer.at(1).to_property() == "bar");
/// assert(pointer.at(2).to_property() == "baz");
/// ```
auto push_back(GenericPointer<PropertyT> &&other) -> void {
auto push_back(GenericPointer<PropertyT, Hash> &&other) -> void {
if (other.empty()) {
return;
} else if (other.size() == 1) {
Expand Down Expand Up @@ -277,7 +277,7 @@ template <typename PropertyT> class GenericPointer {
template <typename OtherT,
typename = std::enable_if_t<std::is_same_v<
PropertyT, std::reference_wrapper<const OtherT>>>>
auto push_back(const GenericPointer<OtherT> &other) -> void {
auto push_back(const GenericPointer<OtherT, Hash> &other) -> void {
if (other.empty()) {
return;
} else if (other.size() == 1) {
Expand Down Expand Up @@ -422,9 +422,9 @@ template <typename PropertyT> class GenericPointer {
/// assert(pointer.at(1).is_property());
/// assert(pointer.at(1).to_property() == "bar");
/// ```
[[nodiscard]] auto initial() const -> GenericPointer<PropertyT> {
[[nodiscard]] auto initial() const -> GenericPointer<PropertyT, Hash> {
assert(!this->empty());
GenericPointer<PropertyT> result{*this};
GenericPointer<PropertyT, Hash> result{*this};
result.pop_back();
return result;
}
Expand All @@ -441,9 +441,9 @@ template <typename PropertyT> class GenericPointer {
/// assert(left.concat(right) ==
/// sourcemeta::jsontoolkit::Pointer{"foo", "bar", "baz"});
/// ```
auto concat(const GenericPointer<PropertyT> &other) const
-> GenericPointer<PropertyT> {
GenericPointer<PropertyT> result{*this};
auto concat(const GenericPointer<PropertyT, Hash> &other) const
-> GenericPointer<PropertyT, Hash> {
GenericPointer<PropertyT, Hash> result{*this};
result.push_back(other);
return result;
}
Expand All @@ -459,7 +459,7 @@ template <typename PropertyT> class GenericPointer {
/// const sourcemeta::jsontoolkit::Pointer prefix{"foo", "bar"};
/// assert(pointer.starts_with(prefix));
/// ```
auto starts_with(const GenericPointer<PropertyT> &other) const -> bool {
auto starts_with(const GenericPointer<PropertyT, Hash> &other) const -> bool {
return other.data.size() <= this->data.size() &&
std::equal(other.data.cbegin(), other.data.cend(),
this->data.cbegin());
Expand All @@ -477,7 +477,7 @@ template <typename PropertyT> class GenericPointer {
/// const sourcemeta::jsontoolkit::Pointer prefix{"foo", "bar", "baz"};
/// assert(pointer.starts_with(prefix, tail));
/// ```
auto starts_with(const GenericPointer<PropertyT> &other,
auto starts_with(const GenericPointer<PropertyT, Hash> &other,
const Token &tail) const -> bool {
if (other.size() == this->size() + 1) {
assert(!other.empty());
Expand All @@ -498,7 +498,7 @@ template <typename PropertyT> class GenericPointer {
/// const sourcemeta::jsontoolkit::Pointer prefix{"foo", "bar", "qux"};
/// assert(pointer.starts_with_initial(prefix));
/// ```
auto starts_with_initial(const GenericPointer<PropertyT> &other) const
auto starts_with_initial(const GenericPointer<PropertyT, Hash> &other) const
-> bool {
const auto prefix_size{other.size()};
if (prefix_size == 0) {
Expand Down Expand Up @@ -529,9 +529,9 @@ template <typename PropertyT> class GenericPointer {
/// assert(pointer.rebase(prefix, replacement) ==
/// sourcemeta::jsontoolkit::Pointer{"qux", "baz"});
/// ```
auto rebase(const GenericPointer<PropertyT> &prefix,
const GenericPointer<PropertyT> &replacement) const
-> GenericPointer<PropertyT> {
auto rebase(const GenericPointer<PropertyT, Hash> &prefix,
const GenericPointer<PropertyT, Hash> &replacement) const
-> GenericPointer<PropertyT, Hash> {
typename Container::size_type index{0};
while (index < prefix.size()) {
if (index >= this->size() || prefix.data[index] != this->data[index]) {
Expand All @@ -545,7 +545,7 @@ template <typename PropertyT> class GenericPointer {
assert(this->starts_with(prefix));
auto new_begin{this->data.cbegin()};
std::advance(new_begin, index);
GenericPointer<PropertyT> result{replacement};
GenericPointer<PropertyT, Hash> result{replacement};
std::copy(new_begin, this->data.cend(), std::back_inserter(result.data));
return result;
}
Expand All @@ -564,8 +564,8 @@ template <typename PropertyT> 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<PropertyT> &base) const
-> GenericPointer<PropertyT> {
auto resolve_from(const GenericPointer<PropertyT, Hash> &base) const
-> GenericPointer<PropertyT, Hash> {
typename Container::size_type index{0};
while (index < base.size()) {
if (index >= this->size() || base.data[index] != this->data[index]) {
Expand All @@ -578,20 +578,20 @@ template <typename PropertyT> class GenericPointer {
// Make a pointer from the remaining tokens
auto new_begin{this->data.cbegin()};
std::advance(new_begin, index);
GenericPointer<PropertyT> result;
GenericPointer<PropertyT, Hash> result;
std::copy(new_begin, this->data.cend(), std::back_inserter(result.data));
return result;
}

/// Compare JSON Pointer instances
auto operator==(const GenericPointer<PropertyT> &other) const noexcept
auto operator==(const GenericPointer<PropertyT, Hash> &other) const noexcept
-> bool {
return this->data == other.data;
}

/// Overload to support ordering of JSON Pointers. Typically for sorting
/// reasons.
auto operator<(const GenericPointer<PropertyT> &other) const noexcept
auto operator<(const GenericPointer<PropertyT, Hash> &other) const noexcept
-> bool {
return this->data < other.data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace sourcemeta::jsontoolkit {
/// ```
class SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT PositionTracker {
public:
using Pointer = GenericPointer<JSON::String>;
using Pointer = GenericPointer<JSON::String, KeyHash<JSON::String>>;
using Position =
std::tuple<std::uint64_t, std::uint64_t, std::uint64_t, std::uint64_t>;
auto operator()(const CallbackPhase phase, const JSON::Type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ template <typename PropertyT, typename Hash> 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
Expand Down Expand Up @@ -172,7 +172,7 @@ template <typename PropertyT, typename Hash> 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;
}
Expand Down Expand Up @@ -271,7 +271,7 @@ template <typename PropertyT, typename Hash> class GenericToken {

bool as_property;
Property property;
typename Hash::property_hash_type hash;
typename Hash::hash_type hash;
Index index;
};

Expand Down
10 changes: 6 additions & 4 deletions src/jsonpointer/jsonpointer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
namespace {

template <template <typename T> typename Allocator, typename V,
typename PointerT =
sourcemeta::jsontoolkit::GenericPointer<typename V::String>>
typename PointerT = sourcemeta::jsontoolkit::GenericPointer<
typename V::String,
sourcemeta::jsontoolkit::KeyHash<typename V::String>>>
auto traverse(V &document, typename PointerT::const_iterator begin,
typename PointerT::const_iterator end) -> V & {
// Make sure types match
Expand Down Expand Up @@ -62,8 +63,9 @@ auto traverse(V &document, typename PointerT::const_iterator begin,
// A variant of the above function that assumes traversing of
// the entire pointer and does not rely on iterators for performance reasons
template <template <typename T> typename Allocator, typename V,
typename PointerT =
sourcemeta::jsontoolkit::GenericPointer<typename V::String>>
typename PointerT = sourcemeta::jsontoolkit::GenericPointer<
typename V::String,
sourcemeta::jsontoolkit::KeyHash<typename V::String>>>
auto traverse_all(V &document, const PointerT &pointer) -> V & {
// Make sure types match
static_assert(
Expand Down
7 changes: 3 additions & 4 deletions test/json/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
noa_googletest(NAMESPACE sourcemeta PROJECT jsontoolkit NAME json
FOLDER "JSON Toolkit/JSON"
noa_googletest(NAMESPACE sourcemeta PROJECT jsontoolkit NAME json
FOLDER "JSON Toolkit/JSON"
SOURCES
json_array_test.cc
json_boolean_test.cc
json_error_test.cc
json_flat_map_test.cc
json_hash_test.cc
json_integer_test.cc
json_null_test.cc
Expand All @@ -28,7 +27,7 @@ target_compile_definitions(sourcemeta_jsontoolkit_json_unit
# JSON Test Suite
# See https://github.com/nst/JSONTestSuite
noa_googletest(NAMESPACE sourcemeta PROJECT jsontoolkit NAME jsontestsuite
FOLDER "JSON Toolkit/JSON"
FOLDER "JSON Toolkit/JSON"
SOURCES jsontestsuite.cc)
target_compile_definitions(sourcemeta_jsontoolkit_jsontestsuite_unit
PRIVATE JSONTESTSUITE_PATH="${PROJECT_SOURCE_DIR}/vendor/jsontestsuite")
Expand Down
Loading
Loading