Skip to content

Commit

Permalink
Merge pull request #262 from bluescarni/pr/boost_s11n
Browse files Browse the repository at this point in the history
(WIP) Support for Boost serialization
  • Loading branch information
bluescarni committed Jan 2, 2021
2 parents 0ba05f2 + 995dfb7 commit 845b4d5
Show file tree
Hide file tree
Showing 35 changed files with 801 additions and 44 deletions.
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ option(MPPP_WITH_MPFR "Enable features relying on MPFR." OFF)
option(MPPP_WITH_ARB "Enable features relying on Arb." OFF)
option(MPPP_WITH_MPC "Enable features relying on MPC." OFF)
option(MPPP_WITH_QUADMATH "Enable features relying on libquadmath (e.g., the real128 type)." OFF)
option(MPPP_WITH_BOOST_S11N "Enable features relying on the Boost.Serialization library." OFF)
option(MPPP_TEST_PYBIND11 "Build tests for the pybind11 integration utilities (effective only if MPPP_BUILD_TESTS is TRUE, requires pybind11 and Python).")
mark_as_advanced(MPPP_TEST_PYBIND11)
option(MPPP_BUILD_STATIC_LIBRARY "Build mp++ as a static library, instead of dynamic." OFF)
Expand Down Expand Up @@ -402,6 +403,13 @@ if(MPPP_WITH_QUADMATH)
set(MPPP_ENABLE_QUADMATH "#define MPPP_WITH_QUADMATH")
endif()

# Optional dependency on Boost s11n.
set(_MPPP_MIN_BOOST_VERSION "1.60")
if(MPPP_WITH_BOOST_S11N)
find_package(Boost ${_MPPP_MIN_BOOST_VERSION} REQUIRED COMPONENTS serialization)
target_link_libraries(mp++ PUBLIC Boost::serialization)
endif()

# Mandatory dependency on GMP.
# NOTE: depend on GMP *after* optionally depending on MPFR, as the order
# of the libraries matters on some platforms.
Expand Down Expand Up @@ -467,3 +475,5 @@ endif()
if(MPPP_BUILD_BENCHMARKS)
add_subdirectory(benchmark)
endif()

unset(_MPPP_MIN_BOOST_VERSION)
24 changes: 12 additions & 12 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ install:
- if [%BUILD_TYPE%]==[MSVC15_64] conda update -n base conda
- if [%BUILD_TYPE%]==[MSVC15_64] conda config --add channels conda-forge
- if [%BUILD_TYPE%]==[MSVC15_64] conda config --set channel_priority strict
- if [%BUILD_TYPE%]==[MSVC15_64] conda create --name mppp cmake mpir mpfr mpc arb pybind11 mpmath python=3.6
- if [%BUILD_TYPE%]==[MSVC15_64] conda create --name mppp cmake mpir mpfr mpc arb pybind11 mpmath python=3.6 boost-cpp
- if [%BUILD_TYPE%]==[MSVC15_64] call activate mppp

- if [%BUILD_TYPE%]==[MSVC17_64] call "C:\\Miniconda36-x64\\Scripts\\activate.bat"
- if [%BUILD_TYPE%]==[MSVC17_64] conda config --set always_yes yes
- if [%BUILD_TYPE%]==[MSVC17_64] conda update -n base conda
- if [%BUILD_TYPE%]==[MSVC17_64] conda config --add channels conda-forge
- if [%BUILD_TYPE%]==[MSVC17_64] conda config --set channel_priority strict
- if [%BUILD_TYPE%]==[MSVC17_64] conda create --name mppp cmake mpir mpfr mpc arb pybind11 mpmath python=3.6
- if [%BUILD_TYPE%]==[MSVC17_64] conda create --name mppp cmake mpir mpfr mpc arb pybind11 mpmath python=3.6 boost-cpp
- if [%BUILD_TYPE%]==[MSVC17_64] call activate mppp

- if [%BUILD_TYPE%]==[MSVC15_clang_64] call "C:\\Miniconda36-x64\\Scripts\\activate.bat"
Expand All @@ -63,15 +63,15 @@ build_script:
- mkdir build
- cd build

