@@ -214,47 +214,7 @@ template<typename X> const X& AsBase(const X& x) { return x; }
214214 template <typename Stream, typename Type, typename Operation> \
215215 static inline void SerializationOps (Type& obj, Stream& s, Operation ser_action) \
216216
217- /* * Variant of FORMATTER_METHODS that supports a declared parameter type.
218- *
219- * If a formatter has a declared parameter type, it must be invoked directly or
220- * indirectly with a parameter of that type. This permits making serialization
221- * depend on run-time context in a type-safe way.
222- *
223- * Example use:
224- * struct BarParameter { bool fancy; ... };
225- * struct Bar { ... };
226- * struct FooFormatter {
227- * FORMATTER_METHODS(Bar, obj, BarParameter, param) {
228- * if (param.fancy) {
229- * READWRITE(VARINT(obj.value));
230- * } else {
231- * READWRITE(obj.value);
232- * }
233- * }
234- * };
235- * which would then be invoked as
236- * READWRITE(WithParams(BarParameter{...}, Using<FooFormatter>(obj.foo)))
237- *
238- * Note that WithParams(parameter, obj) can be invoked anywhere in the call
239- * stack; it is passed down recursively into all serialization code, until
240- * another WithParams overrides it.
241- *
242- * Parameters will be implicitly converted where appropriate. This means that
243- * "parent" serialization code can use a parameter that derives from, or is
244- * convertible to, a "child" formatter's parameter type.
245- *
246- * Compilation will fail in any context where serialization is invoked but
247- * no parameter of a type convertible to BarParameter is provided.
248- */
249- #define FORMATTER_METHODS_PARAMS (cls, obj, paramcls, paramobj ) \
250- template <typename Stream> \
251- static void Ser (Stream& s, const cls& obj) { SerializationOps (obj, s, CSerActionSerialize (), s.GetParams ()); } \
252- template <typename Stream> \
253- static void Unser (Stream& s, cls& obj) { SerializationOps (obj, s, CSerActionUnserialize (), s.GetParams ()); } \
254- template <typename Stream, typename Type, typename Operation> \
255- static inline void SerializationOps (Type& obj, Stream& s, Operation ser_action, const paramcls& paramobj) \
256-
257- #define BASE_SERIALIZE_METHODS (cls ) \
217+ #define SERIALIZE_METHODS (cls, obj ) \
258218 template <typename Stream> \
259219 void Serialize (Stream& s) const \
260220 { \
@@ -266,26 +226,13 @@ template<typename X> const X& AsBase(const X& x) { return x; }
266226 { \
267227 static_assert (std::is_same<cls&, decltype (*this )>::value, " Unserialize type mismatch" ); \
268228 Unser (s, *this ); \
269- }
270-
271- /* *
272- * Implement the Serialize and Unserialize methods by delegating to a single templated
273- * static method that takes the to-be-(de)serialized object as a parameter. This approach
274- * has the advantage that the constness of the object becomes a template parameter, and
275- * thus allows a single implementation that sees the object as const for serializing
276- * and non-const for deserializing, without casts.
277- */
278- #define SERIALIZE_METHODS (cls, obj ) \
279- BASE_SERIALIZE_METHODS (cls) \
229+ } \
280230 FORMATTER_METHODS (cls, obj)
281231
282- /* * Variant of SERIALIZE_METHODS that supports a declared parameter type.
283- *
284- * See FORMATTER_METHODS_PARAMS for more information on parameters.
285- */
232+ /* * Variant of SERIALIZE_METHODS that supports WithParams serialization. */
286233#define SERIALIZE_METHODS_PARAMS (cls, obj, paramcls, paramobj ) \
287- BASE_SERIALIZE_METHODS (cls) \
288- FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj)
234+ template < typename Stream, typename Type, typename Operation> \
235+ static inline void SerializeWithParams (Type& obj, Stream& s, Operation ser_action, const paramcls& paramobj)
289236
290237#ifndef CHAR_EQUALS_INT8
291238template <typename Stream> inline void Serialize (Stream& s, char a ) { ser_writedata8 (s, a); } // TODO Get rid of bare char
@@ -513,10 +460,11 @@ class Wrapper
513460 static_assert (std::is_lvalue_reference<T>::value, " Wrapper needs an lvalue reference type T" );
514461protected:
515462 T m_object;
463+ mutable Formatter m_formatter;
516464public:
517- explicit Wrapper (T obj) : m_object(obj) {}
518- template <typename Stream> void Serialize (Stream &s) const { Formatter () .Ser (s, m_object); }
519- template <typename Stream> void Unserialize (Stream &s) { Formatter () .Unser (s, m_object); }
465+ template < typename ... Args> Wrapper (T obj, Args&&... args ) : m_object(obj), m_formatter(std::forward<Args>(args)... ) {}
466+ template <typename Stream> void Serialize (Stream &s) const { m_formatter .Ser (s, m_object); }
467+ template <typename Stream> void Unserialize (Stream &s) { m_formatter .Unser (s, m_object); }
520468};
521469
522470/* * Cause serialization/deserialization of an object to be done using a specified formatter class.
@@ -656,10 +604,13 @@ struct LimitedStringFormatter
656604template <class Formatter >
657605struct VectorFormatter
658606{
607+ Formatter formatter;
608+
609+ template <typename ... Args> VectorFormatter (Args&&... args) : formatter(std::forward<Args>(args)...) {}
610+
659611 template <typename Stream, typename V>
660612 void Ser (Stream& s, const V& v)
661613 {
662- Formatter formatter;
663614 WriteCompactSize (s, v.size ());
664615 for (const typename V::value_type& elem : v) {
665616 formatter.Ser (s, elem);
@@ -669,7 +620,6 @@ struct VectorFormatter
669620 template <typename Stream, typename V>
670621 void Unser (Stream& s, V& v)
671622 {
672- Formatter formatter;
673623 v.clear ();
674624 size_t size = ReadCompactSize (s);
675625 size_t allocated = 0 ;
@@ -1182,74 +1132,28 @@ size_t GetSerializeSizeMany(int nVersion, const T&... t)
11821132 return sc.size ();
11831133}
11841134
1185- /* * Wrapper that overrides the GetParams() function of a stream. */
1186- template <typename Params, typename Stream>
1187- class ParamsStream
1188- {
1189- const Params& m_params;
1190- Stream& m_substream;
1191- public:
1192- ParamsStream (const Params& params, Stream& substream) : m_params(params), m_substream(substream) {}
1193- template <typename U> inline ParamsStream& operator <<(const U& obj) { ::Serialize (*this , obj); return *this ; }
1194- template <typename U> inline ParamsStream& operator >>(U&& obj) { ::Unserialize (*this , obj); return *this ; }
1195- inline void write (const char * ptr, size_t size) { m_substream.write (ptr, size); }
1196- inline void read (char * ptr, size_t size) { m_substream.read (ptr, size); }
1197- inline size_t size () const { return m_substream.size (); }
1198- inline const Params& GetParams () { return m_params; }
1199- inline int GetVersion () const { return m_substream.GetVersion (); }
1200- inline int GetType () const { return m_substream.GetType (); }
1201- inline Stream& GetSubStream () const { return m_substream; }
1202- };
1203-
1204- /* * Wrapper that serializes objects with the specified parameters. */
1205- template <typename Params, typename T>
1206- class ParamsWrapper
1135+ /* * Formatter that serializes objects with the specified parameters. */
1136+ template <typename Params>
1137+ struct ParamsFormatter
12071138{
1208- static_assert (std::is_lvalue_reference<T>::value, " ParamsWrapper needs an lvalue reference type T" );
1209- const Params& m_params;
1210- T m_object;
1211-
1212- public:
1213- explicit ParamsWrapper (const Params& params, T obj) : m_params(params), m_object(obj) {}
1214-
1215- // ! Serialize to another ParamsStream: optimize by skipping it.
1216- template <typename Stream, typename PrevParams>
1217- inline void Serialize (ParamsStream<PrevParams, Stream>& s) const
1218- {
1219- ParamsStream<Params, Stream> ss (m_params, s.GetSubStream ());
1220- ::Serialize (ss, m_object);
1221- }
1139+ const Params& params;
12221140
1223- // ! Serialize to any other stream
1224- template <typename Stream>
1225- inline void Serialize (Stream& s) const
1226- {
1227- ParamsStream<Params, Stream> ss (m_params, s);
1228- ::Serialize (ss, m_object);
1229- }
1141+ ParamsFormatter (const Params& params) : params(params) {}
12301142
1231- // ! Deserialize from another ParamsStream: optimize by skipping it.
1232- template <typename Stream, typename PrevParams>
1233- inline void Unserialize (ParamsStream<PrevParams, Stream>& s)
1234- {
1235- ParamsStream<Params, Stream> ss (m_params, s.GetSubStream ());
1236- ::Unserialize (ss, m_object);
1237- }
1238-
1239- // ! Deserialize from any other stream
1240- template <typename Stream>
1241- inline void Unserialize (Stream& s)
1242- {
1243- ParamsStream<Params, Stream> ss (m_params, s);
1244- ::Unserialize (ss, m_object);
1245- }
1143+ template <typename Stream, typename T> void Ser (Stream& s, const T& obj) { T::SerializeWithParams (obj, s, CSerActionSerialize (), params); }
1144+ template <typename Stream, typename T> void Unser (Stream& s, T& obj) { T::SerializeWithParams (obj, s, CSerActionUnserialize (), params); }
12461145};
12471146
1147+ /* * Declare-only overloads to help WithParams figure out the right formatter type. */
1148+ template <typename T, typename Params> ParamsFormatter<Params> FormatterType (const T&, const Params&);
1149+ template <typename T, typename Params> VectorFormatter<ParamsFormatter<Params>> FormatterType (const std::vector<T>&, const Params&);
1150+
12481151/* * Return a wrapper around t that (de)serializes it with specified parameter params.
12491152 *
12501153 * See FORMATTER_METHODS_PARAMS for more information on serialization parameters.
12511154 */
1155+ // FIXME: Argument order should be (t, params) not (params, t) and params should be a vararg
12521156template <typename Params, typename T>
1253- static inline ParamsWrapper<Params, T&> WithParams (const Params& params, T&& t) { return ParamsWrapper<Params, T&>(params, t) ; }
1157+ auto WithParams (const Params& params, T&& t) -> Wrapper<decltype(FormatterType(t, params)), T&> { return {t, params} ; }
12541158
12551159#endif // BITCOIN_SERIALIZE_H
0 commit comments