diff --git a/include/mp/proxy-types.h b/include/mp/proxy-types.h index 70b0538..c8936f4 100644 --- a/include/mp/proxy-types.h +++ b/include/mp/proxy-types.h @@ -280,6 +280,30 @@ struct ListOutput<::capnp::List> // clang-format on }; +template +void BuildList(TypeList, InvokeContext& invoke_context, Output&& output, Value&& value) +{ + auto list = output.init(value.size()); + size_t i = 0; + for (const auto& elem : value) { + BuildField(TypeList(), invoke_context, ListOutput(list, i), elem); + ++i; + } +} + +template +void ReadList(TypeList, InvokeContext& invoke_context, Input&& input, InitFn&& init, EmplaceFn&& emplace) +{ + auto data = input.get(); + init(data.size()); + for (auto item : data) { + ReadField(TypeList(), invoke_context, Make(item), + ReadDestEmplace(TypeList(), [&emplace](auto&&... args) -> decltype(auto) { + return emplace(std::forward(args)...); + })); + } +} + template void CustomBuildField(TypeList, Priority<0>, InvokeContext& invoke_context, Value&& value, Output&& output) { diff --git a/include/mp/type-map.h b/include/mp/type-map.h index 50a590c..2b79e67 100644 --- a/include/mp/type-map.h +++ b/include/mp/type-map.h @@ -17,14 +17,7 @@ void CustomBuildField(TypeList>, Value&& value, Output&& output) { - // FIXME dededup with vector handler above - auto list = output.init(value.size()); - size_t i = 0; - for (const auto& elem : value) { - BuildField(TypeList>(), invoke_context, - ListOutput(list, i), elem); - ++i; - } + BuildList(TypeList>(), invoke_context, output, value); } // Replacement for `m.emplace(piecewise_construct, t1, t2)` to work around a @@ -64,16 +57,12 @@ decltype(auto) CustomReadField(TypeList>, ReadDest&& read_dest) { return read_dest.update([&](auto& value) { - auto data = input.get(); - value.clear(); - for (auto item : data) { - ReadField(TypeList>(), invoke_context, - Make(item), - ReadDestEmplace( - TypeList>(), [&](auto&&... args) -> auto& { - return *EmplacePiecewiseSafe(value, std::forward(args)...).first; - })); - } + ReadList( + TypeList>(), invoke_context, input, + [&](size_t) { value.clear(); }, + [&](auto&&... args) -> auto& { + return *EmplacePiecewiseSafe(value, std::forward(args)...).first; + }); }); } } // namespace mp diff --git a/include/mp/type-set.h b/include/mp/type-set.h index 699c6e9..f19dc5d 100644 --- a/include/mp/type-set.h +++ b/include/mp/type-set.h @@ -16,13 +16,7 @@ void CustomBuildField(TypeList>, Value&& value, Output&& output) { - // FIXME dededup with vector handler above - auto list = output.init(value.size()); - size_t i = 0; - for (const auto& elem : value) { - BuildField(TypeList(), invoke_context, ListOutput(list, i), elem); - ++i; - } + BuildList(TypeList(), invoke_context, output, value); } template @@ -33,14 +27,12 @@ decltype(auto) CustomReadField(TypeList>, ReadDest&& read_dest) { return read_dest.update([&](auto& value) { - auto data = input.get(); - value.clear(); - for (auto item : data) { - ReadField(TypeList(), invoke_context, Make(item), - ReadDestEmplace(TypeList(), [&](auto&&... args) -> auto& { - return *value.emplace(std::forward(args)...).first; - })); - } + ReadList( + TypeList(), invoke_context, input, + [&](size_t) { value.clear(); }, + [&](auto&&... args) -> auto& { + return *value.emplace(std::forward(args)...).first; + }); }); } } // namespace mp diff --git a/include/mp/type-unordered-set.h b/include/mp/type-unordered-set.h new file mode 100644 index 0000000..aadc4c5 --- /dev/null +++ b/include/mp/type-unordered-set.h @@ -0,0 +1,44 @@ +// Copyright (c) The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MP_PROXY_TYPE_UNORDERED_SET_H +#define MP_PROXY_TYPE_UNORDERED_SET_H + +#include +#include +#include + +namespace mp { +template +void CustomBuildField(TypeList>, + Priority<1>, + InvokeContext& invoke_context, + Value&& value, + Output&& output) +{ + BuildList(TypeList(), invoke_context, output, value); +} + +template +decltype(auto) CustomReadField(TypeList>, + Priority<1>, + InvokeContext& invoke_context, + Input&& input, + ReadDest&& read_dest) +{ + return read_dest.update([&](auto& value) { + ReadList( + TypeList(), invoke_context, input, + [&](size_t size) { + value.clear(); + value.reserve(size); + }, + [&](auto&&... args) -> auto& { + return *value.emplace(std::forward(args)...).first; + }); + }); +} +} // namespace mp + +#endif // MP_PROXY_TYPE_UNORDERED_SET_H \ No newline at end of file diff --git a/include/mp/type-vector.h b/include/mp/type-vector.h index 90605dd..854e039 100644 --- a/include/mp/type-vector.h +++ b/include/mp/type-vector.h @@ -16,12 +16,7 @@ void CustomBuildField(TypeList>, Value&& value, Output&& output) { - // FIXME dedup with set handler below - auto list = output.init(value.size()); - size_t i = 0; - for (auto it = value.begin(); it != value.end(); ++it, ++i) { - BuildField(TypeList(), invoke_context, ListOutput(list, i), *it); - } + BuildList(TypeList(), invoke_context, output, value); } inline static bool BuildPrimitive(InvokeContext& invoke_context, std::vector::const_reference value, TypeList) @@ -37,16 +32,16 @@ decltype(auto) CustomReadField(TypeList>, ReadDest&& read_dest) { return read_dest.update([&](auto& value) { - auto data = input.get(); - value.clear(); - value.reserve(data.size()); - for (auto item : data) { - ReadField(TypeList(), invoke_context, Make(item), - ReadDestEmplace(TypeList(), [&](auto&&... args) -> auto& { - value.emplace_back(std::forward(args)...); - return value.back(); - })); - } + ReadList( + TypeList(), invoke_context, input, + [&](size_t size) { + value.clear(); + value.reserve(size); + }, + [&](auto&&... args) -> auto& { + value.emplace_back(std::forward(args)...); + return value.back(); + }); }); } diff --git a/test/mp/test/foo-types.h b/test/mp/test/foo-types.h index bd5565a..b96eabf 100644 --- a/test/mp/test/foo-types.h +++ b/test/mp/test/foo-types.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/test/mp/test/foo.capnp b/test/mp/test/foo.capnp index 99e918a..562f249 100644 --- a/test/mp/test/foo.capnp +++ b/test/mp/test/foo.capnp @@ -53,10 +53,11 @@ interface FooFn $Proxy.wrap("ProxyCallback>") { struct FooStruct $Proxy.wrap("mp::test::FooStruct") { name @0 :Text; - setint @1 :List(Int32); - vbool @2 :List(Bool); + setInt @1 :List(Int32) $Proxy.name("set_int"); + vBool @2 :List(Bool) $Proxy.name("v_bool"); optionalInt @3 :Int32 $Proxy.name("optional_int"); hasOptionalInt @4 :Bool; + unorderedSetInt @5 :List(Int32) $Proxy.name("unordered_set_int"); } struct FooCustom $Proxy.wrap("mp::test::FooCustom") { diff --git a/test/mp/test/foo.h b/test/mp/test/foo.h index 4d52fd0..7ec59fc 100644 --- a/test/mp/test/foo.h +++ b/test/mp/test/foo.h @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace mp { @@ -20,9 +21,10 @@ namespace test { struct FooStruct { std::string name; - std::set setint; - std::vector vbool; + std::set set_int; + std::vector v_bool; std::optional optional_int; + std::unordered_set unordered_set_int; }; enum class FooEnum : uint8_t { ONE = 1, TWO = 2, }; diff --git a/test/mp/test/test.cpp b/test/mp/test/test.cpp index 1d3b19b..13fc8e3 100644 --- a/test/mp/test/test.cpp +++ b/test/mp/test/test.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -141,21 +142,27 @@ KJ_TEST("Call FooInterface methods") FooStruct in; in.name = "name"; - in.setint.insert(2); - in.setint.insert(1); - in.vbool.push_back(false); - in.vbool.push_back(true); - in.vbool.push_back(false); + in.set_int.insert(2); + in.set_int.insert(1); + in.unordered_set_int.insert(2); + in.unordered_set_int.insert(1); + in.v_bool.push_back(false); + in.v_bool.push_back(true); + in.v_bool.push_back(false); in.optional_int = 3; FooStruct out = foo->pass(in); KJ_EXPECT(in.name == out.name); - KJ_EXPECT(in.setint.size() == out.setint.size()); - for (auto init{in.setint.begin()}, outit{out.setint.begin()}; init != in.setint.end() && outit != out.setint.end(); ++init, ++outit) { + KJ_EXPECT(in.set_int.size() == out.set_int.size()); + for (auto init{in.set_int.begin()}, outit{out.set_int.begin()}; init != in.set_int.end() && outit != out.set_int.end(); ++init, ++outit) { KJ_EXPECT(*init == *outit); } - KJ_EXPECT(in.vbool.size() == out.vbool.size()); - for (size_t i = 0; i < in.vbool.size(); ++i) { - KJ_EXPECT(in.vbool[i] == out.vbool[i]); + KJ_EXPECT(in.unordered_set_int.size() == out.unordered_set_int.size()); + for (const auto& elem : in.unordered_set_int) { + KJ_EXPECT(out.unordered_set_int.count(elem) == 1); + } + KJ_EXPECT(in.v_bool.size() == out.v_bool.size()); + for (size_t i = 0; i < in.v_bool.size(); ++i) { + KJ_EXPECT(in.v_bool[i] == out.v_bool[i]); } KJ_EXPECT(in.optional_int == out.optional_int);