mirror of
https://github.com/boostorg/histogram.git
synced 2026-02-18 14:12:11 +00:00
More doc improvements
This commit is contained in:
@@ -26,51 +26,20 @@ using common_axes = mp11::mp_cond<
|
||||
is_sequence_of_axis<U>, U,
|
||||
std::true_type, T
|
||||
>;
|
||||
|
||||
template <class T, class U>
|
||||
using common_container = mp11::mp_cond<
|
||||
is_array_like<T>, T,
|
||||
is_array_like<U>, U,
|
||||
is_vector_like<T>, T,
|
||||
is_vector_like<U>, U,
|
||||
std::true_type, T
|
||||
>;
|
||||
// clang-format on
|
||||
|
||||
template <class T>
|
||||
using type_score = mp11::mp_size_t<((!std::is_pod<T>::value) * 1000 +
|
||||
std::is_floating_point<T>::value * 50 + sizeof(T))>;
|
||||
// Non-PODs rank highest, then floats, than integers; types with more capacity are higher
|
||||
template <class Storage>
|
||||
static constexpr std::size_t type_rank() {
|
||||
using T = typename Storage::value_type;
|
||||
return !std::is_pod<T>::value * 10000 + std::is_floating_point<T>::value * 100 +
|
||||
10 * sizeof(T) + 2 * is_array_like<Storage>::value +
|
||||
is_vector_like<Storage>::value;
|
||||
;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
struct common_storage_impl;
|
||||
|
||||
template <class T, class U>
|
||||
struct common_storage_impl<storage_adaptor<T>, storage_adaptor<U>> {
|
||||
using type =
|
||||
mp11::mp_if_c<(type_score<typename storage_adaptor<T>::value_type>::value >=
|
||||
type_score<typename storage_adaptor<U>::value_type>::value),
|
||||
storage_adaptor<T>, storage_adaptor<U>>;
|
||||
};
|
||||
|
||||
template <class T, class A>
|
||||
struct common_storage_impl<storage_adaptor<T>, unlimited_storage<A>> {
|
||||
using type =
|
||||
mp11::mp_if_c<(type_score<typename storage_adaptor<T>::value_type>::value >=
|
||||
type_score<typename unlimited_storage<A>::value_type>::value),
|
||||
storage_adaptor<T>, unlimited_storage<A>>;
|
||||
};
|
||||
|
||||
template <class C, class A>
|
||||
struct common_storage_impl<unlimited_storage<A>, storage_adaptor<C>>
|
||||
: common_storage_impl<storage_adaptor<C>, unlimited_storage<A>> {};
|
||||
|
||||
template <class A1, class A2>
|
||||
struct common_storage_impl<unlimited_storage<A1>, unlimited_storage<A2>> {
|
||||
using type = unlimited_storage<A1>;
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
using common_storage = typename common_storage_impl<A, B>::type;
|
||||
using common_storage = mp11::mp_if_c<(type_rank<T>() >= type_rank<U>()), T, U>;
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
@@ -215,9 +215,18 @@ BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rmul,
|
||||
BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rdiv,
|
||||
(std::declval<T&>() /= std::declval<U&>()));
|
||||
|
||||
BOOST_HISTOGRAM_DETECT(has_threading_support, (T::has_threading_support));
|
||||
|
||||
template <typename T>
|
||||
using is_storage =
|
||||
mp11::mp_bool<(is_indexable_container<T>::value && has_method_reset<T>::value)>;
|
||||
using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
|
||||
has_threading_support<T>>;
|
||||
|
||||
template <class T>
|
||||
using is_adaptible = mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>;
|
||||
|
||||
template <class T, class _ = remove_cvref_t<T>,
|
||||
class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
|
||||
struct requires_storage_or_adaptible {};
|
||||
|
||||
template <typename T>
|
||||
struct is_tuple_impl : std::false_type {};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <boost/histogram/detail/noop_mutex.hpp>
|
||||
#include <boost/histogram/detail/static_if.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/histogram/storage_adaptor.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <mutex>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
@@ -135,7 +137,7 @@ public:
|
||||
}
|
||||
|
||||
/// Get N-th axis with run-time number.
|
||||
/// Use the version that accepts a compile-time number, if possible.
|
||||
/// Prefer the version that accepts a compile-time number, if you can use it.
|
||||
decltype(auto) axis(unsigned i) const {
|
||||
detail::axis_index_is_valid(axes_, i);
|
||||
return detail::axis_get(axes_, i);
|
||||
@@ -153,13 +155,6 @@ public:
|
||||
not convertible to the value type accepted by the axis or passing the wrong number
|
||||
of arguments causes a throw of `std::invalid_argument`.
|
||||
|
||||
__Axis with multiple arguments__
|
||||
|
||||
If the histogram contains an axis which accepts a `std::tuple` of arguments, the
|
||||
arguments for that axis need to passed as a `std::tuple`, for example,
|
||||
`std::make_tuple(1.2, 2.3)`. If the histogram contains only this axis and no other,
|
||||
the arguments can be passed directly.
|
||||
|
||||
__Optional weight__
|
||||
|
||||
An optional weight can be passed as the first or last argument
|
||||
@@ -173,83 +168,93 @@ public:
|
||||
[sample](boost/histogram/sample.html) helper function can pass one or more arguments to
|
||||
the storage element. If samples and weights are used together, they can be passed in
|
||||
any order at the beginning or end of the argument list.
|
||||
|
||||
__Axis with multiple arguments__
|
||||
|
||||
If the histogram contains an axis which accepts a `std::tuple` of arguments, the
|
||||
arguments for that axis need to passed as a `std::tuple`, for example,
|
||||
`std::make_tuple(1.2, 2.3)`. If the histogram contains only this axis and no other,
|
||||
the arguments can be passed directly.
|
||||
*/
|
||||
template <class... Ts>
|
||||
auto operator()(const Ts&... ts) {
|
||||
iterator operator()(const Ts&... ts) {
|
||||
return operator()(std::make_tuple(ts...));
|
||||
}
|
||||
|
||||
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.
|
||||
template <class... Ts>
|
||||
auto operator()(const std::tuple<Ts...>& t) {
|
||||
iterator operator()(const std::tuple<Ts...>& t) {
|
||||
return detail::fill(axes_, storage_and_mutex_, t);
|
||||
}
|
||||
|
||||
/// Access cell value at integral indices.
|
||||
/**
|
||||
/** Access cell value at integral indices.
|
||||
|
||||
You can pass indices as individual arguments, as a std::tuple of integers, or as an
|
||||
interable range of integers. Passing the wrong number of arguments causes a throw of
|
||||
std::invalid_argument. Passing an index which is out of bounds causes a throw of
|
||||
std::out_of_range.
|
||||
|
||||
@param i index of first axis.
|
||||
@param is indices of second, third, ... axes.
|
||||
@returns reference to cell value.
|
||||
*/
|
||||
template <class... Ts>
|
||||
decltype(auto) at(axis::index_type t, Ts... ts) {
|
||||
return at(std::forward_as_tuple(t, ts...));
|
||||
template <class... Indices>
|
||||
decltype(auto) at(axis::index_type i, Indices... is) {
|
||||
return at(std::make_tuple(i, is...));
|
||||
}
|
||||
|
||||
/// Access cell value at integral indices (read-only).
|
||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
||||
template <class... Ts>
|
||||
decltype(auto) at(axis::index_type t, Ts... ts) const {
|
||||
return at(std::forward_as_tuple(t, ts...));
|
||||
template <class... Indices>
|
||||
decltype(auto) at(axis::index_type i, Indices... is) const {
|
||||
return at(std::make_tuple(i, is...));
|
||||
}
|
||||
|
||||
/// Access cell value at integral indices stored in `std::tuple`.
|
||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
||||
template <typename... Ts>
|
||||
decltype(auto) at(const std::tuple<Ts...>& t) {
|
||||
const auto idx = detail::at(axes_, t);
|
||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
||||
template <typename... Indices>
|
||||
decltype(auto) at(const std::tuple<axis::index_type, Indices...>& is) {
|
||||
const auto idx = detail::at(axes_, is);
|
||||
if (!idx)
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||
return storage_and_mutex_.first()[*idx];
|
||||
}
|
||||
|
||||
/// Access cell value at integral indices stored in `std::tuple` (read-only).
|
||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
||||
template <typename... Ts>
|
||||
decltype(auto) at(const std::tuple<Ts...>& t) const {
|
||||
const auto idx = detail::at(axes_, t);
|
||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
||||
template <typename... Indices>
|
||||
decltype(auto) at(const std::tuple<axis::index_type, Indices...>& is) const {
|
||||
const auto idx = detail::at(axes_, is);
|
||||
if (!idx)
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||
return storage_and_mutex_.first()[*idx];
|
||||
}
|
||||
|
||||
/// Access cell value at integral indices stored in iterable.
|
||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
||||
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
||||
decltype(auto) at(const Iterable& c) {
|
||||
const auto idx = detail::at(axes_, c);
|
||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
||||
decltype(auto) at(const Iterable& is) {
|
||||
const auto idx = detail::at(axes_, is);
|
||||
if (!idx)
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||
return storage_and_mutex_.first()[*idx];
|
||||
}
|
||||
|
||||
/// Access cell value at integral indices stored in iterable (read-only).
|
||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
||||
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
||||
decltype(auto) at(const Iterable& c) const {
|
||||
const auto idx = detail::at(axes_, c);
|
||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
||||
decltype(auto) at(const Iterable& is) const {
|
||||
const auto idx = detail::at(axes_, is);
|
||||
if (!idx)
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||
return storage_and_mutex_.first()[*idx];
|
||||
}
|
||||
|
||||
/// Access value at index (number for rank = 1, else `std::tuple` or iterable).
|
||||
template <class T>
|
||||
decltype(auto) operator[](const T& t) {
|
||||
return at(t);
|
||||
template <class Indices>
|
||||
decltype(auto) operator[](const Indices& is) {
|
||||
return at(is);
|
||||
}
|
||||
|
||||
/// @copydoc operator[]
|
||||
template <class T>
|
||||
decltype(auto) operator[](const T& t) const {
|
||||
return at(t);
|
||||
/// Access value at index (read-only).
|
||||
template <class Indices>
|
||||
decltype(auto) operator[](const Indices& is) const {
|
||||
return at(is);
|
||||
}
|
||||
|
||||
/// Equality operator, tests equality for all axes and the storage.
|
||||
@@ -266,11 +271,10 @@ public:
|
||||
}
|
||||
|
||||
/// Add values of another histogram.
|
||||
template <class A, class S>
|
||||
template <class A, class S,
|
||||
class = std::enable_if_t<detail::has_operator_radd<
|
||||
value_type, typename histogram<A, S>::value_type>::value>>
|
||||
histogram& operator+=(const histogram<A, S>& rhs) {
|
||||
static_assert(detail::has_operator_radd<value_type,
|
||||
typename histogram<A, S>::value_type>::value,
|
||||
"cell value does not support adding value of right-hand-side");
|
||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||
auto rit = unsafe_access::storage(rhs).begin();
|
||||
@@ -280,11 +284,10 @@ public:
|
||||
}
|
||||
|
||||
/// Subtract values of another histogram.
|
||||
template <class A, class S>
|
||||
template <class A, class S,
|
||||
class = std::enable_if_t<detail::has_operator_rsub<
|
||||
value_type, typename histogram<A, S>::value_type>::value>>
|
||||
histogram& operator-=(const histogram<A, S>& rhs) {
|
||||
static_assert(detail::has_operator_rsub<value_type,
|
||||
typename histogram<A, S>::value_type>::value,
|
||||
"cell value does not support subtracting value of right-hand-side");
|
||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||
auto rit = unsafe_access::storage(rhs).begin();
|
||||
@@ -294,11 +297,10 @@ public:
|
||||
}
|
||||
|
||||
/// Multiply by values of another histogram.
|
||||
template <class A, class S>
|
||||
template <class A, class S,
|
||||
class = std::enable_if_t<detail::has_operator_rmul<
|
||||
value_type, typename histogram<A, S>::value_type>::value>>
|
||||
histogram& operator*=(const histogram<A, S>& rhs) {
|
||||
static_assert(detail::has_operator_rmul<value_type,
|
||||
typename histogram<A, S>::value_type>::value,
|
||||
"cell value does not support multiplying by value of right-hand-side");
|
||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||
auto rit = unsafe_access::storage(rhs).begin();
|
||||
@@ -308,11 +310,10 @@ public:
|
||||
}
|
||||
|
||||
/// Divide by values of another histogram.
|
||||
template <class A, class S>
|
||||
template <class A, class S,
|
||||
class = std::enable_if_t<detail::has_operator_rdiv<
|
||||
value_type, typename histogram<A, S>::value_type>::value>>
|
||||
histogram& operator/=(const histogram<A, S>& rhs) {
|
||||
static_assert(detail::has_operator_rdiv<value_type,
|
||||
typename histogram<A, S>::value_type>::value,
|
||||
"cell value does not support dividing by value of right-hand-side");
|
||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||
auto rit = unsafe_access::storage(rhs).begin();
|
||||
@@ -372,41 +373,72 @@ private:
|
||||
friend struct unsafe_access;
|
||||
};
|
||||
|
||||
/**
|
||||
Pairwise add cells of two histograms and return histogram with the sum.
|
||||
|
||||
The returned histogram type is the most efficient and safest one constructible from the
|
||||
inputs, if they are not the same type. If one histogram has a tuple axis, the result has
|
||||
a tuple axis. The chosen storage is the one with the larger dynamic range.
|
||||
*/
|
||||
template <class A1, class S1, class A2, class S2>
|
||||
auto operator+(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||
return r += b;
|
||||
}
|
||||
|
||||
/** Pairwise multiply cells of two histograms and return histogram with the product.
|
||||
|
||||
For notes on the returned histogram type, see operator+.
|
||||
*/
|
||||
template <class A1, class S1, class A2, class S2>
|
||||
auto operator*(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||
return r *= b;
|
||||
}
|
||||
|
||||
/** Pairwise subtract cells of two histograms and return histogram with the difference.
|
||||
|
||||
For notes on the returned histogram type, see operator+.
|
||||
*/
|
||||
template <class A1, class S1, class A2, class S2>
|
||||
auto operator-(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||
return r -= b;
|
||||
}
|
||||
|
||||
/** Pairwise divide cells of two histograms and return histogram with the quotient.
|
||||
|
||||
For notes on the returned histogram type, see operator+.
|
||||
*/
|
||||
template <class A1, class S1, class A2, class S2>
|
||||
auto operator/(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||
return r /= b;
|
||||
}
|
||||
|
||||
/** Multiply all cells of the histogram by a number and return a new histogram.
|
||||
|
||||
If the original histogram has integer cells, the result has double cells.
|
||||
*/
|
||||
template <class A, class S>
|
||||
auto operator*(const histogram<A, S>& h, double x) {
|
||||
auto r = histogram<A, detail::common_storage<S, dense_storage<double>>>(h);
|
||||
return r *= x;
|
||||
}
|
||||
|
||||
/** Multiply all cells of the histogram by a number and return a new histogram.
|
||||
|
||||
If the original histogram has integer cells, the result has double cells.
|
||||
*/
|
||||
template <class A, class S>
|
||||
auto operator*(double x, const histogram<A, S>& h) {
|
||||
return h * x;
|
||||
}
|
||||
|
||||
/** Divide all cells of the histogram by a number and return a new histogram.
|
||||
|
||||
If the original histogram has integer cells, the result has double cells.
|
||||
*/
|
||||
template <class A, class S>
|
||||
auto operator/(const histogram<A, S>& h, double x) {
|
||||
return h * (1.0 / x);
|
||||
@@ -423,21 +455,24 @@ histogram(Axes&& axes, Storage&& storage)
|
||||
|
||||
#endif
|
||||
|
||||
/// Helper function to mark argument as weight.
|
||||
/// @param t argument to be forward to the histogram.
|
||||
/** Helper function to mark argument as weight.
|
||||
|
||||
@param t argument to be forward to the histogram.
|
||||
*/
|
||||
template <typename T>
|
||||
auto weight(T&& t) noexcept {
|
||||
return weight_type<T>{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
/// Helper function to mark arguments as sample.
|
||||
/// @param ts arguments to be forwarded to the accumulator.
|
||||
/** Helper function to mark arguments as sample.
|
||||
|
||||
@param ts arguments to be forwarded to the accumulator.
|
||||
*/
|
||||
template <typename... Ts>
|
||||
auto sample(Ts&&... ts) noexcept {
|
||||
return sample_type<std::tuple<Ts...>>{std::forward_as_tuple(std::forward<Ts>(ts)...)};
|
||||
}
|
||||
|
||||
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
|
||||
template <class T>
|
||||
struct weight_type {
|
||||
T value;
|
||||
@@ -447,7 +482,6 @@ template <class T>
|
||||
struct sample_type {
|
||||
T value;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
@@ -30,7 +30,9 @@ namespace histogram {
|
||||
@param axis First axis instance.
|
||||
@param axes Other axis instances.
|
||||
*/
|
||||
template <class Storage, class Axis, class... Axes, class = detail::requires_axis<Axis>>
|
||||
template <class Storage, class Axis, class... Axes,
|
||||
class = detail::requires_storage_or_adaptible<Storage>,
|
||||
class = detail::requires_axis<Axis>>
|
||||
auto make_histogram_with(Storage&& storage, Axis&& axis, Axes&&... axes) {
|
||||
auto a = std::make_tuple(std::forward<Axis>(axis), std::forward<Axes>(axes)...);
|
||||
using U = detail::remove_cvref_t<Storage>;
|
||||
@@ -66,6 +68,7 @@ auto make_weighted_histogram(Axis&& axis, Axes&&... axes) {
|
||||
@param iterable Iterable range of axis objects.
|
||||
*/
|
||||
template <class Storage, class Iterable,
|
||||
class = detail::requires_storage_or_adaptible<Storage>,
|
||||
class = detail::requires_sequence_of_any_axis<Iterable>>
|
||||
auto make_histogram_with(Storage&& storage, Iterable&& iterable) {
|
||||
using U = detail::remove_cvref_t<Storage>;
|
||||
@@ -101,7 +104,9 @@ auto make_weighted_histogram(Iterable&& iterable) {
|
||||
@param begin Iterator to range of axis objects.
|
||||
@param end Iterator to range of axis objects.
|
||||
*/
|
||||
template <class Storage, class Iterator, class = detail::requires_iterator<Iterator>>
|
||||
template <class Storage, class Iterator,
|
||||
class = detail::requires_storage_or_adaptible<Storage>,
|
||||
class = detail::requires_iterator<Iterator>>
|
||||
auto make_histogram_with(Storage&& storage, Iterator begin, Iterator end) {
|
||||
using T = detail::remove_cvref_t<decltype(*begin)>;
|
||||
return make_histogram_with(std::forward<Storage>(storage), std::vector<T>(begin, end));
|
||||
|
||||
@@ -172,8 +172,8 @@ void serialize(Archive& ar, large_int<Allocator>& x, unsigned /* version */) {
|
||||
|
||||
template <class Archive, class T>
|
||||
void serialize(Archive& ar, storage_adaptor<T>& x, unsigned /* version */) {
|
||||
using impl_t = typename storage_adaptor<T>::base_type;
|
||||
ar& serialization::make_nvp("impl", static_cast<impl_t&>(x));
|
||||
auto& impl = unsafe_access::storage_adaptor_impl(x);
|
||||
ar& serialization::make_nvp("impl", impl);
|
||||
}
|
||||
|
||||
template <class Allocator, class Archive>
|
||||
|
||||
@@ -336,9 +336,9 @@ using storage_adaptor_impl =
|
||||
/// Turns any vector-like, array-like, and map-like container into a storage type.
|
||||
template <class T>
|
||||
class storage_adaptor : public detail::storage_adaptor_impl<T> {
|
||||
public:
|
||||
using base_type = detail::storage_adaptor_impl<T>;
|
||||
using impl_type = detail::storage_adaptor_impl<T>;
|
||||
|
||||
public:
|
||||
// standard copy, move, assign
|
||||
storage_adaptor(storage_adaptor&&) = default;
|
||||
storage_adaptor(const storage_adaptor&) = default;
|
||||
@@ -347,12 +347,12 @@ public:
|
||||
|
||||
// forwarding constructor
|
||||
template <class... Ts>
|
||||
storage_adaptor(Ts&&... ts) : base_type(std::forward<Ts>(ts)...) {}
|
||||
storage_adaptor(Ts&&... ts) : impl_type(std::forward<Ts>(ts)...) {}
|
||||
|
||||
// forwarding assign
|
||||
template <class U>
|
||||
storage_adaptor& operator=(U&& u) {
|
||||
base_type::operator=(std::forward<U>(u));
|
||||
impl_type::operator=(std::forward<U>(u));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -362,6 +362,9 @@ public:
|
||||
using std::end;
|
||||
return std::equal(this->begin(), this->end(), begin(u), end(u), detail::equal{});
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct unsafe_access;
|
||||
};
|
||||
|
||||
} // namespace histogram
|
||||
|
||||
@@ -132,7 +132,6 @@ public:
|
||||
using large_int = detail::large_int<
|
||||
typename std::allocator_traits<allocator_type>::template rebind_alloc<uint64_t>>;
|
||||
|
||||
private:
|
||||
struct buffer_type {
|
||||
// cannot be moved outside of scope of unlimited_storage, large_int is dependent type
|
||||
using types = mp11::mp_list<uint8_t, uint16_t, uint32_t, uint64_t, large_int, double>;
|
||||
@@ -246,12 +245,14 @@ private:
|
||||
mutable void* ptr = nullptr;
|
||||
};
|
||||
|
||||
public:
|
||||
class reference; // forward declare to make friend of const_reference
|
||||
|
||||
/// implementation detail
|
||||
class const_reference {
|
||||
public:
|
||||
const_reference(buffer_type& b, std::size_t i) : bref_(b), idx_(i) {}
|
||||
const_reference(buffer_type& b, std::size_t i) : bref_(b), idx_(i) {
|
||||
BOOST_ASSERT(idx_ < bref_.size);
|
||||
}
|
||||
|
||||
const_reference(const const_reference&) = default;
|
||||
|
||||
@@ -355,6 +356,7 @@ public:
|
||||
friend class reference;
|
||||
};
|
||||
|
||||
/// implementation detail
|
||||
class reference : public const_reference {
|
||||
public:
|
||||
reference(buffer_type& b, std::size_t i) : const_reference(b, i) {}
|
||||
@@ -425,28 +427,28 @@ public:
|
||||
|
||||
private:
|
||||
template <class Value, class Reference>
|
||||
class iterator_t : public detail::iterator_adaptor<iterator_t<Value, Reference>,
|
||||
std::size_t, Reference, Value> {
|
||||
class iterator_impl : public detail::iterator_adaptor<iterator_impl<Value, Reference>,
|
||||
std::size_t, Reference, Value> {
|
||||
public:
|
||||
iterator_t() = default;
|
||||
iterator_impl() = default;
|
||||
template <class V, class R>
|
||||
iterator_t(const iterator_t<V, R>& it)
|
||||
: iterator_t::iterator_adaptor_(it.base()), buffer_(it.buffer_) {}
|
||||
iterator_t(buffer_type* b, std::size_t i) noexcept
|
||||
: iterator_t::iterator_adaptor_(i), buffer_(b) {}
|
||||
iterator_impl(const iterator_impl<V, R>& it)
|
||||
: iterator_impl::iterator_adaptor_(it.base()), buffer_(it.buffer_) {}
|
||||
iterator_impl(buffer_type* b, std::size_t i) noexcept
|
||||
: iterator_impl::iterator_adaptor_(i), buffer_(b) {}
|
||||
|
||||
Reference operator*() const noexcept { return {*buffer_, this->base()}; }
|
||||
|
||||
template <class V, class R>
|
||||
friend class iterator_t;
|
||||
friend class iterator_impl;
|
||||
|
||||
private:
|
||||
mutable buffer_type* buffer_ = nullptr;
|
||||
};
|
||||
|
||||
public:
|
||||
using const_iterator = iterator_t<const value_type, const_reference>;
|
||||
using iterator = iterator_t<value_type, reference>;
|
||||
using const_iterator = iterator_impl<const value_type, const_reference>;
|
||||
using iterator = iterator_impl<value_type, reference>;
|
||||
|
||||
explicit unlimited_storage(const allocator_type& a = {}) : buffer_(a) {}
|
||||
unlimited_storage(const unlimited_storage&) = default;
|
||||
@@ -517,6 +519,7 @@ private:
|
||||
struct incrementor {
|
||||
template <class T>
|
||||
void operator()(T* tp, buffer_type& b, std::size_t i) {
|
||||
BOOST_ASSERT(tp && i < b.size);
|
||||
if (!detail::safe_increment(tp[i])) {
|
||||
using U = detail::next_type<typename buffer_type::types, T>;
|
||||
b.template make<U>(b.size, tp);
|
||||
|
||||
@@ -82,6 +82,15 @@ struct unsafe_access {
|
||||
static constexpr auto& unlimited_storage_buffer(unlimited_storage<Allocator>& storage) {
|
||||
return storage.buffer_;
|
||||
}
|
||||
|
||||
/**
|
||||
Get implementation of storage_adaptor.
|
||||
@param storage instance of storage_adaptor.
|
||||
*/
|
||||
template <class T>
|
||||
static constexpr auto& storage_adaptor_impl(storage_adaptor<T>& storage) {
|
||||
return static_cast<typename storage_adaptor<T>::impl_type&>(storage);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace histogram
|
||||
|
||||
Reference in New Issue
Block a user