Skip to content

Commit e7e91b2

Browse files
committed
Merge #277: Add std::unordered_set support and a helper BuildList to dedup list build handlers
9de4b88 test: use camelCase + $Proxy.name for FooStruct fields (ViniciusCestarii) 011b917 type: add std::unordered_set support (ViniciusCestarii) 20d19b9 proxy: add BuildList helper and dedup map/set/vector build handlers (ViniciusCestarii) Pull request description: Add std::unordered_set support and a helper BuildList to dedup list build handlers that is being used for map, set and vector. While looking bitcoin/bitcoin#29409, found a TODO noting that libmultiprocess lacked std::unordered_set support, requiring downstream that PR to implement the build/read functions locally. I believe there could be more dedup adding a ReadList too. I could do that as a follow-up if desirable ACKs for top commit: ryanofsky: Code review ACK 9de4b88. Only changes since last review were renaming and adding commit user better field names in the test. Tree-SHA512: cd38019656bd51dedcb718a4874c165d3d7e09eded1d961e9a034c004e5f9e150715bd1ad5c4c3504a7d9fdb29ef6c511b687bf163858a7297113f04c57cd5d8
2 parents 61de697 + 9de4b88 commit e7e91b2

9 files changed

Lines changed: 82 additions & 35 deletions

File tree

include/mp/proxy-types.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,17 @@ struct ListOutput<::capnp::List<T, kind>>
280280
// clang-format on
281281
};
282282

