Separate serialization code from Boost.Serialization

This commit is contained in:
Hans Dembinski 2019-10-20 21:40:02 +01:00 committed by GitHub
parent d68cc4729c
commit 9dd4a04a10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 339 additions and 300 deletions

View File

@ -51,5 +51,5 @@ test_script:
## Uncomment the following to stop VM and enable interactive login.
## Instructions how to log into the Appveyor VM are automatically printed.
# on_failure:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
on_failure:
- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@ -8,7 +8,10 @@
#define BOOST_HISTOGRAM_ACCUMULATORS_MEAN_HPP
#include <boost/assert.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/fwd.hpp> // for mean<>
#include <boost/throw_exception.hpp>
#include <stdexcept>
#include <type_traits>
namespace boost {
@ -24,10 +27,10 @@ template <class RealType>
class mean {
public:
mean() = default;
mean(const RealType& n, const RealType& mean, const RealType& variance)
mean(const RealType& n, const RealType& mean, const RealType& variance) noexcept
: sum_(n), mean_(mean), sum_of_deltas_squared_(variance * (n - 1)) {}
void operator()(const RealType& x) {
void operator()(const RealType& x) noexcept {
sum_ += static_cast<RealType>(1);
const auto delta = x - mean_;
BOOST_ASSERT(sum_ != 0);
@ -35,7 +38,7 @@ public:
sum_of_deltas_squared_ += delta * (x - mean_);
}
void operator()(const RealType& w, const RealType& x) {
void operator()(const RealType& w, const RealType& x) noexcept {
sum_ += w;
const auto delta = x - mean_;
BOOST_ASSERT(sum_ != 0);
@ -44,7 +47,7 @@ public:
}
template <class T>
mean& operator+=(const mean<T>& rhs) {
mean& operator+=(const mean<T>& rhs) noexcept {
const auto tmp = mean_ * sum_ + static_cast<RealType>(rhs.mean_ * rhs.sum_);
sum_ += rhs.sum_;
BOOST_ASSERT(sum_ != 0);
@ -53,7 +56,7 @@ public:
return *this;
}
mean& operator*=(const RealType& s) {
mean& operator*=(const RealType& s) noexcept {
mean_ *= s;
sum_of_deltas_squared_ *= s * s;
return *this;
@ -72,10 +75,22 @@ public:
const RealType& count() const noexcept { return sum_; }
const RealType& value() const noexcept { return mean_; }
RealType variance() const { return sum_of_deltas_squared_ / (sum_ - 1); }
RealType variance() const noexcept { return sum_of_deltas_squared_ / (sum_ - 1); }
template <class Archive>
void serialize(Archive&, unsigned /* version */);
void serialize(Archive& ar, unsigned version) {
if (version == 0) {
if (Archive::is_saving::value)
BOOST_THROW_EXCEPTION(std::runtime_error("save must not use version 0"));
std::size_t sum;
ar& make_nvp("sum", sum);
sum_ = static_cast<RealType>(sum);
} else {
ar& make_nvp("sum", sum_);
}
ar& make_nvp("mean", mean_);
ar& make_nvp("sum_of_deltas_squared", sum_of_deltas_squared_);
}
private:
RealType sum_ = 0, mean_ = 0, sum_of_deltas_squared_ = 0;
@ -86,6 +101,21 @@ private:
} // namespace boost
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
namespace boost {
namespace serialization {
template <class T>
struct version;
// version 1 for boost::histogram::accumulators::mean<RealType>
template <class RealType>
struct version<boost::histogram::accumulators::mean<RealType>>
: std::integral_constant<int, 1> {};
} // namespace serialization
} // namespace boost
namespace std {
template <class T, class U>
/// Specialization for boost::histogram::accumulators::mean.
@ -94,6 +124,7 @@ struct common_type<boost::histogram::accumulators::mean<T>,
using type = boost::histogram::accumulators::mean<common_type_t<T, U>>;
};
} // namespace std
#endif
#endif

View File

@ -7,7 +7,8 @@
#ifndef BOOST_HISTOGRAM_ACCUMULATORS_SUM_HPP
#define BOOST_HISTOGRAM_ACCUMULATORS_SUM_HPP
#include <boost/histogram/fwd.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/fwd.hpp> // for sum<>
#include <cmath>
#include <type_traits>
@ -83,7 +84,10 @@ public:
operator RealType() const { return large_ + small_; }
template <class Archive>
void serialize(Archive&, unsigned /* version */);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("large", large_);
ar& make_nvp("small", small_);
}
private:
RealType large_ = RealType();

View File

@ -8,6 +8,7 @@
#define BOOST_HISTOGRAM_ACCUMULATORS_THREAD_SAFE_HPP
#include <atomic>
#include <boost/core/nvp.hpp>
#include <boost/mp11/utility.hpp>
#include <type_traits>
@ -48,6 +49,13 @@ public:
void operator+=(T arg) { super_t::fetch_add(arg, std::memory_order_relaxed); }
void operator++() { operator+=(static_cast<T>(1)); }
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
auto value = super_t::load();
ar& make_nvp("value", value);
super_t::store(value);
}
};
} // namespace accumulators

View File

@ -8,7 +8,8 @@
#define BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_MEAN_HPP
#include <boost/assert.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/fwd.hpp> // for weighted_mean<>
#include <type_traits>
namespace boost {
@ -84,7 +85,12 @@ public:
}
template <class Archive>
void serialize(Archive&, unsigned /* version */);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("sum_of_weights", sum_of_weights_);
ar& make_nvp("sum_of_weights_squared", sum_of_weights_squared_);
ar& make_nvp("weighted_mean", weighted_mean_);
ar& make_nvp("sum_of_weighted_deltas_squared", sum_of_weighted_deltas_squared_);
}
private:
RealType sum_of_weights_ = RealType(), sum_of_weights_squared_ = RealType(),