- if [%BUILD_TYPE%]==[MSVC15_64] cmake .. -G "Visual Studio 14 2015 Win64" -DMPPP_BUILD_TESTS=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC15_64] cmake --build . --config Debug
- if [%BUILD_TYPE%]==[MSVC15_64] cmake .. -G "Visual Studio 14 2015 Win64" -DMPPP_BUILD_TESTS=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_TEST_PYBIND11=yes -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC15_64] cmake .. -G "Visual Studio 14 2015 Win64" -DMPPP_BUILD_TESTS=yes -DBoost_NO_BOOST_CMAKE=ON -DMPPP_WITH_BOOST_S11N=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC15_64] cmake --build . --config Release
- if [%BUILD_TYPE%]==[MSVC15_64] cmake .. -G "Visual Studio 14 2015 Win64" -DMPPP_BUILD_TESTS=yes -DBoost_NO_BOOST_CMAKE=ON -DMPPP_WITH_BOOST_S11N=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_TEST_PYBIND11=yes -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC15_64] cmake --build . --config Release --target pybind11_test_01

# This build enables Unicode solutions.
- if [%BUILD_TYPE%]==[MSVC17_64] cmake .. -G "Visual Studio 15 2017 Win64" -DMPPP_BUILD_TESTS=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DCMAKE_CXX_STANDARD=17 -DMPPP_MSVC_UNICODE=YES -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC17_64] cmake --build . --config Debug
- if [%BUILD_TYPE%]==[MSVC17_64] cmake .. -G "Visual Studio 15 2017 Win64" -DMPPP_BUILD_TESTS=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_TEST_PYBIND11=yes -DCMAKE_CXX_STANDARD=17 -DMPPP_MSVC_UNICODE=YES -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC17_64] cmake .. -G "Visual Studio 15 2017 Win64" -DMPPP_BUILD_TESTS=yes -DBoost_NO_BOOST_CMAKE=ON -DMPPP_WITH_BOOST_S11N=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DCMAKE_CXX_STANDARD=17 -DMPPP_MSVC_UNICODE=YES -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC17_64] cmake --build . --config Release
- if [%BUILD_TYPE%]==[MSVC17_64] cmake .. -G "Visual Studio 15 2017 Win64" -DMPPP_BUILD_TESTS=yes -DBoost_NO_BOOST_CMAKE=ON -DMPPP_WITH_BOOST_S11N=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_TEST_PYBIND11=yes -DCMAKE_CXX_STANDARD=17 -DMPPP_MSVC_UNICODE=YES -DMPPP_ENABLE_IPO=yes
- if [%BUILD_TYPE%]==[MSVC17_64] cmake --build . --config Release --target pybind11_test_01

- if [%BUILD_TYPE%]==[MSVC15_clang_64] cmake .. -GNinja -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=Debug -DMPPP_BUILD_TESTS=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_ARB=yes -DMPPP_BUILD_STATIC_LIBRARY=yes -DCMAKE_CXX_STANDARD=17 -DMPPP_ENABLE_IPO=yes
Expand All @@ -86,14 +86,14 @@ test_script:
# otherwise the tests will fail to run.

- if [%BUILD_TYPE%]==[MSVC15_64] set OLD_PATH=%PATH%
- if [%BUILD_TYPE%]==[MSVC15_64] set PATH=%PATH%;%CD%\Debug
- if [%BUILD_TYPE%]==[MSVC15_64] ctest -V -C Debug -E pybind11
- if [%BUILD_TYPE%]==[MSVC15_64] set PATH=%PATH%;%CD%\Release
- if [%BUILD_TYPE%]==[MSVC15_64] ctest -V -C Release -E pybind11
- if [%BUILD_TYPE%]==[MSVC15_64] set PATH=%OLD_PATH%;%CD%\Release
- if [%BUILD_TYPE%]==[MSVC15_64] ctest -V -C Release -R pybind11

- if [%BUILD_TYPE%]==[MSVC17_64] set OLD_PATH=%PATH%
- if [%BUILD_TYPE%]==[MSVC17_64] set PATH=%PATH%;%CD%\Debug
- if [%BUILD_TYPE%]==[MSVC17_64] ctest -V -C Debug -E pybind11
- if [%BUILD_TYPE%]==[MSVC17_64] set PATH=%PATH%;%CD%\Release
- if [%BUILD_TYPE%]==[MSVC17_64] ctest -V -C Release -E pybind11
- if [%BUILD_TYPE%]==[MSVC17_64] set PATH=%OLD_PATH%;%CD%\Release
- if [%BUILD_TYPE%]==[MSVC17_64] ctest -V -C Release -R pybind11

