Skip to content

Commit 3edd648

Browse files
committed
Merge #379: type: Accept any comparator, hash, and allocator in container fields
9a42d00 type: Accept any comparator, hash, and allocator in container fields (Ryan Ofsky) Pull request description: **Problem:** `std::vector`, `std::set`, `std::map` and `std::unordered_set` fields and parameters only work when they use the default comparator, hash and allocator types. Anything else, like Bitcoin Core's `GCSFilter::ElementSet` (`std::unordered_set<Element, ByteVectorHash>`), fails to compile with "no matching function for call to CustomBuildField". Bitcoin Core currently works around this by copying the `std::unordered_set` read and build functions into its own code (bitcoin/bitcoin#29409). **Solution:** Make the container overloads in `type-vector.h`, `type-set.h`, `type-map.h` and `type-unordered-set.h` templates over the containers' comparator, hash and allocator types. Small change to the four headers, plus a `FooStruct` round-trip test with a descending `std::set` and `std::map`, an `std::unordered_set` with a custom hash, and a `std::pmr::vector`. ACKs for top commit: xyzconstant: ACK 9a42d00 Tree-SHA512: 53f791f3aa0d70a29d89be1335fb68d088c6f59d90cd6f2c18a2a01eeab968bb77615a6a81699b0202bedad49bb427acdfbe743cc75b6a4ed517db5eae2c9a7a
2 parents 796dd74 + 9a42d00 commit 3edd648

7 files changed

Lines changed: 41 additions & 16 deletions

File tree

‎include/mp/type-map.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
#include <map>
1313