View File

@ -7,7 +7,8 @@
#ifndef BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_SUM_HPP
#define BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_SUM_HPP
#include <boost/histogram/fwd.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/fwd.hpp> // for weighted_sum<>
#include <type_traits>
namespace boost {
@ -78,7 +79,10 @@ public:
}
template <class Archive>
void serialize(Archive&, unsigned /* version */);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("sum_of_weights", sum_of_weights_);
ar& make_nvp("sum_of_weights_squared", sum_of_weights_squared_);
}
private:
RealType sum_of_weights_ = RealType();

View File

@ -8,6 +8,7 @@
#define BOOST_HISTOGRAM_AXIS_CATEGORY_HPP
#include <algorithm>
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/iterator.hpp>
#include <boost/histogram/axis/option.hpp>
#include <boost/histogram/detail/compressed_pair.hpp>
@ -175,7 +176,10 @@ public:
auto get_allocator() const { return vec_meta_.first().get_allocator(); }
template <class Archive>
void serialize(Archive&, unsigned);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("seq", vec_meta_.first());
ar& make_nvp("meta", vec_meta_.second());
}
private:
detail::compressed_pair<vector_type, metadata_type> vec_meta_;

View File

@ -7,6 +7,7 @@
#ifndef BOOST_HISTOGRAM_AXIS_INTEGER_HPP
#define BOOST_HISTOGRAM_AXIS_INTEGER_HPP
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/iterator.hpp>
#include <boost/histogram/axis/option.hpp>
#include <boost/histogram/detail/compressed_pair.hpp>
@ -184,7 +185,11 @@ public:
}
template <class Archive>
void serialize(Archive&, unsigned);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("size", size_meta_.first());
ar& make_nvp("meta", size_meta_.second());
ar& make_nvp("min", min_);
}
private:
index_type index_impl(std::false_type, int x) const noexcept {

View File

@ -8,6 +8,7 @@
#define BOOST_HISTOGRAM_AXIS_REGULAR_HPP
#include <boost/assert.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/interval_view.hpp>
#include <boost/histogram/axis/iterator.hpp>
#include <boost/histogram/axis/option.hpp>
@ -77,6 +78,9 @@ struct id {
static T inverse(T&& x) noexcept {
return std::forward<T>(x);
}
template <class Archive>
void serialize(Archive&, unsigned /* version */) {}
};
/// Log transform for equidistant bins in log-space.
@ -92,6 +96,9 @@ struct log {
static T inverse(T x) {
return std::exp(x);
}
template <class Archive>
void serialize(Archive&, unsigned /* version */) {}
};
/// Sqrt transform for equidistant bins in sqrt-space.
@ -107,6 +114,9 @@ struct sqrt {
static T inverse(T x) {
return x * x;
}
template <class Archive>
void serialize(Archive&, unsigned /* version */) {}
};
/// Pow transform for equidistant bins in pow-space.
@ -130,6 +140,11 @@ struct pow {
}
bool operator==(const pow& o) const noexcept { return power == o.power; }
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("power", power);
}
};
} // namespace transform
@ -384,7 +399,13 @@ public:
}
template <class Archive>
void serialize(Archive&, unsigned);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("transform", static_cast<transform_type&>(*this));
ar& make_nvp("size", size_meta_.first());
ar& make_nvp("meta", size_meta_.second());
ar& make_nvp("min", min_);
ar& make_nvp("delta", delta_);
}
private:
detail::compressed_pair<index_type, metadata_type> size_meta_{0};

