Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(WIP) Support for Boost serialization #262

Merged
merged 36 commits into from
Jan 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ccc88e0
Initial scaffolding for Boost s11n.
bluescarni Dec 30, 2020
56e8ee4
Overload instead of specialising, header fix.
bluescarni Dec 30, 2020
f53fee2
Simplifications, implementation for complex128.
bluescarni Dec 30, 2020
e2ac233
s11n support for integer.
bluescarni Dec 31, 2020
296535d
Small doc improvement.
bluescarni Dec 31, 2020
fb7ca52
Some clang-tidy updates.
bluescarni Jan 1, 2021
90b1281
Ditto.
bluescarni Jan 1, 2021
573c919
Add binary serialization to real.
bluescarni Jan 1, 2021
1b2a6fe
Tentative workaround for older C++ versions.
bluescarni Jan 1, 2021
dbc3cf0
Use GMP_NUMB_BITS instead of mp_bits_per_limb in order to work around…
bluescarni Jan 1, 2021
1d20e7e
Another batch of clang-tidy updates.
bluescarni Jan 1, 2021
41bb4c2
Use decltype() SFINAE in the implementation of the free overloads for…
bluescarni Jan 1, 2021
da98824
Implement and test the free function s11n interface for real.
bluescarni Jan 1, 2021
60d3273
Try to quench MSVC warning.
bluescarni Jan 1, 2021
353d43f
Docs for real serialization.
bluescarni Jan 1, 2021
3f90e64
Merge branch 'master' into pr/boost_s11n
bluescarni Jan 2, 2021
8a75673
First attempt at enabling boost_s11n in the CI.
bluescarni Jan 2, 2021
ce495ea
More tweaks.
bluescarni Jan 2, 2021
dcf9d65
More tweaks.
bluescarni Jan 2, 2021
0d1218d
Switch to release builds on Windows CI.
bluescarni Jan 2, 2021
b68e4c9
Appveyor debug.
bluescarni Jan 2, 2021
37b264d
Don't enable boost in the static Windows build.
bluescarni Jan 2, 2021
757f117
Minor bits.
bluescarni Jan 2, 2021
0ad7f36
Implement Boost s11n for real.
bluescarni Jan 2, 2021
c19104a
Implement boost s11n for rational.
bluescarni Jan 2, 2021
b5c4d4d
Exception safety improvements.
bluescarni Jan 2, 2021
c8593c5
clang-tidy fix.
bluescarni Jan 2, 2021
c8fcb07
Minor.
bluescarni Jan 2, 2021
6e69d9e
Implement boost s11n for complex.
bluescarni Jan 2, 2021
c5242c5
Try to walk back recent appveyor changes.
bluescarni Jan 2, 2021
46ecb93
Avoid compiler warning.
bluescarni Jan 2, 2021
58cc79a
Minor.
bluescarni Jan 2, 2021
1a1eccf
More clang-tidy fixes.
bluescarni Jan 2, 2021
83f5490
Appveyor debug.
bluescarni Jan 2, 2021
5c0e6c8
Tentative workaround.
bluescarni Jan 2, 2021
995dfb7
Docs/changelog update.
bluescarni Jan 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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