From b17d40401e3d1ad174286669a236f841dc1dd878 Mon Sep 17 00:00:00 2001 From: "Dr. Patrick Urbanke" Date: Tue, 21 Jul 2026 20:13:42 +0200 Subject: [PATCH] Support sets with custom compare and allocater; fixes #690 --- include/rfl/parsing/is_set_like.hpp | 19 ++++---- ...t_with_custom_comparator_and_allocator.cpp | 32 +++++++++++++ ...t_with_custom_comparator_and_allocator.cpp | 31 +++++++++++++ ...ultiset_with_custom_hash_and_allocator.cpp | 45 +++++++++++++++++++ ...red_set_with_custom_hash_and_allocator.cpp | 45 +++++++++++++++++++ 5 files changed, 164 insertions(+), 8 deletions(-) create mode 100644 tests/json/test_multiset_with_custom_comparator_and_allocator.cpp create mode 100644 tests/json/test_set_with_custom_comparator_and_allocator.cpp create mode 100644 tests/json/test_unordered_multiset_with_custom_hash_and_allocator.cpp create mode 100644 tests/json/test_unordered_set_with_custom_hash_and_allocator.cpp diff --git a/include/rfl/parsing/is_set_like.hpp b/include/rfl/parsing/is_set_like.hpp index ed9b2066c..703efd8f5 100644 --- a/include/rfl/parsing/is_set_like.hpp +++ b/include/rfl/parsing/is_set_like.hpp @@ -19,17 +19,20 @@ class is_set_like; template class is_set_like : public std::false_type {}; -template -class is_set_like> : public std::true_type {}; +template +class is_set_like> : public std::true_type {}; -template -class is_set_like> : public std::true_type {}; +template +class is_set_like> + : public std::true_type {}; -template -class is_set_like> : public std::true_type {}; +template +class is_set_like> + : public std::true_type {}; -template -class is_set_like> : public std::true_type {}; +template +class is_set_like> + : public std::true_type {}; template constexpr bool is_set_like_v = diff --git a/tests/json/test_multiset_with_custom_comparator_and_allocator.cpp b/tests/json/test_multiset_with_custom_comparator_and_allocator.cpp new file mode 100644 index 000000000..ba5bc7402 --- /dev/null +++ b/tests/json/test_multiset_with_custom_comparator_and_allocator.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_multiset_with_custom_comparator_and_allocator { + +struct CustomLess { + bool operator()(const int& a, const int& b) const { return a < b; } +}; + +struct Person { + rfl::Rename<"firstName", std::string> first_name; + rfl::Rename<"lastName", std::string> last_name = "Simpson"; + std::unique_ptr>> ages; +}; + +TEST(json, test_multiset_with_custom_comparator_and_allocator) { + auto ages = + std::make_unique>>( + std::multiset>({20, 30, 30, 40})); + + const auto homer = + Person{.first_name = "Homer", .ages = std::move(ages)}; + + write_and_read( + homer, + R"({"firstName":"Homer","lastName":"Simpson","ages":[20,30,30,40]})"); +} +} // namespace test_multiset_with_custom_comparator_and_allocator diff --git a/tests/json/test_set_with_custom_comparator_and_allocator.cpp b/tests/json/test_set_with_custom_comparator_and_allocator.cpp new file mode 100644 index 000000000..9a513068a --- /dev/null +++ b/tests/json/test_set_with_custom_comparator_and_allocator.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_set_with_custom_comparator_and_allocator { + +struct CustomLess { + bool operator()(const int& a, const int& b) const { return a < b; } +}; + +struct Person { + rfl::Rename<"firstName", std::string> first_name; + rfl::Rename<"lastName", std::string> last_name = "Simpson"; + std::unique_ptr>> ages; +}; + +TEST(json, test_set_with_custom_comparator_and_allocator) { + auto ages = std::make_unique>>( + std::set>({20, 30, 40})); + + const auto homer = + Person{.first_name = "Homer", .ages = std::move(ages)}; + + write_and_read( + homer, + R"({"firstName":"Homer","lastName":"Simpson","ages":[20,30,40]})"); +} +} // namespace test_set_with_custom_comparator_and_allocator diff --git a/tests/json/test_unordered_multiset_with_custom_hash_and_allocator.cpp b/tests/json/test_unordered_multiset_with_custom_hash_and_allocator.cpp new file mode 100644 index 000000000..dc54e92ae --- /dev/null +++ b/tests/json/test_unordered_multiset_with_custom_hash_and_allocator.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_unordered_multiset_with_custom_hash_and_allocator { + +template +struct DummyHash { + std::size_t operator()(const T& v) const { return std::hash()(v); } +}; + +template +struct DummyKeyEqual { + bool operator()(const T& a, const T& b) const { return a == b; } +}; + +struct Person { + rfl::Rename<"firstName", std::string> first_name; + rfl::Rename<"lastName", std::string> last_name = "Simpson"; + std::unique_ptr< + std::unordered_multiset, DummyKeyEqual, + std::allocator>> + ages; +}; + +TEST(json, test_unordered_multiset_with_custom_hash_and_allocator) { + auto ages = std::make_unique< + std::unordered_multiset, DummyKeyEqual, + std::allocator>>( + std::unordered_multiset, DummyKeyEqual, + std::allocator>({20, 30, 30, 40})); + + const auto homer = + Person{.first_name = "Homer", .ages = std::move(ages)}; + + // Unordered multisets are unpredictable. We therefore only make sure that + // this compiles. + const auto json_string = rfl::json::write(homer); + const auto homer2 = rfl::json::read(json_string); + EXPECT_TRUE(homer2 && true); +} +} // namespace test_unordered_multiset_with_custom_hash_and_allocator diff --git a/tests/json/test_unordered_set_with_custom_hash_and_allocator.cpp b/tests/json/test_unordered_set_with_custom_hash_and_allocator.cpp new file mode 100644 index 000000000..00fa7788f --- /dev/null +++ b/tests/json/test_unordered_set_with_custom_hash_and_allocator.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_unordered_set_with_custom_hash_and_allocator { + +template +struct DummyHash { + std::size_t operator()(const T& v) const { return std::hash()(v); } +}; + +template +struct DummyKeyEqual { + bool operator()(const T& a, const T& b) const { return a == b; } +}; + +struct Person { + rfl::Rename<"firstName", std::string> first_name; + rfl::Rename<"lastName", std::string> last_name = "Simpson"; + std::unique_ptr< + std::unordered_set, DummyKeyEqual, + std::allocator>> + ages; +}; + +TEST(json, test_unordered_set_with_custom_hash_and_allocator) { + auto ages = std::make_unique< + std::unordered_set, DummyKeyEqual, + std::allocator>>( + std::unordered_set, DummyKeyEqual, + std::allocator>({20, 30, 40})); + + const auto homer = + Person{.first_name = "Homer", .ages = std::move(ages)}; + + // Unordered sets are unpredictable. We therefore only make sure that this + // compiles. + const auto json_string = rfl::json::write(homer); + const auto homer2 = rfl::json::read(json_string); + EXPECT_TRUE(homer2 && true); +} +} // namespace test_unordered_set_with_custom_hash_and_allocator