View File

@ -9,6 +9,7 @@
#include <algorithm>
#include <boost/assert.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/interval_view.hpp>
#include <boost/histogram/axis/iterator.hpp>
#include <boost/histogram/axis/option.hpp>
@ -226,7 +227,10 @@ public:
auto get_allocator() const { return vec_meta_.first().get_allocator(); }
template <class Archive>
void serialize(Archive&, unsigned);
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("seq", vec_meta_.first());
ar& make_nvp("meta", vec_meta_.second());
}
private:
detail::compressed_pair<vec_type, metadata_type> vec_meta_;

View File

@ -1,4 +1,4 @@
// Copyright 2015-2017 Hans Dembinski
// Copyright 2015-2019 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@ -7,6 +7,7 @@
#ifndef BOOST_HISTOGRAM_AXIS_VARIANT_HPP
#define BOOST_HISTOGRAM_AXIS_VARIANT_HPP
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/iterator.hpp>
#include <boost/histogram/axis/polymorphic_bin.hpp>
#include <boost/histogram/axis/traits.hpp>
@ -14,10 +15,9 @@
#include <boost/histogram/detail/relaxed_equal.hpp>
#include <boost/histogram/detail/static_if.hpp>
#include <boost/histogram/detail/type_name.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/histogram/detail/variant_proxy.hpp>
#include <boost/mp11/algorithm.hpp> // mp_contains
#include <boost/mp11/list.hpp> // mp_first
#include <boost/throw_exception.hpp>
#include <boost/variant2/variant.hpp>
#include <ostream>
@ -219,6 +219,12 @@ public:
return !operator==(t);
}
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
detail::variant_proxy<variant> p{*this};
ar& make_nvp("variant", p);
}
private:
impl_type impl;

View File