283+
template <typename LocalType, typename Value, typename Output>
284+
void BuildList(TypeList<LocalType>, InvokeContext& invoke_context, Output&& output, Value&& value)
285+
{
286+
auto list = output.init(value.size());
287+
size_t i = 0;
288+
for (const auto& elem : value) {
289+
BuildField(TypeList<LocalType>(), invoke_context, ListOutput<typename decltype(list)::Builds>(list, i), elem);
290+
++i;
291+
}
292+
}
293+
283294
template <typename LocalType, typename Value, typename Output>
284295
void CustomBuildField(TypeList<LocalType>, Priority<0>, InvokeContext& invoke_context, Value&& value, Output&& output)
285296
{

include/mp/type-map.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,7 @@ void CustomBuildField(TypeList<std::map<KeyLocalType, ValueLocalType>>,
1717
Value&& value,
1818
Output&& output)
1919
{
20-
// FIXME dededup with vector handler above
21-
auto list = output.init(value.size());
22-
size_t i = 0;
23-
for (const auto& elem : value) {
24-
BuildField(TypeList<std::pair<KeyLocalType, ValueLocalType>>(), invoke_context,
25-
ListOutput<typename decltype(list)::Builds>(list, i), elem);
26-
++i;
27-
}
20+
BuildList(TypeList<std::pair<KeyLocalType, ValueLocalType>>(), invoke_context, output, value);
2821
}
2922

3023
// Replacement for `m.emplace(piecewise_construct, t1, t2)` to work around a

include/mp/type-set.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,7 @@ void CustomBuildField(TypeList<std::set<LocalType>>,
1616
Value&& value,
1717
Output&& output)
1818
{
19-
// FIXME dededup with vector handler above
20-
auto list = output.init(value.size());
21-
size_t i = 0;
22-
for (const auto& elem : value) {
23-
BuildField(TypeList<LocalType>(), invoke_context, ListOutput<typename decltype(list)::Builds>(list, i), elem);
24-
++i;
25-
}
19+
BuildList(TypeList<LocalType>(), invoke_context, output, value);
2620
}
2721

2822
template <typename LocalType, typename Input, typename ReadDest>

include/mp/type-unordered-set.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef MP_PROXY_TYPE_UNORDERED_SET_H
6+
#define MP_PROXY_TYPE_UNORDERED_SET_H
7+
8+
#include <mp/proxy-types.h>
9+
#include <mp/util.h>
10+
#include <unordered_set>
11+
12+
namespace mp {
13+
template <typename LocalType, typename Value, typename Output>
14+
void CustomBuildField(TypeList<std::unordered_set<LocalType>>,
15+
Priority<1>,
16+
InvokeContext& invoke_context,
17+
Value&& value,
18+
Output&& output)
19+
{
20+
BuildList(TypeList<LocalType>(), invoke_context, output, value);
21+
}
22+
23+
template <typename LocalType, typename Input, typename ReadDest>
24+
decltype(auto) CustomReadField(TypeList<std::unordered_set<LocalType>>,
25+
Priority<1>,
26+
InvokeContext& invoke_context,
27+
Input&& input,
28+
ReadDest&& read_dest)
29+
{
30+
return read_dest.update([&](auto& value) {
31+
auto data = input.get();
32+
value.clear();
33+
for (auto item : data) {
34+
ReadField(TypeList<LocalType>(), invoke_context, Make<ValueField>(item),
35+
ReadDestEmplace(TypeList<const LocalType>(), [&](auto&&... args) -> auto& {
36+
return *value.emplace(std::forward<decltype(args)>(args)...).first;
37+
}));
38+
}
39+
});
40+
}
41+
} // namespace mp
42+
43+
#endif // MP_PROXY_TYPE_UNORDERED_SET_H

include/mp/type-vector.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ void CustomBuildField(TypeList<std::vector<LocalType>>,
1616
Value&& value,
1717
Output&& output)
1818
{
19-
// FIXME dedup with set handler below
20-
auto list = output.init(value.size());
21-
size_t i = 0;
22-
for (auto it = value.begin(); it != value.end(); ++it, ++i) {
23-
BuildField(TypeList<LocalType>(), invoke_context, ListOutput<typename decltype(list)::Builds>(list, i), *it);
24-
}
19+
BuildList(TypeList<LocalType>(), invoke_context, output, value);
2520
}
2621

2722
inline static bool BuildPrimitive(InvokeContext& invoke_context, std::vector<bool>::const_reference value, TypeList<bool>)

test/mp/test/foo-types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <mp/type-string.h>
2727
#include <mp/type-struct.h>
2828
#include <mp/type-threadmap.h>
29+
#include <mp/type-unordered-set.h>
2930
#include <mp/type-vector.h>
3031
#include <string>
3132
#include <type_traits>

test/mp/test/foo.capnp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ interface FooFn $Proxy.wrap("ProxyCallback<std::function<int()>>") {
5353

5454
struct FooStruct $Proxy.wrap("mp::test::FooStruct") {
5555
name @0 :Text;
56-
setint @1 :List(Int32);
57-
vbool @2 :List(Bool);
56+
setInt @1 :List(Int32) $Proxy.name("set_int");
57+
vBool @2 :List(Bool) $Proxy.name("v_bool");
5858
optionalInt @3 :Int32 $Proxy.name("optional_int");
5959
hasOptionalInt @4 :Bool;
60+
unorderedSetInt @5 :List(Int32) $Proxy.name("unordered_set_int");
6061
}
6162

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

test/mp/test/foo.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <optional>
1313
#include <string>
1414
#include <set>
15+
#include <unordered_set>
1516
#include <vector>
1617

1718
namespace mp {
@@ -20,9 +21,10 @@ namespace test {
2021
struct FooStruct
2122
{
2223
std::string name;
23-
std::set<int> setint;
24-
std::vector<bool> vbool;
24+
std::set<int> set_int;
25+
std::vector<bool> v_bool;
2526
std::optional<int> optional_int;
27+
std::unordered_set<int> unordered_set_int;
2628
};
2729

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

test/mp/test/test.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <string_view>
3535
#include <thread>
3636
#include <type_traits>
37+
#include <unordered_set>
3738
#include <utility>
3839
#include <vector>
3940

@@ -141,21 +142,27 @@ KJ_TEST("Call FooInterface methods")
141142

142143
FooStruct in;
143144
in.name = "name";
144-
in.setint.insert(2);
145-
in.setint.insert(1);
146-
in.vbool.push_back(false);
147-
in.vbool.push_back(true);
148-
in.vbool.push_back(false);
145+
in.set_int.insert(2);
146+
in.set_int.insert(1);
147+
in.unordered_set_int.insert(2);
148+
in.unordered_set_int.insert(1);
149+
in.v_bool.push_back(false);
150+
in.v_bool.push_back(true);
151+
in.v_bool.push_back(false);
149152
in.optional_int = 3;
150153
FooStruct out = foo->pass(in);
151154
KJ_EXPECT(in.name == out.name);
152-
KJ_EXPECT(in.setint.size() == out.setint.size());
153-
for (auto init{in.setint.begin()}, outit{out.setint.begin()}; init != in.setint.end() && outit != out.setint.end(); ++init, ++outit) {
155+
KJ_EXPECT(in.set_int.size() == out.set_int.size());
156+
for (auto init{in.set_int.begin()}, outit{out.set_int.begin()}; init != in.set_int.end() && outit != out.set_int.end(); ++init, ++outit) {
154157
KJ_EXPECT(*init == *outit);
155158
}
156-
KJ_EXPECT(in.vbool.size() == out.vbool.size());
157-
for (size_t i = 0; i < in.vbool.size(); ++i) {
158-
KJ_EXPECT(in.vbool[i] == out.vbool[i]);
159+
KJ_EXPECT(in.unordered_set_int.size() == out.unordered_set_int.size());
160+
for (const auto& elem : in.unordered_set_int) {
161+
KJ_EXPECT(out.unordered_set_int.count(elem) == 1);
162+
}
163+
KJ_EXPECT(in.v_bool.size() == out.v_bool.size());
164+
for (size_t i = 0; i < in.v_bool.size(); ++i) {
165+
KJ_EXPECT(in.v_bool[i] == out.v_bool[i]);
159166
}
160167
KJ_EXPECT(in.optional_int == out.optional_int);
161168

0 commit comments

Comments
 (0)