Expand Down
1 change: 1 addition & 0 deletions config.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#cmakedefine MPPP_QUADMATH_HAVE_EXP2Q
#cmakedefine MPPP_QUADMATH_HAVE_LOGBQ
@MPPP_STATIC_BUILD@
#cmakedefine MPPP_WITH_BOOST_S11N
// clang-format on
// End of defines instantiated by CMake.

Expand Down
3 changes: 3 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ New

- Add a binary serialisation API for :cpp:class:`~mppp::real`
(`#263 <https://github.com/bluescarni/mppp/pull/263>`__).
- Implement optional support for Boost.serialization for all
multiprecision classes
(`#262 <https://github.com/bluescarni/mppp/pull/262>`__).
- Add a header file containing the forward declarations
of all the number classes
(`#261 <https://github.com/bluescarni/mppp/pull/261>`__).
Expand Down
7 changes: 7 additions & 0 deletions doc/definitions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ Macros and definitions
This name is defined if mp++ was configured with support for the quadmath library
(see the :ref:`installation instructions <installation>`).

.. c:macro:: MPPP_WITH_BOOST_S11N
.. versionadded:: 0.22

This name is defined if mp++ was configured with support for the Boost.serialization library
(see the :ref:`installation instructions <installation>`).

.. c:macro:: MPPP_FLOAT128_WITH_LONG_DOUBLE
.. versionadded:: 0.22
Expand Down
11 changes: 9 additions & 2 deletions doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ mp++ has the following dependencies:
(typically, the quadmath library is part of GCC and it does not need to
be installed separately);
* the `Boost <https://www.boost.org/>`__ libraries, *optional*, currently used
only in the benchmarking suite;
for implementing (de)serialisation and in the benchmarking suite;
* the `{fmt} <https://fmt.dev/latest/index.html>`__ library (at least version 6.2), *optional*, currently used
only in the benchmarking suite.

Expand Down Expand Up @@ -66,6 +66,8 @@ path, etc.). The available configuration options are:
(off by default, requires the ``MPPP_WITH_MPFR`` option to be active),
* ``MPPP_WITH_QUADMATH``: enable features relying on the
quadmath library (off by default),
* ``MPPP_WITH_BOOST_S11N``: enable support for serialisation
via the Boost.serialization library (off by default),
* ``MPPP_BUILD_TESTS``: build the test suite (off by default),
* ``MPPP_BUILD_BENCHMARKS``: build the benchmarking suite (off by default),
* ``MPPP_BUILD_STATIC_LIBRARY``: build mp++ as a static library, instead
Expand All @@ -92,6 +94,10 @@ path, etc.). The available configuration options are:

The ``MPPP_WITH_MPC`` and ``MPPP_ENABLE_IPO`` build options.

.. versionadded:: 0.22

The ``MPPP_WITH_BOOST_S11N`` build option.

Note that the ``MPPP_WITH_QUADMATH`` option, at this time, is available only
using GCC (all the supported versions), Clang
(since version 3.9) and the Intel compiler. When this option is active,
Expand Down Expand Up @@ -272,7 +278,8 @@ variables to signal with which optional dependencies mp++ was compiled:
* ``mp++_WITH_MPFR`` if MPFR support was enabled,
* ``mp++_WITH_MPC`` if MPC support was enabled,
* ``mp++_WITH_ARB`` if Arb support was enabled,
* ``mp++_WITH_QUADMATH`` if quadmath support was enabled.
* ``mp++_WITH_QUADMATH`` if quadmath support was enabled,
* ``mp++_WITH_BOOST_S11N`` if Boost.serialization support was enabled.

.. _inst_plat_specific:

Expand Down
1 change: 1 addition & 0 deletions doc/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ on to the full :ref:`C++ reference <reference>`.
tutorial_complex128.rst
tutorial_real.rst
tutorial_complex.rst
tutorial_boost_s11n.rst
tutorial_pybind11.rst
23 changes: 23 additions & 0 deletions doc/tutorial_boost_s11n.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.. _tutorial_boost_s11n:

Boost.serialization support
===========================