@ -9,6 +9,7 @@
#include <array>
#include <boost/assert.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/traits.hpp>
#include <boost/histogram/axis/variant.hpp>
#include <boost/histogram/detail/make_default.hpp>
@ -179,6 +180,24 @@ void axes_assign(T& t, const U& u) {
t.assign(u.begin(), u.end());
}
template <class Archive, class T>
void axes_serialize(Archive& ar, T& axes) {
ar& make_nvp("axes", axes);
}
template <class Archive, class... Ts>
void axes_serialize(Archive& ar, std::tuple<Ts...>& axes) {
// needed to keep serialization format backward compatible
struct proxy {
std::tuple<Ts...>& t;
void serialize(Archive& ar, unsigned) {
mp11::tuple_for_each(t, [&ar](auto& x) { ar& make_nvp("item", x); });
}
};
proxy p{axes};
ar& make_nvp("axes", p);
}
// create empty dynamic axis which can store any axes types from the argument
template <class T>
auto make_empty_dynamic_axes(const T& axes) {

View File

@ -229,8 +229,8 @@ void fill_n_1(const std::size_t offset, S& storage, A& axes, const std::size_t v
}
}
template <class T>
std::size_t get_total_size(const dtl::span<const T>& values) {
template <class T, std::size_t N>
std::size_t get_total_size(const dtl::span<const T, N>& values) {
std::size_t s = 1u;
auto vis = [&s](const auto& v) {
// cannot be replaced by std::decay_t
@ -261,9 +261,9 @@ void fill_n_check_extra_args(std::size_t n, Ts&&... ts) {
inline void fill_n_check_extra_args(std::size_t) noexcept {}
template <class S, class A, class T, class... Us>
template <class S, class A, class T, std::size_t N, class... Us>
void fill_n(const std::size_t offset, S& storage, A& axes,
const dtl::span<const T> values, Us&&... us) {
const dtl::span<const T, N> values, Us&&... us) {
static_assert(!std::is_pointer<T>::value,
"passing iterable of pointers not allowed (cannot determine lengths); "
"pass iterable of iterables instead");

View File

@ -217,6 +217,11 @@ struct large_int : totally_ordered<large_int<Allocator>, large_int<Allocator>>,
--d -= tmp;
}
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("data", data);
}
std::vector<std::uint64_t, Allocator> data;
};

View File

@ -7,6 +7,11 @@
#ifndef BOOST_HISTOGRAM_DETAIL_SPAN_HPP
#define BOOST_HISTOGRAM_DETAIL_SPAN_HPP
#include <boost/assert.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/detail/static_if.hpp>
#include <type_traits>
#if __cpp_constexpr >= 201603 && __cpp_deduction_guides >= 201703 && \
__cpp_lib_nonmember_container_access >= 201411 && __has_include(<span>)
#include <span>
@ -240,7 +245,12 @@ auto make_span(const Container& cont) {
template <class T, std::size_t N>
auto make_span(T (&arr)[N]) {
return dtl::span<T>(arr, N);
return dtl::span<T, N>(arr, N);
}
template <class Archive, class T, std::size_t N>
void serialize(Archive& ar, dtl::span<T, N>& sp, unsigned /* version */) {
for (auto&& x : sp) ar& make_nvp("item", x);
}
} // namespace detail

View File

@ -0,0 +1,67 @@
// Copyright 2019 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_HISTOGRAM_DETAIL_VARIANT_PROXY_HPP
#define BOOST_HISTOGRAM_DETAIL_VARIANT_PROXY_HPP
#include <boost/core/nvp.hpp>
#include <boost/histogram/axis/traits.hpp> // variant_access
#include <boost/histogram/detail/static_if.hpp>
#include <boost/mp11/algorithm.hpp> // mp_with_index, mp_find, mp_at
#include <boost/mp11/list.hpp> // mp_size
#include <boost/throw_exception.hpp>
#include <stdexcept>
namespace boost {
namespace histogram {
namespace detail {
// This is a workaround to remain backward compatible in the serialization format. The
// proxy uses only the public interface of axis::variant for serialization and works
// independently of the underlying variant implementation.
template <class Variant>
struct variant_proxy {
Variant& variant;
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
detail::static_if_c<Archive::is_loading::value>(
[this](auto& ar) { // loading
int which = 0;
ar >> make_nvp("which", which);
constexpr unsigned N = mp11::mp_size<Variant>::value;
if (which < 0 || static_cast<unsigned>(which) >= N)
// throw if which >= N, can happen if type was removed from variant
BOOST_THROW_EXCEPTION(
std::runtime_error("variant has fewer types than stored version"));
mp11::mp_with_index<N>(static_cast<unsigned>(which), [&ar, this](auto i) {
using T = mp11::mp_at_c<Variant, i>;
T value;
ar >> make_nvp("value", value);
this->variant = std::move(value);
T* new_address = variant_access::template get_if<T>(&this->variant);
ar.reset_object_address(new_address, &value);
});
},
[this](auto& ar) { // saving
visit(
[&ar](const auto& value) {
using T = std::decay_t<decltype(value)>;
const int which = static_cast<int>(mp11::mp_find<Variant, T>::value);
ar << make_nvp("which", which);
ar << make_nvp("value", value);
},
this->variant);
},
ar);
}
};
} // namespace detail
} // namespace histogram
} // namespace boost
#endif

View File

@ -38,6 +38,9 @@ using empty_type = null_type;
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
template <class Archive>
void serialize(Archive&, null_type&, unsigned /* version */) {}
namespace transform {
struct id;
struct log;

View File

@ -503,6 +503,16 @@ public:
/// Return value iterator to the end in the histogram (read-only).
const_iterator cend() const noexcept { return end(); }
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
detail::axes_serialize(ar, axes_);
ar& make_nvp("storage", storage_and_mutex_.first());
if (Archive::is_loading::value) {
offset_ = detail::offset(axes_);
detail::throw_if_axes_is_too_large(axes_);
}
}
private:
axes_type axes_;

View File

@ -1,4 +1,4 @@
// Copyright 2015-2017 Hans Dembinski
// Copyright 2015-2019 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@ -7,278 +7,17 @@
#ifndef BOOST_HISTOGRAM_SERIALIZATION_HPP
#define BOOST_HISTOGRAM_SERIALIZATION_HPP
#include <boost/archive/archive_exception.hpp>
#include <boost/assert.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/accumulators/mean.hpp>
#include <boost/histogram/accumulators/sum.hpp>
#include <boost/histogram/accumulators/weighted_mean.hpp>
#include <boost/histogram/accumulators/weighted_sum.hpp>
#include <boost/histogram/axis/category.hpp>
#include <boost/histogram/axis/integer.hpp>
#include <boost/histogram/axis/regular.hpp>
#include <boost/histogram/axis/variable.hpp>
#include <boost/histogram/axis/variant.hpp>
#include <boost/histogram/histogram.hpp>
#include <boost/histogram/storage_adaptor.hpp>
#include <boost/histogram/unlimited_storage.hpp>
#include <boost/histogram/unsafe_access.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/tuple.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/throw_exception.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/version.hpp>
#include <tuple>
#include <type_traits>
/**
\file boost/histogram/serialization.hpp
Implemenations of the serialization functions using
[Boost.Serialization](https://www.boost.org/doc/libs/develop/libs/serialization/doc/index.html).
Headers from
[Boost.Serialization](https://www.boost.org/doc/libs/develop/libs/serialization/doc/index.html)
needed to serialize STL types that are used internally by the Boost.Histogram classes.
*/
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
namespace boost {
namespace serialization {
// version 1 for boost::histogram::accumulators::mean<RealType>
template <class RealType>
struct version<boost::histogram::accumulators::mean<RealType>> {
typedef mpl::int_<1> type;
typedef mpl::integral_c_tag tag;
BOOST_STATIC_CONSTANT(int, value = version::type::value);
};
template <class Archive, class... Ts>
void serialize(Archive& ar, std::tuple<Ts...>& t, unsigned /* version */) {
mp11::tuple_for_each(t, [&ar](auto& x) { ar& make_nvp("item", x); });
}
} // namespace serialization
} // namespace boost
namespace boost {
namespace histogram {
namespace accumulators {
template <class RealType>
template <class Archive>
void sum<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("large", large_);
ar& make_nvp("small", small_);
}
template <class RealType>
template <class Archive>
void weighted_sum<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("sum_of_weights", sum_of_weights_);
ar& make_nvp("sum_of_weights_squared", sum_of_weights_squared_);
}
template <class RealType>
template <class Archive>
void mean<RealType>::serialize(Archive& ar, unsigned version) {
if (version == 0 && Archive::is_loading::value) {
std::size_t sum;
ar& make_nvp("sum", sum);
sum_ = static_cast<RealType>(sum);
} else {
ar& make_nvp("sum", sum_);
}
ar& make_nvp("mean", mean_);
ar& make_nvp("sum_of_deltas_squared", sum_of_deltas_squared_);
}
template <class RealType>
template <class Archive>
void weighted_mean<RealType>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("sum_of_weights", sum_of_weights_);
ar& make_nvp("sum_of_weights_squared", sum_of_weights_squared_);
ar& make_nvp("weighted_mean", weighted_mean_);
ar& make_nvp("sum_of_weighted_deltas_squared", sum_of_weighted_deltas_squared_);
}
template <class Archive, class T>
void serialize(Archive& ar, thread_safe<T>& t, unsigned /* version */) {
T value = t;
ar& make_nvp("value", value);
t = value;
}
} // namespace accumulators
namespace axis {
namespace transform {
template <class Archive>
void serialize(Archive&, id&, unsigned /* version */) {}
template <class Archive>
void serialize(Archive&, log&, unsigned /* version */) {}
template <class Archive>
void serialize(Archive&, sqrt&, unsigned /* version */) {}
template <class Archive>
void serialize(Archive& ar, pow& t, unsigned /* version */) {
ar& make_nvp("power", t.power);
}
} // namespace transform
template <class Archive>
void serialize(Archive&, null_type&, unsigned /* version */) {}
template <class T, class Tr, class M, class O>
template <class Archive>
void regular<T, Tr, M, O>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("transform", static_cast<transform_type&>(*this));
ar& make_nvp("size", size_meta_.first());
ar& make_nvp("meta", size_meta_.second());
ar& make_nvp("min", min_);
ar& make_nvp("delta", delta_);
}
template <class T, class M, class O>
template <class Archive>
void integer<T, M, O>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("size", size_meta_.first());
ar& make_nvp("meta", size_meta_.second());
ar& make_nvp("min", min_);
}
template <class T, class M, class O, class A>
template <class Archive>
void variable<T, M, O, A>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("seq", vec_meta_.first());
ar& make_nvp("meta", vec_meta_.second());
}
template <class T, class M, class O, class A>
template <class Archive>
void category<T, M, O, A>::serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("seq", vec_meta_.first());
ar& make_nvp("meta", vec_meta_.second());
}
// variant_proxy is a workaround to remain backward compatible in the serialization
// format. It uses only the public interface of axis::variant for serialization and
// therefore works independently of the underlying variant implementation.
template <class Variant>
struct variant_proxy {
Variant& v;
BOOST_SERIALIZATION_SPLIT_MEMBER()
template <class Archive>
void save(Archive& ar, unsigned /* version */) const {
visit(
[&ar](auto& value) {
using T = std::decay_t<decltype(value)>;
int which = static_cast<int>(mp11::mp_find<Variant, T>::value);
ar << make_nvp("which", which);
ar << make_nvp("value", value);
},
v);
}
template <class Archive>
void load(Archive& ar, unsigned /* version */) {
int which = 0;
ar >> make_nvp("which", which);
constexpr unsigned N = mp11::mp_size<Variant>::value;
if (which < 0 || static_cast<unsigned>(which) >= N)
// throw on invalid which, which >= N can happen if type was removed from variant
serialization::throw_exception(
archive::archive_exception(archive::archive_exception::unsupported_version));
mp11::mp_with_index<N>(static_cast<unsigned>(which), [&ar, this](auto i) {
using T = mp11::mp_at_c<Variant, i>;
T value;
ar >> make_nvp("value", value);
v = std::move(value);
T* new_address = get_if<T>(&v);
ar.reset_object_address(new_address, &value);
});
}
};
template <class Archive, class... Ts>
void serialize(Archive& ar, variant<Ts...>& v, unsigned /* version */) {
variant_proxy<variant<Ts...>> p{v};
ar& make_nvp("variant", p);
}
} // namespace axis
namespace detail {
template <class Archive, class T>
void serialize(Archive& ar, vector_impl<T>& impl, unsigned /* version */) {
ar& make_nvp("vector", static_cast<T&>(impl));
}
template <class Archive, class T>
void serialize(Archive& ar, array_impl<T>& impl, unsigned /* version */) {
ar& make_nvp("size", impl.size_);
ar& make_nvp("array", serialization::make_array(impl.data(), impl.size_));
}
template <class Archive, class T>
void serialize(Archive& ar, map_impl<T>& impl, unsigned /* version */) {
ar& make_nvp("size", impl.size_);
ar& make_nvp("map", static_cast<T&>(impl));
}
template <class Archive, class Allocator>
void serialize(Archive& ar, large_int<Allocator>& x, unsigned /* version */) {
ar& make_nvp("data", x.data);
}
} // namespace detail
template <class Archive, class T>
void serialize(Archive& ar, storage_adaptor<T>& x, unsigned /* version */) {
auto& impl = unsafe_access::storage_adaptor_impl(x);
ar& make_nvp("impl", impl);
}
template <class Allocator, class Archive>
void serialize(Archive& ar, unlimited_storage<Allocator>& s, unsigned /* version */) {
auto& buffer = unsafe_access::unlimited_storage_buffer(s);
using buffer_t = std::remove_reference_t<decltype(buffer)>;
if (Archive::is_loading::value) {
buffer_t helper(buffer.alloc);
std::size_t size;
ar& make_nvp("type", helper.type);
ar& make_nvp("size", size);
helper.visit([&buffer, size](auto* tp) {
BOOST_ASSERT(tp == nullptr);
using T = std::decay_t<decltype(*tp)>;
buffer.template make<T>(size);
});
} else {
ar& make_nvp("type", buffer.type);
ar& make_nvp("size", buffer.size);
}
buffer.visit([&buffer, &ar](auto* tp) {
ar& make_nvp("buffer", serialization::make_array(
static_cast<decltype(tp)>(buffer.ptr), buffer.size));
});
}
template <class Archive, class A, class S>
void serialize(Archive& ar, histogram<A, S>& h, unsigned /* version */) {
ar& make_nvp("axes", unsafe_access::axes(h));
ar& make_nvp("storage", unsafe_access::storage(h));
if (Archive::is_loading::value) {
unsafe_access::offset(h) = detail::offset(unsafe_access::axes(h));
detail::throw_if_axes_is_too_large(unsafe_access::axes(h));
}
}
} // namespace histogram
} // namespace boost
#endif
#endif

