aboutsummaryrefslogtreecommitdiff
path: root/src/serialize.h
diff options
context:
space:
mode:
authorRyan Ofsky <ryan@ofsky.org>2023-11-22 17:56:04 -0500
committerRyan Ofsky <ryan@ofsky.org>2024-02-21 07:07:50 -0500
commite6794e475c84d9edca4a2876e2342cbb1d85f804 (patch)
tree26f39ab177e84f59da3ef1f1be516d319a691118 /src/serialize.h
parentcb28849a88339c1e7ba03ffc7e38998339074e6e (diff)
downloadbitcoin-e6794e475c84d9edca4a2876e2342cbb1d85f804.tar.xz
serialization: Accept multiple parameters in ParamsStream constructor
Before this change it was possible but awkward to create ParamStream streams with multiple parameter objects. After this change it is straightforward. The change to support multiple parameters is implemented by letting ParamsStream contain substream instances, instead of just references to external substreams. So a side-effect of this change is that ParamStream can now accept rvalue stream arguments and be easier to use in some other cases. A test for rvalues is added in this commit, and some simplifications to non-test code are made in the next commit.
Diffstat (limited to 'src/serialize.h')
-rw-r--r--src/serialize.h32
1 files changed, 30 insertions, 2 deletions
diff --git a/src/serialize.h b/src/serialize.h
index 8ad5ad5147..8bca4d8ada 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1108,10 +1108,22 @@ template <typename SubStream, typename Params>
class ParamsStream
{
const Params& m_params;
- SubStream& m_substream;
+ // If ParamsStream constructor is passed an lvalue argument, Substream will
+ // be a reference type, and m_substream will reference that argument.
+ // Otherwise m_substream will be a substream instance and move from the
+ // argument. Letting ParamsStream contain a substream instance instead of
+ // just a reference is useful to make the ParamsStream object self contained
+ // and let it do cleanup when destroyed, for example by closing files if
+ // SubStream is a file stream.
+ SubStream m_substream;
public:
- ParamsStream(SubStream& substream LIFETIMEBOUND, const Params& params LIFETIMEBOUND) : m_params{params}, m_substream{substream} {}
+ ParamsStream(SubStream&& substream, const Params& params LIFETIMEBOUND) : m_params{params}, m_substream{std::forward<SubStream>(substream)} {}
+
+ template <typename NestedSubstream, typename Params1, typename Params2, typename... NestedParams>
+ ParamsStream(NestedSubstream&& s, const Params1& params1 LIFETIMEBOUND, const Params2& params2 LIFETIMEBOUND, const NestedParams&... params LIFETIMEBOUND)
+ : ParamsStream{::ParamsStream{std::forward<NestedSubstream>(s), params2, params...}, params1} {}
+
template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
void write(Span<const std::byte> src) { m_substream.write(src); }
@@ -1132,6 +1144,22 @@ public:
}
};
+/**
+ * Explicit template deduction guide is required for single-parameter
+ * constructor so Substream&& is treated as a forwarding reference, and
+ * SubStream is deduced as reference type for lvalue arguments.
+ */
+template <typename Substream, typename Params>
+ParamsStream(Substream&&, const Params&) -> ParamsStream<Substream, Params>;
+
+/**
+ * Template deduction guide for multiple params arguments that creates a nested
+ * ParamsStream.
+ */
+template <typename Substream, typename Params1, typename Params2, typename... Params>
+ParamsStream(Substream&& s, const Params1& params1, const Params2& params2, const Params&... params) ->
+ ParamsStream<decltype(ParamsStream{std::forward<Substream>(s), params2, params...}), Params1>;
+
/** Wrapper that serializes objects with the specified parameters. */
template <typename Params, typename T>
class ParamsWrapper