Starting from version 0.22, all of mp++'s multiprecision classes support (de)serialisation
via the `Boost.serialization <https://www.boost.org/doc/libs/1_75_0/libs/serialization/doc/index.html>`_
library, provided that mp++ was compiled with the ``MPPP_WITH_BOOST_S11N`` option enabled
(see the :ref:`installation instructions <installation>`). We refer to the documentation
of Boost.serialization (particularly the
`tutorial <https://www.boost.org/doc/libs/1_75_0/libs/serialization/doc/tutorial.html>`_)
for usage examples. Note that, as detailed in the previous sections,
certain classes (such as :cpp:class:`~mppp::integer` and
:cpp:class:`~mppp::real`) also provide a separate, low-level binary serialisation API
which does not depend on Boost.serialization.

There is an important **caveat** to keep in mind when using mp++'s Boost.serialization support.
The serialisation to/from binary archives is optimised for speed, and no checks are performed
on the validity of the data that is loaded from a binary archive. In other words, a
maliciously-crafted binary archive could lead to the creation of an invalid mp++ object
whose use could then lead to undefined and/or erratic runtime behaviour. Users are thus
advised not to load data from untrusted binary archives. Non-binary archives do not suffer from
these issues.
46 changes: 46 additions & 0 deletions include/mp++/complex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
#include <string_view>
#endif

#if defined(MPPP_WITH_BOOST_S11N)

#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/tracking.hpp>

#endif

#include <mp++/concepts.hpp>
#include <mp++/detail/mpc.hpp>
#include <mp++/detail/mpfr.hpp>
Expand Down Expand Up @@ -193,6 +202,35 @@ enum class complex_prec_t : ::mpfr_prec_t {};
// Multiprecision complex class.
class MPPP_DLL_PUBLIC complex
{
#if defined(MPPP_WITH_BOOST_S11N)
// Boost serialization support.
friend class boost::serialization::access;

template <typename Archive>
void save(Archive &ar, unsigned) const
{
re_cref re{*this};
im_cref im{*this};

ar << *re;
ar << *im;
}

template <typename Archive>
void load(Archive &ar, unsigned)
{
MPPP_MAYBE_TLS real re, im;

ar >> re;
ar >> im;

*this = complex{re, im};
}
void load(boost::archive::binary_iarchive &, unsigned);

BOOST_SERIALIZATION_SPLIT_MEMBER()
#endif

// Make friends, for accessing the non-checking prec setting funcs.
template <bool, typename F, typename Arg0, typename... Args>
// NOLINTNEXTLINE(readability-redundant-declaration)
Expand Down Expand Up @@ -3131,6 +3169,14 @@ inline rational<SSize> &rational<SSize>::operator=(const complex &c)

} // namespace mppp

#if defined(MPPP_WITH_BOOST_S11N)

// Never track the address of complex objects
// during serialization.
BOOST_CLASS_TRACKING(mppp::complex, boost::serialization::track_never)

#endif

// Support for pretty printing in xeus-cling.
#if defined(__CLING__)

Expand Down
44 changes: 44 additions & 0 deletions include/mp++/complex128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@

#endif

#if defined(MPPP_WITH_BOOST_S11N)

#include <boost/serialization/access.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/tracking.hpp>

#endif

#include <mp++/concepts.hpp>
#include <mp++/detail/type_traits.hpp>
#include <mp++/detail/visibility.hpp>
Expand Down Expand Up @@ -94,6 +102,34 @@ constexpr complex128 conj(const complex128 &);

class MPPP_DLL_PUBLIC complex128
{
#if defined(MPPP_WITH_BOOST_S11N)
// Boost serialization support.
friend class boost::serialization::access;

template <typename Archive>
void save(Archive &ar, unsigned) const
{
ar << real();
ar << imag();
}

template <typename Archive>
void load(Archive &ar, unsigned)
{
// NOTE: use tmp variables
// for exception safety.
real128 re, im;

ar >> re;
ar >> im;

set_real(re);
set_imag(im);
}

BOOST_SERIALIZATION_SPLIT_MEMBER()
#endif

public:
// NOLINTNEXTLINE(modernize-use-default-member-init)
cplex128 m_value;
Expand Down Expand Up @@ -1245,6 +1281,14 @@ inline MPPP_CONSTEXPR_14 real128 &real128::operator=(const complex128 &x)

} // namespace mppp

#if defined(MPPP_WITH_BOOST_S11N)

// Never track the address of complex128 objects
// during serialization.
BOOST_CLASS_TRACKING(mppp::complex128, boost::serialization::track_never)

#endif

// Support for pretty printing in xeus-cling.
#if defined(__CLING__)

Expand Down

0 comments on commit 845b4d5

Please sign in to comment.