View File

@ -8,14 +8,15 @@
#define BOOST_HISTOGRAM_STORAGE_ADAPTOR_HPP
#include <algorithm>
#include <boost/core/nvp.hpp>
#include <boost/histogram/detail/cat.hpp>
#include <boost/histogram/detail/detect.hpp>
#include <boost/histogram/detail/iterator_adaptor.hpp>
#include <boost/histogram/detail/safe_comparison.hpp>
#include <boost/histogram/detail/span.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/throw_exception.hpp>
#include <iosfwd>
#include <stdexcept>
#include <type_traits>
@ -57,7 +58,12 @@ struct vector_impl : T {
T::resize(n, value_type());
std::fill_n(T::begin(), (std::min)(n, old_size), value_type());
}
}; // namespace detail
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("vector", static_cast<T&>(*this));
}
};
template <class T>
struct array_impl : T {
@ -107,6 +113,13 @@ struct array_impl : T {
std::size_t size() const noexcept { return size_; }
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("size", size_);
auto sp = detail::make_span(T::data(), size_);
ar& make_nvp("array", sp);
}
std::size_t size_ = 0;
};
@ -315,6 +328,12 @@ struct map_impl : T {
std::size_t size() const noexcept { return size_; }
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("size", size_);
ar& make_nvp("map", static_cast<T&>(*this));
}
std::size_t size_ = 0;
};
@ -363,6 +382,11 @@ public:
return std::equal(this->begin(), this->end(), begin(u), end(u), detail::safe_equal{});
}
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("impl", static_cast<impl_type&>(*this));
}
private:
friend struct unsafe_access;
};