1414
namespace mp {
15-
template <typename KeyLocalType, typename ValueLocalType, typename Value, typename Output>
16-
void CustomBuildField(TypeList<std::map<KeyLocalType, ValueLocalType>>,
15+
template <typename KeyLocalType, typename ValueLocalType, typename Compare, typename Allocator, typename Value, typename Output>
16+
void CustomBuildField(TypeList<std::map<KeyLocalType, ValueLocalType, Compare, Allocator>>,
1717
Priority<1>,
1818
InvokeContext& invoke_context,
1919
Value&& value,
@@ -51,8 +51,8 @@ auto EmplacePiecewiseSafe(
5151
}
5252
}
5353

54-
template <typename KeyLocalType, typename ValueLocalType, typename Input, typename ReadDest>
55-
decltype(auto) CustomReadField(TypeList<std::map<KeyLocalType, ValueLocalType>>,
54+
template <typename KeyLocalType, typename ValueLocalType, typename Compare, typename Allocator, typename Input, typename ReadDest>
55+
decltype(auto) CustomReadField(TypeList<std::map<KeyLocalType, ValueLocalType, Compare, Allocator>>,
5656
Priority<1>,
5757
InvokeContext& invoke_context,
5858
Input&& input,

‎include/mp/type-set.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#include <mp/util.h>
1010

1111
namespace mp {
12-
template <typename LocalType, typename Value, typename Output>
13-
void CustomBuildField(TypeList<std::set<LocalType>>,
12+
template <typename LocalType, typename Compare, typename Allocator, typename Value, typename Output>
13+
void CustomBuildField(TypeList<std::set<LocalType, Compare, Allocator>>,
1414
Priority<1>,
1515
InvokeContext& invoke_context,
1616
Value&& value,
@@ -19,8 +19,8 @@ void CustomBuildField(TypeList<std::set<LocalType>>,
1919
BuildList(TypeList<LocalType>(), invoke_context, output, value);
2020
}
2121

22-
template <typename LocalType, typename Input, typename ReadDest>
23-
decltype(auto) CustomReadField(TypeList<std::set<LocalType>>,
22+
template <typename LocalType, typename Compare, typename Allocator, typename Input, typename ReadDest>
23+
decltype(auto) CustomReadField(TypeList<std::set<LocalType, Compare, Allocator>>,
2424
Priority<1>,
2525
InvokeContext& invoke_context,
2626
Input&& input,

‎include/mp/type-unordered-set.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
#include <unordered_set>
1111

1212
namespace mp {
13-
template <typename LocalType, typename Value, typename Output>
14-
void CustomBuildField(TypeList<std::unordered_set<LocalType>>,
13+
template <typename LocalType, typename Hash, typename KeyEqual, typename Allocator, typename Value, typename Output>
14+
void CustomBuildField(TypeList<std::unordered_set<LocalType, Hash, KeyEqual, Allocator>>,
1515
Priority<1>,
1616
InvokeContext& invoke_context,
1717
Value&& value,
@@ -20,8 +20,8 @@ void CustomBuildField(TypeList<std::unordered_set<LocalType>>,
2020
BuildList(TypeList<LocalType>(), invoke_context, output, value);
2121
}
2222

23-
template <typename LocalType, typename Input, typename ReadDest>
24-
decltype(auto) CustomReadField(TypeList<std::unordered_set<LocalType>>,
23+
template <typename LocalType, typename Hash, typename KeyEqual, typename Allocator, typename Input, typename ReadDest>
24+
decltype(auto) CustomReadField(TypeList<std::unordered_set<LocalType, Hash, KeyEqual, Allocator>>,
2525
Priority<1>,
2626
InvokeContext& invoke_context,
2727
Input&& input,

‎include/mp/type-vector.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#include <mp/util.h>
1010

1111
namespace mp {
12-
template <typename LocalType, typename Value, typename Output>
13-
void CustomBuildField(TypeList<std::vector<LocalType>>,
12+
template <typename LocalType, typename Allocator, typename Value, typename Output>
13+
void CustomBuildField(TypeList<std::vector<LocalType, Allocator>>,
1414
Priority<1>,
1515
InvokeContext& invoke_context,
1616
Value&& value,
@@ -24,8 +24,8 @@ inline static bool BuildPrimitive(InvokeContext&, std::vector<bool>::const_refer
2424
return value;
2525
}
2626

27-
template <typename LocalType, typename Input, typename ReadDest>
28-
decltype(auto) CustomReadField(TypeList<std::vector<LocalType>>,
27+
template <typename LocalType, typename Allocator, typename Input, typename ReadDest>
28+
decltype(auto) CustomReadField(TypeList<std::vector<LocalType, Allocator>>,
2929
Priority<1>,
3030
InvokeContext& invoke_context,
3131
Input&& input,

‎test/mp/test/foo.capnp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ struct FooStruct $Proxy.wrap("mp::test::FooStruct") {
7272
hasOptionalInt @4 :Bool;
7373
unorderedSetInt @5 :List(Int32) $Proxy.name("unordered_set_int");
7474
mapStringInt @6 :List(StringIntPair) $Proxy.name("map_string_int");
75+
setIntDesc @7 :List(Int32) $Proxy.name("set_int_desc");
76+
pmrVectorInt @8 :List(Int32) $Proxy.name("pmr_vector_int");
77+
unorderedSetStringHash @9 :List(Text) $Proxy.name("unordered_set_string_hash");
78+
mapStringIntDesc @10 :List(StringIntPair) $Proxy.name("map_string_int_desc");
7579
}
7680

7781
struct FooCustom $Proxy.wrap("mp::test::FooCustom") {

‎test/mp/test/foo.h‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
#define MP_TEST_FOO_H
77

88
#include <cassert>
9+
#include <cstddef>
910
#include <functional>
1011
#include <map>
1112
#include <memory>
13+
#include <memory_resource>
1214
#include <optional>
1315
#include <string>
1416
#include <set>
@@ -18,6 +20,12 @@
1820
namespace mp {
1921
namespace test {
2022

23+
//! Hash function used to test std::unordered_set with a custom hash.
24+
struct FooHash
25+
{
26+
size_t operator()(const std::string& str) const { return str.size(); }
27+
};
28+
2129
struct FooStruct
2230
{
2331
std::string name;
@@ -26,6 +34,11 @@ struct FooStruct
2634
std::optional<int> optional_int;
2735
std::unordered_set<int> unordered_set_int;
2836
std::map<std::string, int> map_string_int;
37+
// Containers with non-default comparator, allocator, and hash types.
38+
std::set<int, std::greater<>> set_int_desc;
39+
std::pmr::vector<int> pmr_vector_int;
40+
std::unordered_set<std::string, FooHash> unordered_set_string_hash;
41+
std::map<std::string, int, std::greater<>> map_string_int_desc;
2942
};
3043

3144
enum class FooEnum : uint8_t { ONE = 1, TWO = 2, };

‎test/mp/test/test.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ KJ_TEST("Call FooInterface methods")
174174
in.optional_int = 3;
175175
in.map_string_int.emplace("a", 1);
176176
in.map_string_int.emplace("b", 2);
177+
in.set_int_desc = {1, 2, 3};
178+
in.pmr_vector_int = {3, 1, 2};
179+
in.unordered_set_string_hash = {"a", "bb"};
180+
in.map_string_int_desc = {{"a", 1}, {"b", 2}};
177181
FooStruct out = foo->pass(in);
178182
KJ_EXPECT(in.name == out.name);
179183
KJ_EXPECT(in.set_int.size() == out.set_int.size());
@@ -194,6 +198,10 @@ KJ_TEST("Call FooInterface methods")
194198
KJ_EXPECT(init->first == outit->first);
195199
KJ_EXPECT(init->second == outit->second);
196200
}
201+
KJ_EXPECT(in.set_int_desc == out.set_int_desc);
202+
KJ_EXPECT(in.pmr_vector_int == out.pmr_vector_int);
203+
KJ_EXPECT(in.unordered_set_string_hash == out.unordered_set_string_hash);
204+
KJ_EXPECT(in.map_string_int_desc == out.map_string_int_desc);
197205

198206
// Additional checks for std::optional member
199207
KJ_EXPECT(foo->pass(in).optional_int == 3);

0 commit comments

Comments
 (0)