diff --git a/src/common/va_args.h b/src/common/va_args.h new file mode 100644 index 000000000..3389b1cb9 --- /dev/null +++ b/src/common/va_args.h @@ -0,0 +1,45 @@ +// Copyright (c) 2024, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +// Check for __VA_OPT__ support +// Apdated from cpplearner's StackOverflow answer: https://stackoverflow.com/a/48045656 +#define PP_THIRD_ARG(a,b,c,...) c +#define VA_OPT_SUPPORTED_I(...) PP_THIRD_ARG(__VA_OPT__(,),true,false,) +#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?) + +// VA_ARGS_COMMAPREFIX(): VA_ARGS_COMMAPREFIX(__VA_ARGS__) expands to __VA_ARGS__ with a comma in +// front if more than one argument, else nothing. +// If __VA_OPT__ supported, use that. Else, use GCC's ,## hack +#if VA_OPT_SUPPORTED +# define VA_ARGS_COMMAPREFIX(...) __VA_OPT__(,) __VA_ARGS__ +#else +# define VA_ARGS_COMMAPREFIX(...) , ## __VA_ARGS__ +#endif + diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index d1f97e324..512f06cbf 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -50,6 +50,8 @@ #include #include +#include "common/va_args.h" + /*! \struct is_blob_type * * \brief a descriptor for dispatching serialize @@ -88,6 +90,15 @@ inline bool do_serialize(Archive &ar, bool &v) ar.serialize_blob(&v, sizeof(v)); return true; } +template +inline auto do_serialize(Archive &ar, T &v, Args&&... args) + -> decltype(do_serialize_object(ar, v, args...), true) +{ + ar.begin_object(); + const bool r = do_serialize_object(ar, v, args...); + ar.end_object(); + return r && ar.good(); +} /* the following add a trait to a set and define the serialization DSL*/ @@ -158,18 +169,9 @@ inline bool do_serialize(Archive &ar, bool &v) * VARINT_FIELD_F(). Otherwise, this macro is similar to * BEGIN_SERIALIZE_OBJECT(), as you should list only field serializations. */ -#define BEGIN_SERIALIZE_OBJECT_FN(stype) \ - template class Archive> \ - bool do_serialize_object(Archive &ar, stype &v); \ - template class Archive> \ - bool do_serialize(Archive &ar, stype &v) { \ - ar.begin_object(); \ - bool r = do_serialize_object(ar, v); \ - ar.end_object(); \ - return r; \ - } \ - template class Archive> \ - bool do_serialize_object(Archive &ar, stype &v) { \ +#define BEGIN_SERIALIZE_OBJECT_FN(stype, ...) \ + template class Archive> \ + bool do_serialize_object(Archive &ar, stype &v VA_ARGS_COMMAPREFIX(__VA_ARGS__)) { /*! \macro PREPARE_CUSTOM_VECTOR_SERIALIZATION */ @@ -187,10 +189,10 @@ inline bool do_serialize(Archive &ar, bool &v) * * \brief serializes a field \a f tagged \a t */ -#define FIELD_N(t, f) \ +#define FIELD_N(t, f, ...) \ do { \ ar.tag(t); \ - bool r = do_serialize(ar, f); \ + bool r = do_serialize(ar, f VA_ARGS_COMMAPREFIX(__VA_ARGS__)); \ if (!r || !ar.good()) return false; \ } while(0); @@ -209,7 +211,7 @@ inline bool do_serialize(Archive &ar, bool &v) * * \brief tags the field with the variable name and then serializes it (for use in a free function) */ -#define FIELD_F(f) FIELD_N(#f, v.f) +#define FIELD_F(f, ...) FIELD_N(#f, v.f VA_ARGS_COMMAPREFIX(__VA_ARGS__)) /*! \macro FIELDS(f) *