View File

@ -13,10 +13,12 @@
#include <boost/config/workaround.hpp>
#include <boost/core/alloc_construct.hpp>
#include <boost/core/exchange.hpp>
#include <boost/core/nvp.hpp>
#include <boost/histogram/detail/iterator_adaptor.hpp>
#include <boost/histogram/detail/large_int.hpp>
#include <boost/histogram/detail/operators.hpp>
#include <boost/histogram/detail/safe_comparison.hpp>
#include <boost/histogram/detail/span.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
@ -506,6 +508,28 @@ public:
buffer_.template make<T>(s, p);
}
template <class Archive>
void serialize(Archive& ar, unsigned /* version */) {
if (Archive::is_loading::value) {
buffer_type tmp(buffer_.alloc);
std::size_t size;
ar& make_nvp("type", tmp.type);
ar& make_nvp("size", size);
tmp.visit([this, size](auto* tp) {
BOOST_ASSERT(tp == nullptr);
using T = std::decay_t<decltype(*tp)>;
buffer_.template make<T>(size);
});
} else {
ar& make_nvp("type", buffer_.type);
ar& make_nvp("size", buffer_.size);
}
buffer_.visit([this, &ar](auto* tp) {
auto sp = detail::make_span(tp, buffer_.size);
ar& make_nvp("buffer", sp);
});
}
private:
struct incrementor {
template <class T>

View File

@ -4,6 +4,7 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/archive/xml_oarchive.hpp>
#include <boost/assert.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/histogram/accumulators.hpp>
@ -24,6 +25,10 @@ int main(int argc, char** argv) {
BOOST_TEST_EQ(a.count(), 3);
BOOST_TEST_EQ(a.value(), 2);
BOOST_TEST_EQ(a.variance(), 0.5);
#ifndef BOOST_NO_EXCEPTIONS
boost::archive::xml_oarchive oa(std::cout);
BOOST_TEST_THROWS(a.serialize(oa, 0), std::runtime_error);
#endif
}
// mean

View File

@ -35,7 +35,7 @@ int main(int argc, char** argv) {
BOOST_TEST_EQ(a, b);
variant<I> c; // load incompatible version
BOOST_TEST_THROWS(load_xml(filename, c), boost::archive::archive_exception);
BOOST_TEST_THROWS(load_xml(filename, c), std::runtime_error);
return boost::report_errors();
}

View File

@ -11,6 +11,7 @@
#include <boost/archive/xml_oarchive.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/core/nvp.hpp>
#include <fstream>
#include <iostream>
#include <string>
@ -39,14 +40,14 @@ void load_xml(const std::string& filename, T& t) {
BOOST_ASSERT(std::strlen(line) < 127);
} while (!ifs.fail() && !ifs.eof() && std::strstr(line, "-->") == nullptr);
boost::archive::xml_iarchive ia(ifs);
ia >> boost::serialization::make_nvp("item", t);
ia >> boost::make_nvp("item", t);
}
template <class T>
void print_xml(const std::string& filename, const T& t) {
std::cout << filename << "\n";
boost::archive::xml_oarchive oa(std::cout);
oa << boost::serialization::make_nvp("item", t);
oa << boost::make_nvp("item", t);
std::cout << std::flush;
}

39
tools/tidy.py Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env python3
# Copyright 2019 Hans Dembinski
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
import subprocess as subp
from pathlib import Path
from multiprocessing.pool import ThreadPool
clang_tidy_cmd = None
for version in range(15, 5, -1):
clang_tidy_cmd = f"clang-tidy-{version}"
if subp.run(("which", clang_tidy_cmd), stdout=subp.DEVNULL).returncode == 0:
break
project_dir = Path(__file__).resolve().parents[1]
assert project_dir.exists()
boost_dir = project_dir.parents[1]
filenames = (project_dir / "include").rglob("*.hpp")
def run_tidy(filename):
n = len(project_dir.parts) + 2
cmd = f"{clang_tidy_cmd} {filename} -- -I{boost_dir}"
return (
cmd,
subp.run(cmd.split(), stdout=subp.PIPE, stderr=subp.STDOUT).stdout.decode(
"utf-8"
),
)
pool = ThreadPool()
for cmd, report in pool.map(run_tidy, filenames):
if report:
print(cmd)
print(report)