-->

boost serialization of mpfr_float

2020-04-16 17:45发布

问题:

I would like to serialize a custom class containing an boost::multiprecision::mpfr_float as a member. It says here in the Boost.Serialization documentation that a type T is serializable iff at least one of 5 properties is true, and here at the Multiprecision documentation that the number class has pass-through support which requires the underlying backend to be serializable.

For Boost.Multiprecision's mpfr_float type, I know:

  1. It is not a primitive type.
  2. It is a class type, but it doesn't have the serialize function(s) defined.
  3. It is not a pointer to a Serializable type.
  4. It is not a reference to a Serializable type.
  5. It is not a native C++ array of Serializable type.

So, it looks like if I want to serialize the mpfr_float type, I must provide the serialize function for that type.

My question is this: How can I extend the mpfr_float type to be serializable by writing the serialize function myself? I think I need to access the mpfr backend, and play with the underlying data, and I am unsure how to proceed. Tips from someone with experience Boost serializing previously-unserialized classes would be greatly appreciated.


Concluding Solution

Based on the reply from sehe, I arrived at a solution which round-trips just fine with precisions 100 and 1000:

namespace boost { namespace serialization { // insert this code to the appropriate namespaces


/**
 Save a mpfr_float type to a boost archive.
 */
template <typename Archive>
void save(Archive& ar, ::boost::multiprecision::backends::mpfr_float_backend<0> const& r, unsigned /*version*/)
{
    std::string tmp = r.str(0, std::ios::fixed);// 0 indicates use full precision
    ar & tmp;
}

/**
 Load a mpfr_float type from a boost archive.
 */
template <typename Archive>
void load(Archive& ar, ::boost::multiprecision::backends::mpfr_float_backend<0>& r, unsigned /*version*/)
{
    std::string tmp;
    ar & tmp;
    r = tmp.c_str();
}

} } // re: namespaces

This solution addresses the need from item (2) above, which indicated the need to add the serialize functions. Thanks for the help.

回答1:

The passthrough support implies that you have to add the serialization for the backend type, indeed.

You can use the same approach as I showed in this answer:

  • How to de/serialize a map with template class using boost::multiprecision::mpq_rational

where I show how to (de)serialize mpq_rational



回答2:

If you are using version 4.0.0 or higher, you can use mpfr_fpif_export and mpfr_fpif_import to serialize/deserialize it.

using realtype = number<mpfr_float_backend<100, allocate_stack>>;

#define MPFR_BUFFER_SIZE 1000

    namespace boost {
        namespace serialization {
            template<class Archive>
            void save(Archive& ar, const realtype& x, const boost::serialization::version_type&) {
                static char buffer[MPFR_BUFFER_SIZE];
                FILE* fid = fmemopen(buffer, MPFR_BUFFER_SIZE, "wb+");
                mpfr_fpif_export(fid, const_cast<mpfr_ptr>(x.backend().data()));
                fseek(fid, 0L, SEEK_END);
                long length = ftell(fid);
                ar& length;
                ar& boost::serialization::make_array(buffer, length);
                fclose(fid);
            }

            template<class Archive>
            void load(Archive& ar, realtype& x, const boost::serialization::version_type&) {
                static char buffer[MPFR_BUFFER_SIZE];
                long length = 0;

                ar& length;
                ar& boost::serialization::make_array(buffer, length);

                FILE* fid = fmemopen(buffer, length, "r");
                mpfr_fpif_import(x.backend().data(), fid);
                fclose(fid);
            }

            template<class Archive>
            inline void
                serialize(Archive& ar, realtype& t, const unsigned int file_version) {
                split_free(ar, t, file_version);
            }
        }
    }