feat():initial version
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// 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_ACCUMULATOR_TRAITS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ACCUMULATOR_TRAITS_HPP
|
||||
|
||||
#include <boost/histogram/detail/priority.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
|
||||
// forward declare accumulator_set so that it can be matched below
|
||||
namespace accumulators {
|
||||
template <class, class, class>
|
||||
struct accumulator_set;
|
||||
}
|
||||
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <bool WeightSupport, class... Ts>
|
||||
struct accumulator_traits_holder {
|
||||
static constexpr bool weight_support = WeightSupport;
|
||||
using args = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
// member function pointer with weight_type as first argument is better match
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
|
||||
R (T::*)(boost::histogram::weight_type<U>, Ts...));
|
||||
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
|
||||
R (T::*)(boost::histogram::weight_type<U>&, Ts...));
|
||||
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
|
||||
R (T::*)(boost::histogram::weight_type<U>&&, Ts...));
|
||||
|
||||
template <class R, class T, class U, class... Ts>
|
||||
accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
|
||||
R (T::*)(const boost::histogram::weight_type<U>&, Ts...));
|
||||
|
||||
// member function pointer only considered if all specializations above fail
|
||||
template <class R, class T, class... Ts>
|
||||
accumulator_traits_holder<false, Ts...> accumulator_traits_impl_call_op(R (T::*)(Ts...));
|
||||
|
||||
template <class T>
|
||||
auto accumulator_traits_impl(T&, priority<1>)
|
||||
-> decltype(accumulator_traits_impl_call_op(&T::operator()));
|
||||
|
||||
template <class T>
|
||||
auto accumulator_traits_impl(T&, priority<1>)
|
||||
-> decltype(std::declval<T&>() += 0, accumulator_traits_holder<true>{});
|
||||
|
||||
template <class T>
|
||||
auto accumulator_traits_impl(T&, priority<0>) -> accumulator_traits_holder<false>;
|
||||
|
||||
// for boost.accumulators compatibility
|
||||
template <class S, class F, class W>
|
||||
accumulator_traits_holder<false, S> accumulator_traits_impl(
|
||||
boost::accumulators::accumulator_set<S, F, W>&, priority<1>) {
|
||||
static_assert(std::is_same<W, void>::value,
|
||||
"accumulator_set with weights is not directly supported, please use "
|
||||
"a wrapper class that implements the Accumulator concept");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using accumulator_traits =
|
||||
decltype(accumulator_traits_impl(std::declval<T&>(), priority<1>{}));
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2015-2018 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_ARGS_TYPE_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ARGS_TYPE_HPP
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct args_type_impl {
|
||||
using T::ERROR_this_should_never_be_instantiated_please_write_an_issue;
|
||||
};
|
||||
|
||||
template <class R, class T, class... Ts>
|
||||
struct args_type_impl<R (T::*)(Ts...)> {
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
template <class R, class T, class... Ts>
|
||||
struct args_type_impl<R (T ::*)(Ts...) const> {
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
template <class R, class... Ts>
|
||||
struct args_type_impl<R (*)(Ts...)> {
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
#if __cpp_noexcept_function_type >= 201510
|
||||
template <class R, class T, class... Ts>
|
||||
struct args_type_impl<R (T::*)(Ts...) noexcept> {
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
template <class R, class T, class... Ts>
|
||||
struct args_type_impl<R (T ::*)(Ts...) const noexcept> {
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
|
||||
template <class R, class... Ts>
|
||||
struct args_type_impl<R (*)(Ts...) noexcept> {
|
||||
using type = std::tuple<Ts...>;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class FunctionPointer>
|
||||
using args_type = typename args_type_impl<FunctionPointer>::type;
|
||||
|
||||
template <class T, std::size_t N = 0>
|
||||
using arg_type = std::tuple_element_t<N, args_type<T>>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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_ARGUMENT_TRAITS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ARGUMENT_TRAITS_HPP
|
||||
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integral.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <tuple>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct is_weight_impl : mp11::mp_false {};
|
||||
|
||||
template <class T>
|
||||
struct is_weight_impl<weight_type<T>> : mp11::mp_true {};
|
||||
|
||||
template <class T>
|
||||
using is_weight = is_weight_impl<T>;
|
||||
|
||||
template <class T>
|
||||
struct is_sample_impl : mp11::mp_false {};
|
||||
|
||||
template <class T>
|
||||
struct is_sample_impl<sample_type<T>> : mp11::mp_true {};
|
||||
|
||||
template <class T>
|
||||
using is_sample = is_sample_impl<T>;
|
||||
|
||||
template <int Idx, class L>
|
||||
struct sample_args_impl {
|
||||
using type = mp11::mp_first<std::decay_t<mp11::mp_at_c<L, (Idx >= 0 ? Idx : 0)>>>;
|
||||
};
|
||||
|
||||
template <class L>
|
||||
struct sample_args_impl<-1, L> {
|
||||
using type = std::tuple<>;
|
||||
};
|
||||
|
||||
template <std::size_t NArgs, std::size_t Start, int WeightPos, int SamplePos,
|
||||
class SampleArgs>
|
||||
struct argument_traits_holder {
|
||||
using nargs = mp11::mp_size_t<NArgs>;
|
||||
using start = mp11::mp_size_t<Start>;
|
||||
using wpos = mp11::mp_int<WeightPos>;
|
||||
using spos = mp11::mp_int<SamplePos>;
|
||||
using sargs = SampleArgs;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct argument_traits_impl {
|
||||
using list_ = mp11::mp_list<Ts...>;
|
||||
static constexpr std::size_t size_ = sizeof...(Ts);
|
||||
static constexpr std::size_t weight_ = mp11::mp_find_if<list_, is_weight>::value;
|
||||
static constexpr std::size_t sample_ = mp11::mp_find_if<list_, is_sample>::value;
|
||||
static constexpr int spos_ = (sample_ < size_ ? static_cast<int>(sample_) : -1);
|
||||
static constexpr int wpos_ = (weight_ < size_ ? static_cast<int>(weight_) : -1);
|
||||
|
||||
using type =
|
||||
argument_traits_holder<(size_ - (weight_ < size_) - (sample_ < size_)),
|
||||
(weight_ < size_ && sample_ < size_ &&
|
||||
(weight_ + sample_ < 2)
|
||||
? 2
|
||||
: ((weight_ == 0 || sample_ == 0) ? 1 : 0)),
|
||||
wpos_, spos_, typename sample_args_impl<spos_, list_>::type>;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
using argument_traits = typename argument_traits_impl<Ts...>::type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -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_ARRAY_WRAPPER_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ARRAY_WRAPPER_HPP
|
||||
|
||||
#include <boost/core/nvp.hpp>
|
||||
#include <boost/histogram/detail/span.hpp>
|
||||
#include <boost/histogram/detail/static_if.hpp>
|
||||
#include <boost/mp11/function.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class = decltype(&T::template save_array<int>)>
|
||||
struct has_save_array_impl;
|
||||
|
||||
template <class T, class = decltype(&T::template load_array<int>)>
|
||||
struct has_load_array_impl;
|
||||
|
||||
template <class T>
|
||||
using has_array_optimization = mp11::mp_or<mp11::mp_valid<has_save_array_impl, T>,
|
||||
mp11::mp_valid<has_load_array_impl, T>>;
|
||||
|
||||
template <class T>
|
||||
struct array_wrapper {
|
||||
using pointer = T*;
|
||||
|
||||
pointer ptr;
|
||||
std::size_t size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, unsigned /* version */) {
|
||||
static_if_c<(has_array_optimization<Archive>::value &&
|
||||
std::is_trivially_copyable<T>::value)>(
|
||||
[this](auto& ar) {
|
||||
// cannot use and therefore bypass save_array / load_array interface, because
|
||||
// it requires exact type boost::serialization::array_wrapper<T>
|
||||
static_if_c<Archive::is_loading::value>(
|
||||
[this](auto& ar) { ar.load_binary(this->ptr, sizeof(T) * this->size); },
|
||||
[this](auto& ar) { ar.save_binary(this->ptr, sizeof(T) * this->size); },
|
||||
ar);
|
||||
},
|
||||
[this](auto& ar) {
|
||||
for (auto&& x : boost::histogram::detail::make_span(this->ptr, this->size))
|
||||
ar& make_nvp("item", x);
|
||||
},
|
||||
ar);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
auto make_array_wrapper(T* t, std::size_t s) {
|
||||
return array_wrapper<T>{t, s};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
439
install/boost_1_75_0/include/boost/histogram/detail/axes.hpp
Normal file
439
install/boost_1_75_0/include/boost/histogram/detail/axes.hpp
Normal file
@@ -0,0 +1,439 @@
|
||||
// Copyright 2015-2018 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_AXES_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_AXES_HPP
|
||||
|
||||
#include <array>
|
||||
#include <boost/core/nvp.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/axis/variant.hpp>
|
||||
#include <boost/histogram/detail/make_default.hpp>
|
||||
#include <boost/histogram/detail/nonmember_container_access.hpp>
|
||||
#include <boost/histogram/detail/optional_index.hpp>
|
||||
#include <boost/histogram/detail/priority.hpp>
|
||||
#include <boost/histogram/detail/relaxed_tuple_size.hpp>
|
||||
#include <boost/histogram/detail/static_if.hpp>
|
||||
#include <boost/histogram/detail/sub_array.hpp>
|
||||
#include <boost/histogram/detail/try_cast.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integer_sequence.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class Unary>
|
||||
void for_each_axis_impl(dynamic_size, T& t, Unary& p) {
|
||||
for (auto& a : t) axis::visit(p, a);
|
||||
}
|
||||
|
||||
template <class N, class T, class Unary>
|
||||
void for_each_axis_impl(N, T& t, Unary& p) {
|
||||
mp11::tuple_for_each(t, p);
|
||||
}
|
||||
|
||||
// also matches const T and const Unary
|
||||
template <class T, class Unary>
|
||||
void for_each_axis(T&& t, Unary&& p) {
|
||||
for_each_axis_impl(relaxed_tuple_size(t), t, p);
|
||||
}
|
||||
|
||||
// merge if a and b are discrete and growing
|
||||
struct axis_merger {
|
||||
template <class T, class U>
|
||||
T operator()(const T& a, const U& u) {
|
||||
const T* bp = ptr_cast<T>(&u);
|
||||
if (!bp) BOOST_THROW_EXCEPTION(std::invalid_argument("axes not mergable"));
|
||||
using O = axis::traits::get_options<T>;
|
||||
constexpr bool discrete_and_growing =
|
||||
axis::traits::is_continuous<T>::value == false && O::test(axis::option::growth);
|
||||
return impl(mp11::mp_bool<discrete_and_growing>{}, a, *bp);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T impl(std::false_type, const T& a, const T& b) {
|
||||
if (!relaxed_equal{}(a, b))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes not mergable"));
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T impl(std::true_type, const T& a, const T& b) {
|
||||
if (relaxed_equal{}(axis::traits::metadata(a), axis::traits::metadata(b))) {
|
||||
auto r = a;
|
||||
if (axis::traits::is_ordered<T>::value) {
|
||||
r.update(b.value(0));
|
||||
r.update(b.value(b.size() - 1));
|
||||
} else
|
||||
for (auto&& v : b) r.update(v);
|
||||
return r;
|
||||
}
|
||||
return impl(std::false_type{}, a, b);
|
||||
}
|
||||
};
|
||||
|
||||
// create empty dynamic axis which can store any axes types from the argument
|
||||
template <class T>
|
||||
auto make_empty_dynamic_axes(const T& axes) {
|
||||
return make_default(axes);
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
auto make_empty_dynamic_axes(const std::tuple<Ts...>&) {
|
||||
using namespace ::boost::mp11;
|
||||
using L = mp_unique<axis::variant<Ts...>>;
|
||||
// return std::vector<axis::variant<Axis0, Axis1, ...>> or std::vector<Axis0>
|
||||
return std::vector<mp_if_c<(mp_size<L>::value == 1), mp_first<L>, L>>{};
|
||||
}
|
||||
|
||||
template <class T, class Functor, std::size_t... Is>
|
||||
auto axes_transform_impl(const T& t, Functor&& f, mp11::index_sequence<Is...>) {
|
||||
return std::make_tuple(f(Is, std::get<Is>(t))...);
|
||||
}
|
||||
|
||||
// warning: sequential order of functor execution is platform-dependent!
|
||||
template <class... Ts, class Functor>
|
||||
auto axes_transform(const std::tuple<Ts...>& old_axes, Functor&& f) {
|
||||
return axes_transform_impl(old_axes, std::forward<Functor>(f),
|
||||
mp11::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
|
||||
// changing axes type is not supported
|
||||
template <class T, class Functor>
|
||||
T axes_transform(const T& old_axes, Functor&& f) {
|
||||
T axes = make_default(old_axes);
|
||||
axes.reserve(old_axes.size());
|
||||
for_each_axis(old_axes, [&](const auto& a) { axes.emplace_back(f(axes.size(), a)); });
|
||||
return axes;
|
||||
}
|
||||
|
||||
template <class... Ts, class Binary, std::size_t... Is>
|
||||
std::tuple<Ts...> axes_transform_impl(const std::tuple<Ts...>& lhs,
|
||||
const std::tuple<Ts...>& rhs, Binary&& bin,
|
||||
mp11::index_sequence<Is...>) {
|
||||
return std::make_tuple(bin(std::get<Is>(lhs), std::get<Is>(rhs))...);
|
||||
}
|
||||
|
||||
template <class... Ts, class Binary>
|
||||
std::tuple<Ts...> axes_transform(const std::tuple<Ts...>& lhs,
|
||||
const std::tuple<Ts...>& rhs, Binary&& bin) {
|
||||
return axes_transform_impl(lhs, rhs, bin, mp11::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
|
||||
template <class T, class Binary>
|
||||
T axes_transform(const T& lhs, const T& rhs, Binary&& bin) {
|
||||
T ax = make_default(lhs);
|
||||
ax.reserve(lhs.size());
|
||||
using std::begin;
|
||||
auto ir = begin(rhs);
|
||||
for (auto&& li : lhs) {
|
||||
axis::visit(
|
||||
[&](const auto& li) {
|
||||
axis::visit([&](const auto& ri) { ax.emplace_back(bin(li, ri)); }, *ir);
|
||||
},
|
||||
li);
|
||||
++ir;
|
||||
}
|
||||
return ax;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
unsigned axes_rank(const T& axes) {
|
||||
using std::begin;
|
||||
using std::end;
|
||||
return static_cast<unsigned>(std::distance(begin(axes), end(axes)));
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
constexpr unsigned axes_rank(const std::tuple<Ts...>&) {
|
||||
return static_cast<unsigned>(sizeof...(Ts));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void throw_if_axes_is_too_large(const T& axes) {
|
||||
if (axes_rank(axes) > BOOST_HISTOGRAM_DETAIL_AXES_LIMIT)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("length of axis vector exceeds internal buffers, "
|
||||
"recompile with "
|
||||
"-DBOOST_HISTOGRAM_DETAIL_AXES_LIMIT=<new max size> "
|
||||
"to increase internal buffers"));
|
||||
}
|
||||
|
||||
// tuple is never too large because internal buffers adapt to size of tuple
|
||||
template <class... Ts>
|
||||
void throw_if_axes_is_too_large(const std::tuple<Ts...>&) {}
|
||||
|
||||
template <unsigned N, class... Ts>
|
||||
decltype(auto) axis_get(std::tuple<Ts...>& axes) {
|
||||
return std::get<N>(axes);
|
||||
}
|
||||
|
||||
template <unsigned N, class... Ts>
|
||||
decltype(auto) axis_get(const std::tuple<Ts...>& axes) {
|
||||
return std::get<N>(axes);
|
||||
}
|
||||
|
||||
template <unsigned N, class T>
|
||||
decltype(auto) axis_get(T& axes) {
|
||||
return axes[N];
|
||||
}
|
||||
|
||||
template <unsigned N, class T>
|
||||
decltype(auto) axis_get(const T& axes) {
|
||||
return axes[N];
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
auto axis_get(std::tuple<Ts...>& axes, const unsigned i) {
|
||||
constexpr auto S = sizeof...(Ts);
|
||||
using V = mp11::mp_unique<axis::variant<Ts*...>>;
|
||||
return mp11::mp_with_index<S>(i, [&axes](auto i) { return V(&std::get<i>(axes)); });
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
auto axis_get(const std::tuple<Ts...>& axes, const unsigned i) {
|
||||
constexpr auto S = sizeof...(Ts);
|
||||
using V = mp11::mp_unique<axis::variant<const Ts*...>>;
|
||||
return mp11::mp_with_index<S>(i, [&axes](auto i) { return V(&std::get<i>(axes)); });
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) axis_get(T& axes, const unsigned i) {
|
||||
return axes[i];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) axis_get(const T& axes, const unsigned i) {
|
||||
return axes[i];
|
||||
}
|
||||
|
||||
template <class T, class U, std::size_t... Is>
|
||||
bool axes_equal_impl(const T& t, const U& u, mp11::index_sequence<Is...>) noexcept {
|
||||
bool result = true;
|
||||
// operator folding emulation
|
||||
(void)std::initializer_list<bool>{
|
||||
(result &= relaxed_equal{}(std::get<Is>(t), std::get<Is>(u)))...};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class... Ts, class... Us>
|
||||
bool axes_equal_impl(const std::tuple<Ts...>& t, const std::tuple<Us...>& u) noexcept {
|
||||
return axes_equal_impl(
|
||||
t, u, mp11::make_index_sequence<std::min(sizeof...(Ts), sizeof...(Us))>{});
|
||||
}
|
||||
|
||||
template <class... Ts, class U>
|
||||
bool axes_equal_impl(const std::tuple<Ts...>& t, const U& u) noexcept {
|
||||
using std::begin;
|
||||
auto iu = begin(u);
|
||||
bool result = true;
|
||||
mp11::tuple_for_each(t, [&](const auto& ti) {
|
||||
axis::visit([&](const auto& ui) { result &= relaxed_equal{}(ti, ui); }, *iu);
|
||||
++iu;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class... Us>
|
||||
bool axes_equal_impl(const T& t, const std::tuple<Us...>& u) noexcept {
|
||||
return axes_equal_impl(u, t);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool axes_equal_impl(const T& t, const U& u) noexcept {
|
||||
using std::begin;
|
||||
auto iu = begin(u);
|
||||
bool result = true;
|
||||
for (auto&& ti : t) {
|
||||
axis::visit(
|
||||
[&](const auto& ti) {
|
||||
axis::visit([&](const auto& ui) { result &= relaxed_equal{}(ti, ui); }, *iu);
|
||||
},
|
||||
ti);
|
||||
++iu;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool axes_equal(const T& t, const U& u) noexcept {
|
||||
return axes_rank(t) == axes_rank(u) && axes_equal_impl(t, u);
|
||||
}
|
||||
|
||||
// enable_if_t needed by msvc :(
|
||||
template <class... Ts, class... Us>
|
||||
std::enable_if_t<!(std::is_same<std::tuple<Ts...>, std::tuple<Us...>>::value)>
|
||||
axes_assign(std::tuple<Ts...>&, const std::tuple<Us...>&) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("cannot assign axes, types do not match"));
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
void axes_assign(std::tuple<Ts...>& t, const std::tuple<Ts...>& u) {
|
||||
t = u;
|
||||
}
|
||||
|
||||
template <class... Ts, class U>
|
||||
void axes_assign(std::tuple<Ts...>& t, const U& u) {
|
||||
if (sizeof...(Ts) == detail::size(u)) {
|
||||
using std::begin;
|
||||
auto iu = begin(u);
|
||||
mp11::tuple_for_each(t, [&](auto& ti) {
|
||||
using T = std::decay_t<decltype(ti)>;
|
||||
ti = axis::get<T>(*iu);
|
||||
++iu;
|
||||
});
|
||||
return;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("cannot assign axes, sizes do not match"));
|
||||
}
|
||||
|
||||
template <class T, class... Us>
|
||||
void axes_assign(T& t, const std::tuple<Us...>& u) {
|
||||
// resize instead of reserve, because t may not be empty and we want exact capacity
|
||||
t.resize(sizeof...(Us));
|
||||
using std::begin;
|
||||
auto it = begin(t);
|
||||
mp11::tuple_for_each(u, [&](const auto& ui) { *it++ = ui; });
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
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 /* version */) {
|
||||
mp11::tuple_for_each(t, [&ar](auto& x) { ar& make_nvp("item", x); });
|
||||
}
|
||||
};
|
||||
proxy p{axes};
|
||||
ar& make_nvp("axes", p);
|
||||
}
|
||||
|
||||
// total number of bins including *flow bins
|
||||
template <class T>
|
||||
std::size_t bincount(const T& axes) {
|
||||
std::size_t n = 1;
|
||||
for_each_axis(axes, [&n](const auto& a) {
|
||||
const auto old = n;
|
||||
const auto s = axis::traits::extent(a);
|
||||
n *= s;
|
||||
if (s > 0 && n < old) BOOST_THROW_EXCEPTION(std::overflow_error("bincount overflow"));
|
||||
});
|
||||
return n;
|
||||
}
|
||||
|
||||
// initial offset for the linear index
|
||||
template <class T>
|
||||
std::size_t offset(const T& axes) {
|
||||
std::size_t n = 0;
|
||||
auto stride = static_cast<std::size_t>(1);
|
||||
for_each_axis(axes, [&](const auto& a) {
|
||||
if (axis::traits::options(a) & axis::option::growth)
|
||||
n = invalid_index;
|
||||
else if (n != invalid_index && axis::traits::options(a) & axis::option::underflow)
|
||||
n += stride;
|
||||
stride *= axis::traits::extent(a);
|
||||
});
|
||||
return n;
|
||||
}
|
||||
|
||||
// make default-constructed buffer (no initialization for POD types)
|
||||
template <class T, class A>
|
||||
auto make_stack_buffer(const A& a) {
|
||||
return sub_array<T, buffer_size<A>::value>(axes_rank(a));
|
||||
}
|
||||
|
||||
// make buffer with elements initialized to v
|
||||
template <class T, class A>
|
||||
auto make_stack_buffer(const A& a, const T& t) {
|
||||
return sub_array<T, buffer_size<A>::value>(axes_rank(a), t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using has_underflow =
|
||||
decltype(axis::traits::get_options<T>::test(axis::option::underflow));
|
||||
|
||||
template <class T>
|
||||
using is_growing = decltype(axis::traits::get_options<T>::test(axis::option::growth));
|
||||
|
||||
template <class T>
|
||||
using is_not_inclusive = mp11::mp_not<axis::traits::is_inclusive<T>>;
|
||||
|
||||
// for vector<T>
|
||||
template <class T>
|
||||
struct axis_types_impl {
|
||||
using type = mp11::mp_list<std::decay_t<T>>;
|
||||
};
|
||||
|
||||
// for vector<variant<Ts...>>
|
||||
template <class... Ts>
|
||||
struct axis_types_impl<axis::variant<Ts...>> {
|
||||
using type = mp11::mp_list<std::decay_t<Ts>...>;
|
||||
};
|
||||
|
||||
// for tuple<Ts...>
|
||||
template <class... Ts>
|
||||
struct axis_types_impl<std::tuple<Ts...>> {
|
||||
using type = mp11::mp_list<std::decay_t<Ts>...>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using axis_types =
|
||||
typename axis_types_impl<mp11::mp_if<is_vector_like<T>, mp11::mp_first<T>, T>>::type;
|
||||
|
||||
template <template <class> class Trait, class Axes>
|
||||
using has_special_axis = mp11::mp_any_of<axis_types<Axes>, Trait>;
|
||||
|
||||
template <class Axes>
|
||||
using has_growing_axis = mp11::mp_any_of<axis_types<Axes>, is_growing>;
|
||||
|
||||
template <class Axes>
|
||||
using has_non_inclusive_axis = mp11::mp_any_of<axis_types<Axes>, is_not_inclusive>;
|
||||
|
||||
template <class T>
|
||||
constexpr std::size_t type_score() {
|
||||
return sizeof(T) *
|
||||
(std::is_integral<T>::value ? 1 : std::is_floating_point<T>::value ? 10 : 100);
|
||||
}
|
||||
|
||||
// arbitrary ordering of types
|
||||
template <class T, class U>
|
||||
using type_less = mp11::mp_bool<(type_score<T>() < type_score<U>())>;
|
||||
|
||||
template <class Axes>
|
||||
using value_types = mp11::mp_sort<
|
||||
mp11::mp_unique<mp11::mp_transform<axis::traits::value_type, axis_types<Axes>>>,
|
||||
type_less>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2015-2018 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_COMMON_TYPE_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_COMMON_TYPE_HPP
|
||||
|
||||
#include <boost/histogram/detail/detect.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
// clang-format off
|
||||
template <class T, class U>
|
||||
using common_axes = mp11::mp_cond<
|
||||
is_tuple<T>, T,
|
||||
is_tuple<U>, U,
|
||||
is_sequence_of_axis<T>, T,
|
||||
is_sequence_of_axis<U>, U,
|
||||
std::true_type, T
|
||||
>;
|
||||
// clang-format on
|
||||
|
||||
// Non-PODs rank highest, then floats, than integers; types with more capacity are higher
|
||||
template <class Storage>
|
||||
constexpr std::size_t type_rank() {
|
||||
using T = typename Storage::value_type;
|
||||
return !std::is_arithmetic<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>
|
||||
using common_storage = mp11::mp_if_c<(type_rank<T>() >= type_rank<U>()), T, U>;
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018-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_CONVERT_INTEGER_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_CONVERT_INTEGER_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
using convert_integer =
|
||||
std::conditional_t<std::is_integral<std::decay_t<T>>::value, U, T>;
|
||||
|
||||
}
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
// 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_COUNTING_STREAMBUF_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP
|
||||
|
||||
#include <boost/core/exchange.hpp>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
// detect how many characters will be printed by formatted output
|
||||
template <class CharT, class Traits = std::char_traits<CharT>>
|
||||
struct counting_streambuf : std::basic_streambuf<CharT, Traits> {
|
||||
using base_t = std::basic_streambuf<CharT, Traits>;
|
||||
using typename base_t::char_type;
|
||||
using typename base_t::int_type;
|
||||
|
||||
std::streamsize* p_count;
|
||||
|
||||
counting_streambuf(std::streamsize& c) : p_count(&c) {}
|
||||
|
||||
std::streamsize xsputn(const char_type* /* s */, std::streamsize n) override {
|
||||
*p_count += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
int_type overflow(int_type ch) override {
|
||||
++*p_count;
|
||||
return ch;
|
||||
}
|
||||
};
|
||||
|
||||
template <class C, class T>
|
||||
struct count_guard {
|
||||
using bos = std::basic_ostream<C, T>;
|
||||
using bsb = std::basic_streambuf<C, T>;
|
||||
|
||||
counting_streambuf<C, T> csb;
|
||||
bos* p_os;
|
||||
bsb* p_rdbuf;
|
||||
|
||||
count_guard(bos& os, std::streamsize& s) : csb(s), p_os(&os), p_rdbuf(os.rdbuf(&csb)) {}
|
||||
|
||||
count_guard(count_guard&& o)
|
||||
: csb(o.csb), p_os(boost::exchange(o.p_os, nullptr)), p_rdbuf(o.p_rdbuf) {}
|
||||
|
||||
count_guard& operator=(count_guard&& o) {
|
||||
if (this != &o) {
|
||||
csb = std::move(o.csb);
|
||||
p_os = boost::exchange(o.p_os, nullptr);
|
||||
p_rdbuf = o.p_rdbuf;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~count_guard() {
|
||||
if (p_os) p_os->rdbuf(p_rdbuf);
|
||||
}
|
||||
};
|
||||
|
||||
template <class C, class T>
|
||||
count_guard<C, T> make_count_guard(std::basic_ostream<C, T>& os, std::streamsize& s) {
|
||||
return {os, s};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
207
install/boost_1_75_0/include/boost/histogram/detail/detect.hpp
Normal file
207
install/boost_1_75_0/include/boost/histogram/detail/detect.hpp
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright 2015-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_DETECT_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_DETECT_HPP
|
||||
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/function.hpp> // mp_and, mp_or
|
||||
#include <boost/mp11/integral.hpp> // mp_not
|
||||
#include <boost/mp11/list.hpp> // mp_first
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
// forward declaration
|
||||
namespace boost {
|
||||
namespace variant2 {
|
||||
template <class...>
|
||||
class variant;
|
||||
} // namespace variant2
|
||||
} // namespace boost
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
#define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
|
||||
template <class U> \
|
||||
struct name##_impl { \
|
||||
typedef char yes[1]; \
|
||||
typedef char no[2]; \
|
||||
template <class T> \
|
||||
static yes& test(T& t, decltype(cond, 0)); \
|
||||
template <class T> \
|
||||
static no& test(T&, float); \
|
||||
using type = \
|
||||
std::integral_constant<bool, (sizeof(test(std::declval<U&>(), 0)) == 1)>; \
|
||||
}; \
|
||||
template <class T> \
|
||||
using name = typename name##_impl<T>::type
|
||||
|
||||
#define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
|
||||
template <class V, class W> \
|
||||
struct name##_impl { \
|
||||
typedef char yes[1]; \
|
||||
typedef char no[2]; \
|
||||
template <class T, class U> \
|
||||
static yes& test(decltype(cond, 0)); \
|
||||
template <class, class> \
|
||||
static no& test(float); \
|
||||
using type = std::integral_constant<bool, (sizeof(test<V, W>(0)) == 1)>; \
|
||||
}; \
|
||||
template <class T, class U = T> \
|
||||
using name = typename name##_impl<T, U>::type
|
||||
|
||||
// reset has overloads, trying to get pmf in this case always fails
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]);
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
|
||||
is_transform,
|
||||
(std::declval<T&>().inverse(std::declval<T&>().forward(std::declval<U>()))));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container,
|
||||
(t[0], t.size(), std::begin(t), std::end(t)));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like,
|
||||
(t[0], t.size(), t.resize(0), std::begin(t), std::end(t)));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value,
|
||||
std::begin(t), std::end(t)));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, ((typename T::key_type*)nullptr,
|
||||
(typename T::mapped_type*)nullptr,
|
||||
std::begin(t), std::end(t)));
|
||||
|
||||
// ok: is_axis is false for axis::variant, because T::index is templated
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t)));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator,
|
||||
(typename std::iterator_traits<T>::iterator_category{}));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t);
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() ==
|
||||
std::declval<const U&>()));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd,
|
||||
(std::declval<T&>() += std::declval<U>()));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub,
|
||||
(std::declval<T&>() -= std::declval<U>()));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul,
|
||||
(std::declval<T&>() *= std::declval<U>()));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv,
|
||||
(std::declval<T&>() /= std::declval<U>()));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
|
||||
has_method_eq, (std::declval<const T&>().operator==(std::declval<const U&>())));
|
||||
|
||||
BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
|
||||
|
||||
template <class T>
|
||||
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_and<mp11::mp_not<is_storage<T>>,
|
||||
mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>;
|
||||
|
||||
template <class T>
|
||||
struct is_tuple_impl : std::false_type {};
|
||||
|
||||
template <class... Ts>
|
||||
struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
|
||||
|
||||
template <class T>
|
||||
using is_tuple = typename is_tuple_impl<T>::type;
|
||||
|
||||
template <class T>
|
||||
struct is_variant_impl : std::false_type {};
|
||||
|
||||
template <class... Ts>
|
||||
struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {};
|
||||
|
||||
template <class T>
|
||||
using is_variant = typename is_variant_impl<T>::type;
|
||||
|
||||
template <class T>
|
||||
struct is_axis_variant_impl : std::false_type {};
|
||||
|
||||
template <class... Ts>
|
||||
struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {};
|
||||
|
||||
template <class T>
|
||||
using is_axis_variant = typename is_axis_variant_impl<T>::type;
|
||||
|
||||
template <class T>
|
||||
using is_any_axis = mp11::mp_or<is_axis<T>, is_axis_variant<T>>;
|
||||
|
||||
template <class T>
|
||||
using is_sequence_of_axis = mp11::mp_and<is_iterable<T>, is_axis<mp11::mp_first<T>>>;
|
||||
|
||||
template <class T>
|
||||
using is_sequence_of_axis_variant =
|
||||
mp11::mp_and<is_iterable<T>, is_axis_variant<mp11::mp_first<T>>>;
|
||||
|
||||
template <class T>
|
||||
using is_sequence_of_any_axis =
|
||||
mp11::mp_and<is_iterable<T>, is_any_axis<mp11::mp_first<T>>>;
|
||||
|
||||
// poor-mans concept checks
|
||||
template <class T, class = std::enable_if_t<is_storage<std::decay_t<T>>::value>>
|
||||
struct requires_storage {};
|
||||
|
||||
template <class T, class _ = std::decay_t<T>,
|
||||
class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
|
||||
struct requires_storage_or_adaptible {};
|
||||
|
||||
template <class T, class = std::enable_if_t<is_iterator<std::decay_t<T>>::value>>
|
||||
struct requires_iterator {};
|
||||
|
||||
template <class T, class = std::enable_if_t<
|
||||
is_iterable<std::remove_cv_t<std::remove_reference_t<T>>>::value>>
|
||||
struct requires_iterable {};
|
||||
|
||||
template <class T, class = std::enable_if_t<is_axis<std::decay_t<T>>::value>>
|
||||
struct requires_axis {};
|
||||
|
||||
template <class T, class = std::enable_if_t<is_any_axis<std::decay_t<T>>::value>>
|
||||
struct requires_any_axis {};
|
||||
|
||||
template <class T, class = std::enable_if_t<is_sequence_of_axis<std::decay_t<T>>::value>>
|
||||
struct requires_sequence_of_axis {};
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<is_sequence_of_axis_variant<std::decay_t<T>>::value>>
|
||||
struct requires_sequence_of_axis_variant {};
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<is_sequence_of_any_axis<std::decay_t<T>>::value>>
|
||||
struct requires_sequence_of_any_axis {};
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>>
|
||||
struct requires_axes {};
|
||||
|
||||
template <class T, class U,
|
||||
class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>>
|
||||
struct requires_transform {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
348
install/boost_1_75_0/include/boost/histogram/detail/fill.hpp
Normal file
348
install/boost_1_75_0/include/boost/histogram/detail/fill.hpp
Normal file
@@ -0,0 +1,348 @@
|
||||
// Copyright 2015-2018 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_FILL_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_FILL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/axis/variant.hpp>
|
||||
#include <boost/histogram/detail/argument_traits.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/linearize.hpp>
|
||||
#include <boost/histogram/detail/make_default.hpp>
|
||||
#include <boost/histogram/detail/optional_index.hpp>
|
||||
#include <boost/histogram/detail/priority.hpp>
|
||||
#include <boost/histogram/detail/tuple_slice.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integral.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
struct sample_args_passed_vs_expected;
|
||||
|
||||
template <class... Passed, class... Expected>
|
||||
struct sample_args_passed_vs_expected<std::tuple<Passed...>, std::tuple<Expected...>> {
|
||||
static_assert(!(sizeof...(Expected) > 0 && sizeof...(Passed) == 0),
|
||||
"error: accumulator requires samples, but sample argument is missing");
|
||||
static_assert(
|
||||
!(sizeof...(Passed) > 0 && sizeof...(Expected) == 0),
|
||||
"error: accumulator does not accept samples, but sample argument is passed");
|
||||
static_assert(sizeof...(Passed) == sizeof...(Expected),
|
||||
"error: numbers of passed and expected sample arguments differ");
|
||||
static_assert(
|
||||
std::is_convertible<std::tuple<Passed...>, std::tuple<Expected...>>::value,
|
||||
"error: sample argument(s) not convertible to accumulator argument(s)");
|
||||
};
|
||||
|
||||
template <class A>
|
||||
struct storage_grower {
|
||||
const A& axes_;
|
||||
struct {
|
||||
axis::index_type idx, old_extent;
|
||||
std::size_t new_stride;
|
||||
} data_[buffer_size<A>::value];
|
||||
std::size_t new_size_;
|
||||
|
||||
storage_grower(const A& axes) noexcept : axes_(axes) {}
|
||||
|
||||
void from_shifts(const axis::index_type* shifts) noexcept {
|
||||
auto dit = data_;
|
||||
std::size_t s = 1;
|
||||
for_each_axis(axes_, [&](const auto& a) {
|
||||
const auto n = axis::traits::extent(a);
|
||||
*dit++ = {0, n - std::abs(*shifts++), s};
|
||||
s *= n;
|
||||
});
|
||||
new_size_ = s;
|
||||
}
|
||||
|
||||
// must be extents before any shifts were applied
|
||||
void from_extents(const axis::index_type* old_extents) noexcept {
|
||||
auto dit = data_;
|
||||
std::size_t s = 1;
|
||||
for_each_axis(axes_, [&](const auto& a) {
|
||||
const auto n = axis::traits::extent(a);
|
||||
*dit++ = {0, *old_extents++, s};
|
||||
s *= n;
|
||||
});
|
||||
new_size_ = s;
|
||||
}
|
||||
|
||||
template <class S>
|
||||
void apply(S& storage, const axis::index_type* shifts) {
|
||||
auto new_storage = make_default(storage);
|
||||
new_storage.reset(new_size_);
|
||||
const auto dlast = data_ + axes_rank(axes_) - 1;
|
||||
for (auto&& x : storage) {
|
||||
auto ns = new_storage.begin();
|
||||
auto sit = shifts;
|
||||
auto dit = data_;
|
||||
for_each_axis(axes_, [&](const auto& a) {
|
||||
using opt = axis::traits::get_options<std::decay_t<decltype(a)>>;
|
||||
if (opt::test(axis::option::underflow)) {
|
||||
if (dit->idx == 0) {
|
||||
// axis has underflow and we are in the underflow bin:
|
||||
// keep storage pointer unchanged
|
||||
++dit;
|
||||
++sit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (opt::test(axis::option::overflow)) {
|
||||
if (dit->idx == dit->old_extent - 1) {
|
||||
// axis has overflow and we are in the overflow bin:
|
||||
// move storage pointer to corresponding overflow bin position
|
||||
ns += (axis::traits::extent(a) - 1) * dit->new_stride;
|
||||
++dit;
|
||||
++sit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// we are in a normal bin:
|
||||
// move storage pointer to index position; apply positive shifts if any
|
||||
ns += (dit->idx + (*sit >= 0 ? *sit : 0)) * dit->new_stride;
|
||||
++dit;
|
||||
++sit;
|
||||
});
|
||||
// assign old value to new location
|
||||
*ns = x;
|
||||
// advance multi-dimensional index
|
||||
dit = data_;
|
||||
++dit->idx;
|
||||
while (dit != dlast && dit->idx == dit->old_extent) {
|
||||
dit->idx = 0;
|
||||
++(++dit)->idx;
|
||||
}
|
||||
}
|
||||
storage = std::move(new_storage);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... Us>
|
||||
auto fill_storage_element_impl(priority<2>, T&& t, const Us&... args) noexcept
|
||||
-> decltype(t(args...), void()) {
|
||||
t(args...);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto fill_storage_element_impl(priority<1>, T&& t, const weight_type<U>& w) noexcept
|
||||
-> decltype(t += w, void()) {
|
||||
t += w;
|
||||
}
|
||||
|
||||
// fallback for arithmetic types and accumulators that do not handle the weight
|
||||
template <class T, class U>
|
||||
auto fill_storage_element_impl(priority<0>, T&& t, const weight_type<U>& w) noexcept
|
||||
-> decltype(t += w.value, void()) {
|
||||
t += w.value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto fill_storage_element_impl(priority<1>, T&& t) noexcept -> decltype(++t, void()) {
|
||||
++t;
|
||||
}
|
||||
|
||||
template <class T, class... Us>
|
||||
void fill_storage_element(T&& t, const Us&... args) noexcept {
|
||||
fill_storage_element_impl(priority<2>{}, std::forward<T>(t), args...);
|
||||
}
|
||||
|
||||
// t may be a proxy and then it is an rvalue reference, not an lvalue reference
|
||||
template <class IW, class IS, class T, class U>
|
||||
void fill_storage_2(IW, IS, T&& t, U&& u) noexcept {
|
||||
mp11::tuple_apply(
|
||||
[&](const auto&... args) {
|
||||
fill_storage_element(std::forward<T>(t), std::get<IW::value>(u), args...);
|
||||
},
|
||||
std::get<IS::value>(u).value);
|
||||
}
|
||||
|
||||
// t may be a proxy and then it is an rvalue reference, not an lvalue reference
|
||||
template <class IS, class T, class U>
|
||||
void fill_storage_2(mp11::mp_int<-1>, IS, T&& t, const U& u) noexcept {
|
||||
mp11::tuple_apply(
|
||||
[&](const auto&... args) { fill_storage_element(std::forward<T>(t), args...); },
|
||||
std::get<IS::value>(u).value);
|
||||
}
|
||||
|
||||
// t may be a proxy and then it is an rvalue reference, not an lvalue reference
|
||||
template <class IW, class T, class U>
|
||||
void fill_storage_2(IW, mp11::mp_int<-1>, T&& t, const U& u) noexcept {
|
||||
fill_storage_element(std::forward<T>(t), std::get<IW::value>(u));
|
||||
}
|
||||
|
||||
// t may be a proxy and then it is an rvalue reference, not an lvalue reference
|
||||
template <class T, class U>
|
||||
void fill_storage_2(mp11::mp_int<-1>, mp11::mp_int<-1>, T&& t, const U&) noexcept {
|
||||
fill_storage_element(std::forward<T>(t));
|
||||
}
|
||||
|
||||
template <class IW, class IS, class Storage, class Index, class Args>
|
||||
auto fill_storage(IW, IS, Storage& s, const Index idx, const Args& a) noexcept {
|
||||
if (is_valid(idx)) {
|
||||
assert(idx < s.size());
|
||||
fill_storage_2(IW{}, IS{}, s[idx], a);
|
||||
return s.begin() + idx;
|
||||
}
|
||||
return s.end();
|
||||
}
|
||||
|
||||
template <int S, int N>
|
||||
struct linearize_args {
|
||||
template <class Index, class A, class Args>
|
||||
static void impl(mp11::mp_int<N>, Index&, const std::size_t, A&, const Args&) {}
|
||||
|
||||
template <int I, class Index, class A, class Args>
|
||||
static void impl(mp11::mp_int<I>, Index& o, const std::size_t s, A& ax,
|
||||
const Args& args) {
|
||||
const auto e = linearize(o, s, axis_get<I>(ax), std::get<(S + I)>(args));
|
||||
impl(mp11::mp_int<(I + 1)>{}, o, s * e, ax, args);
|
||||
}
|
||||
|
||||
template <class Index, class A, class Args>
|
||||
static void apply(Index& o, A& ax, const Args& args) {
|
||||
impl(mp11::mp_int<0>{}, o, 1, ax, args);
|
||||
}
|
||||
};
|
||||
|
||||
template <int S>
|
||||
struct linearize_args<S, 1> {
|
||||
template <class Index, class A, class Args>
|
||||
static void apply(Index& o, A& ax, const Args& args) {
|
||||
linearize(o, 1, axis_get<0>(ax), std::get<S>(args));
|
||||
}
|
||||
};
|
||||
|
||||
template <class A>
|
||||
constexpr unsigned min(const unsigned n) noexcept {
|
||||
constexpr unsigned a = buffer_size<A>::value;
|
||||
return a < n ? a : n;
|
||||
}
|
||||
|
||||
// not growing
|
||||
template <class ArgTraits, class Storage, class Axes, class Args>
|
||||
auto fill_2(ArgTraits, mp11::mp_false, const std::size_t offset, Storage& st,
|
||||
const Axes& axes, const Args& args) {
|
||||
mp11::mp_if<has_non_inclusive_axis<Axes>, optional_index, std::size_t> idx{offset};
|
||||
linearize_args<ArgTraits::start::value, min<Axes>(ArgTraits::nargs::value)>::apply(
|
||||
idx, axes, args);
|
||||
return fill_storage(typename ArgTraits::wpos{}, typename ArgTraits::spos{}, st, idx,
|
||||
args);
|
||||
}
|
||||
|
||||
// at least one axis is growing
|
||||
template <class ArgTraits, class Storage, class Axes, class Args>
|
||||
auto fill_2(ArgTraits, mp11::mp_true, const std::size_t, Storage& st, Axes& axes,
|
||||
const Args& args) {
|
||||
std::array<axis::index_type, ArgTraits::nargs::value> shifts;
|
||||
// offset must be zero for linearize_growth
|
||||
mp11::mp_if<has_non_inclusive_axis<Axes>, optional_index, std::size_t> idx{0};
|
||||
std::size_t stride = 1;
|
||||
bool update_needed = false;
|
||||
mp11::mp_for_each<mp11::mp_iota_c<min<Axes>(ArgTraits::nargs::value)>>([&](auto i) {
|
||||
auto& ax = axis_get<i>(axes);
|
||||
const auto extent = linearize_growth(idx, shifts[i], stride, ax,
|
||||
std::get<(ArgTraits::start::value + i)>(args));
|
||||
update_needed |= shifts[i] != 0;
|
||||
stride *= extent;
|
||||
});
|
||||
if (update_needed) {
|
||||
storage_grower<Axes> g(axes);
|
||||
g.from_shifts(shifts.data());
|
||||
g.apply(st, shifts.data());
|
||||
}
|
||||
return fill_storage(typename ArgTraits::wpos{}, typename ArgTraits::spos{}, st, idx,
|
||||
args);
|
||||
}
|
||||
|
||||
// pack original args tuple into another tuple (which is unpacked later)
|
||||
template <int Start, int Size, class IW, class IS, class Args>
|
||||
decltype(auto) pack_args(IW, IS, const Args& args) noexcept {
|
||||
return std::make_tuple(tuple_slice<Start, Size>(args), std::get<IW::value>(args),
|
||||
std::get<IS::value>(args));
|
||||
}
|
||||
|
||||
template <int Start, int Size, class IW, class Args>
|
||||
decltype(auto) pack_args(IW, mp11::mp_int<-1>, const Args& args) noexcept {
|
||||
return std::make_tuple(tuple_slice<Start, Size>(args), std::get<IW::value>(args));
|
||||
}
|
||||
|
||||
template <int Start, int Size, class IS, class Args>
|
||||
decltype(auto) pack_args(mp11::mp_int<-1>, IS, const Args& args) noexcept {
|
||||
return std::make_tuple(tuple_slice<Start, Size>(args), std::get<IS::value>(args));
|
||||
}
|
||||
|
||||
template <int Start, int Size, class Args>
|
||||
decltype(auto) pack_args(mp11::mp_int<-1>, mp11::mp_int<-1>, const Args& args) noexcept {
|
||||
return std::make_tuple(args);
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 0)
|
||||
#pragma warning(disable : 4702) // fixing warning would reduce code readability a lot
|
||||
#endif
|
||||
|
||||
template <class ArgTraits, class S, class A, class Args>
|
||||
auto fill(std::true_type, ArgTraits, const std::size_t offset, S& storage, A& axes,
|
||||
const Args& args) -> typename S::iterator {
|
||||
using growing = has_growing_axis<A>;
|
||||
|
||||
// Sometimes we need to pack the tuple into another tuple:
|
||||
// - histogram contains one axis which accepts tuple
|
||||
// - user passes tuple to fill(...)
|
||||
// Tuple is normally unpacked and arguments are processed, this causes pos::nargs > 1.
|
||||
// Now we pack tuple into another tuple so that original tuple is send to axis.
|
||||
// Notes:
|
||||
// - has nice side-effect of making histogram::operator(1, 2) work as well
|
||||
// - cannot detect call signature of axis at compile-time in all configurations
|
||||
// (axis::variant provides generic call interface and hides concrete
|
||||
// interface), so we throw at runtime if incompatible argument is passed (e.g.
|
||||
// 3d tuple)
|
||||
|
||||
if (axes_rank(axes) == ArgTraits::nargs::value)
|
||||
return fill_2(ArgTraits{}, growing{}, offset, storage, axes, args);
|
||||
else if (axes_rank(axes) == 1 &&
|
||||
axis::traits::rank(axis_get<0>(axes)) == ArgTraits::nargs::value)
|
||||
return fill_2(
|
||||
argument_traits_holder<
|
||||
1, 0, (ArgTraits::wpos::value >= 0 ? 1 : -1),
|
||||
(ArgTraits::spos::value >= 0 ? (ArgTraits::wpos::value >= 0 ? 2 : 1) : -1),
|
||||
typename ArgTraits::sargs>{},
|
||||
growing{}, offset, storage, axes,
|
||||
pack_args<ArgTraits::start::value, ArgTraits::nargs::value>(
|
||||
typename ArgTraits::wpos{}, typename ArgTraits::spos{}, args));
|
||||
return BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("number of arguments != histogram rank")),
|
||||
storage.end();
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 0)
|
||||
#pragma warning(default : 4702)
|
||||
#endif
|
||||
|
||||
// empty implementation for bad arguments to stop compiler from showing internals
|
||||
template <class ArgTraits, class S, class A, class Args>
|
||||
auto fill(std::false_type, ArgTraits, const std::size_t, S& storage, A&, const Args&) ->
|
||||
typename S::iterator {
|
||||
return storage.end();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
339
install/boost_1_75_0/include/boost/histogram/detail/fill_n.hpp
Normal file
339
install/boost_1_75_0/include/boost/histogram/detail/fill_n.hpp
Normal file
@@ -0,0 +1,339 @@
|
||||
// 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_FILL_N_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_FILL_N_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/histogram/axis/option.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/detect.hpp>
|
||||
#include <boost/histogram/detail/fill.hpp>
|
||||
#include <boost/histogram/detail/linearize.hpp>
|
||||
#include <boost/histogram/detail/nonmember_container_access.hpp>
|
||||
#include <boost/histogram/detail/optional_index.hpp>
|
||||
#include <boost/histogram/detail/span.hpp>
|
||||
#include <boost/histogram/detail/static_if.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/bind.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
namespace dtl = boost::histogram::detail;
|
||||
|
||||
template <class Axes, class T>
|
||||
using is_convertible_to_any_value_type =
|
||||
mp11::mp_any_of_q<value_types<Axes>, mp11::mp_bind_front<std::is_convertible, T>>;
|
||||
|
||||
template <class T>
|
||||
auto to_ptr_size(const T& x) {
|
||||
return static_if<std::is_scalar<T>>(
|
||||
[](const auto& x) { return std::make_pair(&x, static_cast<std::size_t>(0)); },
|
||||
[](const auto& x) { return std::make_pair(dtl::data(x), dtl::size(x)); }, x);
|
||||
}
|
||||
|
||||
template <class F, class V>
|
||||
decltype(auto) maybe_visit(F&& f, V&& v) {
|
||||
return static_if<is_variant<std::decay_t<V>>>(
|
||||
[](auto&& f, auto&& v) {
|
||||
return variant2::visit(std::forward<F>(f), std::forward<V>(v));
|
||||
},
|
||||
[](auto&& f, auto&& v) { return std::forward<F>(f)(std::forward<V>(v)); },
|
||||
std::forward<F>(f), std::forward<V>(v));
|
||||
}
|
||||
|
||||
template <class Index, class Axis, class IsGrowing>
|
||||
struct index_visitor {
|
||||
using index_type = Index;
|
||||
using pointer = index_type*;
|
||||
using value_type = axis::traits::value_type<Axis>;
|
||||
using Opt = axis::traits::get_options<Axis>;
|
||||
|
||||
Axis& axis_;
|
||||
const std::size_t stride_, start_, size_; // start and size of value collection
|
||||
const pointer begin_;
|
||||
axis::index_type* shift_;
|
||||
|
||||
index_visitor(Axis& a, std::size_t& str, const std::size_t& sta, const std::size_t& si,
|
||||
const pointer it, axis::index_type* shift)
|
||||
: axis_(a), stride_(str), start_(sta), size_(si), begin_(it), shift_(shift) {}
|
||||
|
||||
template <class T>
|
||||
void call_2(std::true_type, pointer it, const T& x) const {
|
||||
// must use this code for all axes if one of them is growing
|
||||
axis::index_type shift;
|
||||
linearize_growth(*it, shift, stride_, axis_,
|
||||
try_cast<value_type, std::invalid_argument>(x));
|
||||
if (shift > 0) { // shift previous indices, because axis zero-point has changed
|
||||
while (it != begin_) *--it += static_cast<std::size_t>(shift) * stride_;
|
||||
*shift_ += shift;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void call_2(std::false_type, pointer it, const T& x) const {
|
||||
// no axis is growing
|
||||
linearize(*it, stride_, axis_, try_cast<value_type, std::invalid_argument>(x));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void call_1(std::false_type, const T& iterable) const {
|
||||
// T is iterable; fill N values
|
||||
const auto* tp = dtl::data(iterable) + start_;
|
||||
for (auto it = begin_; it != begin_ + size_; ++it) call_2(IsGrowing{}, it, *tp++);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void call_1(std::true_type, const T& value) const {
|
||||
// T is compatible value; fill single value N times
|
||||
index_type idx{*begin_};
|
||||
call_2(IsGrowing{}, &idx, value);
|
||||
if (is_valid(idx)) {
|
||||
const auto delta =
|
||||
static_cast<std::intptr_t>(idx) - static_cast<std::intptr_t>(*begin_);
|
||||
for (auto&& i : make_span(begin_, size_)) i += delta;
|
||||
} else
|
||||
std::fill(begin_, begin_ + size_, invalid_index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void operator()(const T& iterable_or_value) const {
|
||||
call_1(mp11::mp_bool<(std::is_convertible<T, value_type>::value ||
|
||||
!is_iterable<T>::value)>{},
|
||||
iterable_or_value);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Index, class S, class Axes, class T>
|
||||
void fill_n_indices(Index* indices, const std::size_t start, const std::size_t size,
|
||||
const std::size_t offset, S& storage, Axes& axes, const T* viter) {
|
||||
axis::index_type extents[buffer_size<Axes>::value];
|
||||
axis::index_type shifts[buffer_size<Axes>::value];
|
||||
for_each_axis(axes, [eit = extents, sit = shifts](const auto& a) mutable {
|
||||
*sit++ = 0;
|
||||
*eit++ = axis::traits::extent(a);
|
||||
}); // LCOV_EXCL_LINE: gcc-8 is missing this line for no reason
|
||||
|
||||
// offset must be zero for growing axes
|
||||
using IsGrowing = has_growing_axis<Axes>;
|
||||
std::fill(indices, indices + size, IsGrowing::value ? 0 : offset);
|
||||
for_each_axis(axes, [&, stride = static_cast<std::size_t>(1),
|
||||
pshift = shifts](auto& axis) mutable {
|
||||
using Axis = std::decay_t<decltype(axis)>;
|
||||
maybe_visit(
|
||||
index_visitor<Index, Axis, IsGrowing>{axis, stride, start, size, indices, pshift},
|
||||
*viter++);
|
||||
stride *= static_cast<std::size_t>(axis::traits::extent(axis));
|
||||
++pshift;
|
||||
});
|
||||
|
||||
bool update_needed = false;
|
||||
for_each_axis(axes, [&update_needed, eit = extents](const auto& a) mutable {
|
||||
update_needed |= *eit++ != axis::traits::extent(a);
|
||||
});
|
||||
if (update_needed) {
|
||||
storage_grower<Axes> g(axes);
|
||||
g.from_extents(extents);
|
||||
g.apply(storage, shifts);
|
||||
}
|
||||
}
|
||||
|
||||
template <class S, class Index, class... Ts>
|
||||
void fill_n_storage(S& s, const Index idx, Ts&&... p) noexcept {
|
||||
if (is_valid(idx)) {
|
||||
assert(idx < s.size());
|
||||
fill_storage_element(s[idx], *p.first...);
|
||||
}
|
||||
// operator folding emulation
|
||||
(void)std::initializer_list<int>{(p.second ? (++p.first, 0) : 0)...};
|
||||
}
|
||||
|
||||
template <class S, class Index, class T, class... Ts>
|
||||
void fill_n_storage(S& s, const Index idx, weight_type<T>&& w, Ts&&... ps) noexcept {
|
||||
if (is_valid(idx)) {
|
||||
assert(idx < s.size());
|
||||
fill_storage_element(s[idx], weight(*w.value.first), *ps.first...);
|
||||
}
|
||||
if (w.value.second) ++w.value.first;
|
||||
// operator folding emulation
|
||||
(void)std::initializer_list<int>{(ps.second ? (++ps.first, 0) : 0)...};
|
||||
}
|
||||
|
||||
// general Nd treatment
|
||||
template <class Index, class S, class A, class T, class... Ts>
|
||||
void fill_n_nd(const std::size_t offset, S& storage, A& axes, const std::size_t vsize,
|
||||
const T* values, Ts&&... ts) {
|
||||
constexpr std::size_t buffer_size = 1ul << 14;
|
||||
Index indices[buffer_size];
|
||||
|
||||
/*
|
||||
Parallelization options.
|
||||
|
||||
A) Run the whole fill2 method in parallel, each thread fills its own buffer of
|
||||
indices, synchronization (atomics) are needed to synchronize the incrementing of
|
||||
the storage cells. This leads to a lot of congestion for small histograms.
|
||||
|
||||
B) Run only fill_n_indices in parallel, subsections of the indices buffer
|
||||
can be filled by different threads. The final loop that fills the storage runs
|
||||
in the main thread, this requires no synchronization for the storage, cells do
|
||||
not need to support atomic operations.
|
||||
|
||||
C) Like B), then sort the indices in the main thread and fill the
|
||||
storage in parallel, where each thread uses a disjunct set of indices. This
|
||||
should create less congestion and requires no synchronization for the storage.
|
||||
|
||||
Note on C): Let's say we have an axis with 5 bins (with *flow to simplify).
|
||||
Then after filling 10 values, converting to indices and sorting, the index
|
||||
buffer may look like this: 0 0 0 1 2 2 2 4 4 5. Let's use two threads to fill
|
||||
the storage. Still in the main thread, we compute an iterator to the middle of
|
||||
the index buffer and move it to the right until the pointee changes. Now we have
|
||||
two ranges which contain disjunct sets of indices. We pass these ranges to the
|
||||
threads which then fill the storage. Since the threads by construction do not
|
||||
compete to increment the same cell, no further synchronization is required.
|
||||
|
||||
In all cases, growing axes cannot be parallelized.
|
||||
*/
|
||||
|
||||
for (std::size_t start = 0; start < vsize; start += buffer_size) {
|
||||
const std::size_t n = std::min(buffer_size, vsize - start);
|
||||
// fill buffer of indices...
|
||||
fill_n_indices(indices, start, n, offset, storage, axes, values);
|
||||
// ...and fill corresponding storage cells
|
||||
for (auto&& idx : make_span(indices, n))
|
||||
fill_n_storage(storage, idx, std::forward<Ts>(ts)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class S, class... As, class T, class... Us>
|
||||
void fill_n_1(const std::size_t offset, S& storage, std::tuple<As...>& axes,
|
||||
const std::size_t vsize, const T* values, Us&&... us) {
|
||||
using index_type =
|
||||
mp11::mp_if<has_non_inclusive_axis<std::tuple<As...>>, optional_index, std::size_t>;
|
||||
fill_n_nd<index_type>(offset, storage, axes, vsize, values, std::forward<Us>(us)...);
|
||||
}
|
||||
|
||||
template <class S, class A, class T, class... Us>
|
||||
void fill_n_1(const std::size_t offset, S& storage, A& axes, const std::size_t vsize,
|
||||
const T* values, Us&&... us) {
|
||||
bool all_inclusive = true;
|
||||
for_each_axis(axes,
|
||||
[&](const auto& ax) { all_inclusive &= axis::traits::inclusive(ax); });
|
||||
if (axes_rank(axes) == 1) {
|
||||
axis::visit(
|
||||
[&](auto& ax) {
|
||||
std::tuple<decltype(ax)> axes{ax};
|
||||
fill_n_1(offset, storage, axes, vsize, values, std::forward<Us>(us)...);
|
||||
},
|
||||
axes[0]);
|
||||
} else {
|
||||
if (all_inclusive)
|
||||
fill_n_nd<std::size_t>(offset, storage, axes, vsize, values,
|
||||
std::forward<Us>(us)...);
|
||||
else
|
||||
fill_n_nd<optional_index>(offset, storage, axes, vsize, values,
|
||||
std::forward<Us>(us)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class A, class T, std::size_t N>
|
||||
std::size_t get_total_size(const A& axes, const dtl::span<const T, N>& values) {
|
||||
// supported cases (T = value type; CT = containter of T; V<T, CT, ...> = variant):
|
||||
// - span<CT, N>: for any histogram, N == rank
|
||||
// - span<V<T, CT>, N>: for any histogram, N == rank
|
||||
assert(axes_rank(axes) == values.size());
|
||||
constexpr auto unset = static_cast<std::size_t>(-1);
|
||||
std::size_t size = unset;
|
||||
for_each_axis(axes, [&size, vit = values.begin()](const auto& ax) mutable {
|
||||
using AV = axis::traits::value_type<std::decay_t<decltype(ax)>>;
|
||||
maybe_visit(
|
||||
[&size](const auto& v) {
|
||||
// v is either convertible to value or a sequence of values
|
||||
using V = std::remove_const_t<std::remove_reference_t<decltype(v)>>;
|
||||
static_if_c<(std::is_convertible<decltype(v), AV>::value ||
|
||||
!is_iterable<V>::value)>(
|
||||
[](const auto&) {},
|
||||
[&size](const auto& v) {
|
||||
const auto n = dtl::size(v);
|
||||
// must repeat this here for msvc :(
|
||||
constexpr auto unset = static_cast<std::size_t>(-1);
|
||||
if (size == unset)
|
||||
size = dtl::size(v);
|
||||
else if (size != n)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("spans must have compatible lengths"));
|
||||
},
|
||||
v);
|
||||
},
|
||||
*vit++);
|
||||
});
|
||||
// if all arguments are not iterables, return size of 1
|
||||
return size == unset ? 1 : size;
|
||||
}
|
||||
|
||||
inline void fill_n_check_extra_args(std::size_t) noexcept {}
|
||||
|
||||
template <class T, class... Ts>
|
||||
void fill_n_check_extra_args(std::size_t size, T&& x, Ts&&... ts) {
|
||||
// sequences must have same lengths, but sequences of length 0 are broadcast
|
||||
if (x.second != 0 && x.second != size)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("spans must have compatible lengths"));
|
||||
fill_n_check_extra_args(size, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
template <class T, class... Ts>
|
||||
void fill_n_check_extra_args(std::size_t size, weight_type<T>&& w, Ts&&... ts) {
|
||||
fill_n_check_extra_args(size, w.value, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
template <class S, class A, class T, std::size_t N, class... Us>
|
||||
void fill_n(std::true_type, const std::size_t offset, S& storage, A& axes,
|
||||
const dtl::span<const T, N> values, Us&&... us) {
|
||||
// supported cases (T = value type; CT = containter of T; V<T, CT, ...> = variant):
|
||||
// - span<T, N>: only valid for 1D histogram, N > 1 allowed
|
||||
// - span<CT, N>: for any histogram, N == rank
|
||||
// - span<V<T, CT>, N>: for any histogram, N == rank
|
||||
static_if<is_convertible_to_any_value_type<A, T>>(
|
||||
[&](const auto& values, auto&&... us) {
|
||||
// T matches one of the axis value types, must be 1D special case
|
||||
if (axes_rank(axes) != 1)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("number of arguments must match histogram rank"));
|
||||
fill_n_check_extra_args(values.size(), std::forward<Us>(us)...);
|
||||
fill_n_1(offset, storage, axes, values.size(), &values, std::forward<Us>(us)...);
|
||||
},
|
||||
[&](const auto& values, auto&&... us) {
|
||||
// generic ND case
|
||||
if (axes_rank(axes) != values.size())
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("number of arguments must match histogram rank"));
|
||||
const auto vsize = get_total_size(axes, values);
|
||||
fill_n_check_extra_args(vsize, std::forward<Us>(us)...);
|
||||
fill_n_1(offset, storage, axes, vsize, values.data(), std::forward<Us>(us)...);
|
||||
},
|
||||
values, std::forward<Us>(us)...);
|
||||
}
|
||||
|
||||
// empty implementation for bad arguments to stop compiler from showing internals
|
||||
template <class... Ts>
|
||||
void fill_n(std::false_type, Ts...) {}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_HISTOGRAM_DETAIL_FILL_N_HPP
|
||||
@@ -0,0 +1,113 @@
|
||||
// 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_INDEX_TRANSLATOR_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_INDEX_TRANSLATOR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/axis/variant.hpp>
|
||||
#include <boost/histogram/detail/relaxed_equal.hpp>
|
||||
#include <boost/histogram/detail/relaxed_tuple_size.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/histogram/multi_index.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integer_sequence.hpp>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class A>
|
||||
struct index_translator {
|
||||
using index_type = axis::index_type;
|
||||
using multi_index_type = multi_index<relaxed_tuple_size_t<A>::value>;
|
||||
using cref = const A&;
|
||||
|
||||
cref dst, src;
|
||||
bool pass_through[buffer_size<A>::value];
|
||||
|
||||
index_translator(cref d, cref s) : dst{d}, src{s} { init(dst, src); }
|
||||
|
||||
template <class T>
|
||||
void init(const T& a, const T& b) {
|
||||
std::transform(a.begin(), a.end(), b.begin(), pass_through,
|
||||
[](const auto& a, const auto& b) {
|
||||
return axis::visit(
|
||||
[&](const auto& a) {
|
||||
using U = std::decay_t<decltype(a)>;
|
||||
return relaxed_equal{}(a, axis::get<U>(b));
|
||||
},
|
||||
a);
|
||||
});
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
void init(const std::tuple<Ts...>& a, const std::tuple<Ts...>& b) {
|
||||
using Seq = mp11::mp_iota_c<sizeof...(Ts)>;
|
||||
mp11::mp_for_each<Seq>([&](auto I) {
|
||||
pass_through[I] = relaxed_equal{}(std::get<I>(a), std::get<I>(b));
|
||||
});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static index_type translate(const T& dst, const T& src, index_type i) noexcept {
|
||||
assert(axis::traits::is_continuous<T>::value == false); // LCOV_EXCL_LINE: unreachable
|
||||
return dst.index(src.value(i));
|
||||
}
|
||||
|
||||
template <class... Ts, class It>
|
||||
void impl(const std::tuple<Ts...>& a, const std::tuple<Ts...>& b, It i,
|
||||
index_type* j) const noexcept {
|
||||
using Seq = mp11::mp_iota_c<sizeof...(Ts)>;
|
||||
mp11::mp_for_each<Seq>([&](auto I) {
|
||||
if (pass_through[I])
|
||||
*(j + I) = *(i + I);
|
||||
else
|
||||
*(j + I) = this->translate(std::get<I>(a), std::get<I>(b), *(i + I));
|
||||
});
|
||||
}
|
||||
|
||||
template <class T, class It>
|
||||
void impl(const T& a, const T& b, It i, index_type* j) const noexcept {
|
||||
const bool* p = pass_through;
|
||||
for (unsigned k = 0; k < a.size(); ++k, ++i, ++j, ++p) {
|
||||
if (*p)
|
||||
*j = *i;
|
||||
else {
|
||||
const auto& bk = b[k];
|
||||
axis::visit(
|
||||
[&](const auto& ak) {
|
||||
using U = std::decay_t<decltype(ak)>;
|
||||
*j = this->translate(ak, axis::get<U>(bk), *i);
|
||||
},
|
||||
a[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Indices>
|
||||
auto operator()(const Indices& seq) const noexcept {
|
||||
auto mi = multi_index_type::create(seq.size());
|
||||
impl(dst, src, seq.begin(), mi.begin());
|
||||
return mi;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Axes>
|
||||
auto make_index_translator(const Axes& dst, const Axes& src) noexcept {
|
||||
return index_translator<Axes>{dst, src};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
// 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)
|
||||
//
|
||||
// Uses code segments from boost/iterator/iterator_adaptor.hpp
|
||||
// and boost/iterator/iterator_fascade.hpp
|
||||
|
||||
#ifndef BOOST_HISTOGRAM_DETAIL_ITERATOR_ADAPTOR_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_ITERATOR_ADAPTOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
// operator->() needs special support for input iterators to strictly meet the
|
||||
// standard's requirements. If *i is not a reference type, we must still
|
||||
// produce an lvalue to which a pointer can be formed. We do that by
|
||||
// returning a proxy object containing an instance of the reference object.
|
||||
template <class Reference>
|
||||
struct operator_arrow_dispatch_t // proxy references
|
||||
{
|
||||
struct proxy {
|
||||
explicit proxy(Reference const& x) noexcept : m_ref(x) {}
|
||||
Reference* operator->() noexcept { return std::addressof(m_ref); }
|
||||
Reference m_ref;
|
||||
};
|
||||
|
||||
using result_type = proxy;
|
||||
static result_type apply(Reference const& x) noexcept { return proxy(x); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct operator_arrow_dispatch_t<T&> // "real" references
|
||||
{
|
||||
using result_type = T*;
|
||||
static result_type apply(T& x) noexcept { return std::addressof(x); }
|
||||
};
|
||||
|
||||
// only for random access Base
|
||||
template <class Derived, class Base, class Reference = std::remove_pointer_t<Base>&,
|
||||
class Value = std::decay_t<Reference>>
|
||||
class iterator_adaptor {
|
||||
using operator_arrow_dispatch = operator_arrow_dispatch_t<Reference>;
|
||||
|
||||
public:
|
||||
using base_type = Base;
|
||||
|
||||
using reference = Reference;
|
||||
using value_type = std::remove_const_t<Value>;
|
||||
using pointer = typename operator_arrow_dispatch::result_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
iterator_adaptor() = default;
|
||||
|
||||
explicit iterator_adaptor(base_type const& iter) : iter_(iter) {}
|
||||
|
||||
pointer operator->() const noexcept {
|
||||
return operator_arrow_dispatch::apply(this->derived().operator*());
|
||||
}
|
||||
reference operator[](difference_type n) const { return *(this->derived() + n); }
|
||||
|
||||
Derived& operator++() {
|
||||
++iter_;
|
||||
return this->derived();
|
||||
}
|
||||
|
||||
Derived& operator--() {
|
||||
--iter_;
|
||||
return this->derived();
|
||||
}
|
||||
|
||||
Derived operator++(int) {
|
||||
Derived tmp(this->derived());
|
||||
++iter_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Derived operator--(int) {
|
||||
Derived tmp(this->derived());
|
||||
--iter_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Derived& operator+=(difference_type n) {
|
||||
iter_ += n;
|
||||
return this->derived();
|
||||
}
|
||||
|
||||
Derived& operator-=(difference_type n) {
|
||||
iter_ -= n;
|
||||
return this->derived();
|
||||
}
|
||||
|
||||
Derived operator+(difference_type n) const {
|
||||
Derived tmp(this->derived());
|
||||
tmp += n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Derived operator-(difference_type n) const { return operator+(-n); }
|
||||
|
||||
template <class... Ts>
|
||||
difference_type operator-(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return iter_ - x.iter_;
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
bool operator==(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return iter_ == x.iter_;
|
||||
}
|
||||
template <class... Ts>
|
||||
bool operator!=(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return !this->derived().operator==(x); // equal operator may be overridden in derived
|
||||
}
|
||||
template <class... Ts>
|
||||
bool operator<(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return iter_ < x.iter_;
|
||||
}
|
||||
template <class... Ts>
|
||||
bool operator>(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return iter_ > x.iter_;
|
||||
}
|
||||
template <class... Ts>
|
||||
bool operator<=(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return iter_ <= x.iter_;
|
||||
}
|
||||
template <class... Ts>
|
||||
bool operator>=(const iterator_adaptor<Ts...>& x) const noexcept {
|
||||
return iter_ >= x.iter_;
|
||||
}
|
||||
|
||||
friend Derived operator+(difference_type n, const Derived& x) { return x + n; }
|
||||
|
||||
Base const& base() const noexcept { return iter_; }
|
||||
|
||||
protected:
|
||||
// for convenience in derived classes
|
||||
using iterator_adaptor_ = iterator_adaptor;
|
||||
|
||||
private:
|
||||
Derived& derived() noexcept { return *static_cast<Derived*>(this); }
|
||||
const Derived& derived() const noexcept { return *static_cast<Derived const*>(this); }
|
||||
|
||||
Base iter_;
|
||||
|
||||
template <class, class, class, class>
|
||||
friend class iterator_adaptor;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,255 @@
|
||||
// Copyright 2018-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_LARGE_INT_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_LARGE_INT_HPP
|
||||
|
||||
#include <boost/histogram/detail/operators.hpp>
|
||||
#include <boost/histogram/detail/safe_comparison.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/function.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
using is_unsigned_integral = mp11::mp_and<std::is_integral<T>, std::is_unsigned<T>>;
|
||||
|
||||
template <class T>
|
||||
bool safe_increment(T& t) {
|
||||
if (t < (std::numeric_limits<T>::max)()) {
|
||||
++t;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool safe_radd(T& t, const U& u) {
|
||||
static_assert(is_unsigned_integral<T>::value, "T must be unsigned integral type");
|
||||
static_assert(is_unsigned_integral<U>::value, "T must be unsigned integral type");
|
||||
if (static_cast<T>((std::numeric_limits<T>::max)() - t) >= u) {
|
||||
t += static_cast<T>(u); // static_cast to suppress conversion warning
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// An integer type which can grow arbitrarily large (until memory is exhausted).
|
||||
// Use boost.multiprecision.cpp_int in your own code, it is much more sophisticated.
|
||||
// We use it only to reduce coupling between boost libs.
|
||||
template <class Allocator>
|
||||
struct large_int : totally_ordered<large_int<Allocator>, large_int<Allocator>>,
|
||||
partially_ordered<large_int<Allocator>, void> {
|
||||
explicit large_int(const Allocator& a = {}) : data(1, 0, a) {}
|
||||
explicit large_int(std::uint64_t v, const Allocator& a = {}) : data(1, v, a) {}
|
||||
|
||||
large_int(const large_int&) = default;
|
||||
large_int& operator=(const large_int&) = default;
|
||||
large_int(large_int&&) = default;
|
||||
large_int& operator=(large_int&&) = default;
|
||||
|
||||
large_int& operator=(std::uint64_t o) {
|
||||
data = decltype(data)(1, o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
large_int& operator++() {
|
||||
assert(data.size() > 0u);
|
||||
std::size_t i = 0;
|
||||
while (!safe_increment(data[i])) {
|
||||
data[i] = 0;
|
||||
++i;
|
||||
if (i == data.size()) {
|
||||
data.push_back(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
large_int& operator+=(const large_int& o) {
|
||||
if (this == &o) {
|
||||
auto tmp{o};
|
||||
return operator+=(tmp);
|
||||
}
|
||||
bool carry = false;
|
||||
std::size_t i = 0;
|
||||
for (std::uint64_t oi : o.data) {
|
||||
auto& di = maybe_extend(i);
|
||||
if (carry) {
|
||||
if (safe_increment(oi))
|
||||
carry = false;
|
||||
else {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!safe_radd(di, oi)) {
|
||||
add_remainder(di, oi);
|
||||
carry = true;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
while (carry) {
|
||||
auto& di = maybe_extend(i);
|
||||
if (safe_increment(di)) break;
|
||||
di = 0;
|
||||
++i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
large_int& operator+=(std::uint64_t o) {
|
||||
assert(data.size() > 0u);
|
||||
if (safe_radd(data[0], o)) return *this;
|
||||
add_remainder(data[0], o);
|
||||
// carry the one, data may grow several times
|
||||
std::size_t i = 1;
|
||||
while (true) {
|
||||
auto& di = maybe_extend(i);
|
||||
if (safe_increment(di)) break;
|
||||
di = 0;
|
||||
++i;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator double() const noexcept {
|
||||
assert(data.size() > 0u);
|
||||
double result = static_cast<double>(data[0]);
|
||||
std::size_t i = 0;
|
||||
while (++i < data.size())
|
||||
result += static_cast<double>(data[i]) * std::pow(2.0, i * 64);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator<(const large_int& o) const noexcept {
|
||||
assert(data.size() > 0u);
|
||||
assert(o.data.size() > 0u);
|
||||
// no leading zeros allowed
|
||||
assert(data.size() == 1 || data.back() > 0u);
|
||||
assert(o.data.size() == 1 || o.data.back() > 0u);
|
||||
if (data.size() < o.data.size()) return true;
|
||||
if (data.size() > o.data.size()) return false;
|
||||
auto s = data.size();
|
||||
while (s > 0u) {
|
||||
--s;
|
||||
if (data[s] < o.data[s]) return true;
|
||||
if (data[s] > o.data[s]) return false;
|
||||
}
|
||||
return false; // args are equal
|
||||
}
|
||||
|
||||
bool operator==(const large_int& o) const noexcept {
|
||||
assert(data.size() > 0u);
|
||||
assert(o.data.size() > 0u);
|
||||
// no leading zeros allowed
|
||||
assert(data.size() == 1 || data.back() > 0u);
|
||||
assert(o.data.size() == 1 || o.data.back() > 0u);
|
||||
if (data.size() != o.data.size()) return false;
|
||||
return std::equal(data.begin(), data.end(), o.data.begin());
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<std::is_integral<U>::value, bool> operator<(
|
||||
const U& o) const noexcept {
|
||||
assert(data.size() > 0u);
|
||||
return data.size() == 1 && safe_less()(data[0], o);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<std::is_integral<U>::value, bool> operator>(
|
||||
const U& o) const noexcept {
|
||||
assert(data.size() > 0u);
|
||||
assert(data.size() == 1 || data.back() > 0u); // no leading zeros allowed
|
||||
return data.size() > 1 || safe_less()(o, data[0]);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<std::is_integral<U>::value, bool> operator==(
|
||||
const U& o) const noexcept {
|
||||
assert(data.size() > 0u);
|
||||
return data.size() == 1 && safe_equal()(data[0], o);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<std::is_floating_point<U>::value, bool> operator<(
|
||||
const U& o) const noexcept {
|
||||
return operator double() < o;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<std::is_floating_point<U>::value, bool> operator>(
|
||||
const U& o) const noexcept {
|
||||
return operator double() > o;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<std::is_floating_point<U>::value, bool> operator==(
|
||||
const U& o) const noexcept {
|
||||
return operator double() == o;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<
|
||||
(!std::is_arithmetic<U>::value && std::is_convertible<U, double>::value), bool>
|
||||
operator<(const U& o) const noexcept {
|
||||
return operator double() < o;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<
|
||||
(!std::is_arithmetic<U>::value && std::is_convertible<U, double>::value), bool>
|
||||
operator>(const U& o) const noexcept {
|
||||
return operator double() > o;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
std::enable_if_t<
|
||||
(!std::is_arithmetic<U>::value && std::is_convertible<U, double>::value), bool>
|
||||
operator==(const U& o) const noexcept {
|
||||
return operator double() == o;
|
||||
}
|
||||
|
||||
std::uint64_t& maybe_extend(std::size_t i) {
|
||||
while (i >= data.size()) data.push_back(0);
|
||||
return data[i];
|
||||
}
|
||||
|
||||
static void add_remainder(std::uint64_t& d, const std::uint64_t o) noexcept {
|
||||
assert(d > 0u);
|
||||
// in decimal system it would look like this:
|
||||
// 8 + 8 = 6 = 8 - (9 - 8) - 1
|
||||
// 9 + 1 = 0 = 9 - (9 - 1) - 1
|
||||
auto tmp = (std::numeric_limits<std::uint64_t>::max)();
|
||||
tmp -= o;
|
||||
--d -= tmp;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, unsigned /* version */) {
|
||||
ar& make_nvp("data", data);
|
||||
}
|
||||
|
||||
std::vector<std::uint64_t, Allocator> data;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2015-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_LIMITS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_LIMITS_HPP
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
constexpr T lowest() {
|
||||
return std::numeric_limits<T>::lowest();
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr double lowest() {
|
||||
return -std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr float lowest() {
|
||||
return -std::numeric_limits<float>::infinity();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr T highest() {
|
||||
return (std::numeric_limits<T>::max)();
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr double highest() {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr float highest() {
|
||||
return std::numeric_limits<float>::infinity();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
// 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_LINEARIZE_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_LINEARIZE_HPP
|
||||
|
||||
#include <boost/histogram/axis/option.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/axis/variant.hpp>
|
||||
#include <boost/histogram/detail/optional_index.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/histogram/multi_index.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
// initial offset to out must be set
|
||||
template <class Index, class Opts>
|
||||
std::size_t linearize(Opts, Index& out, const std::size_t stride,
|
||||
const axis::index_type size, const axis::index_type idx) {
|
||||
constexpr bool u = Opts::test(axis::option::underflow);
|
||||
constexpr bool o = Opts::test(axis::option::overflow);
|
||||
|
||||
// must be non-const to avoid if constexpr warning from msvc
|
||||
bool fast_track = std::is_same<Index, std::size_t>::value || (u && o);
|
||||
if (fast_track) {
|
||||
assert(idx >= (u ? -1 : 0));
|
||||
assert(idx < (o ? size + 1 : size));
|
||||
assert(idx >= 0 || static_cast<std::size_t>(-idx * stride) <= out);
|
||||
out += idx * stride;
|
||||
} else {
|
||||
assert(idx >= -1);
|
||||
assert(idx < size + 1);
|
||||
// must be non-const to avoid if constexpr warning from msvc
|
||||
bool is_valid = (u || idx >= 0) && (o || idx < size);
|
||||
if (is_valid)
|
||||
out += idx * stride;
|
||||
else
|
||||
out = invalid_index;
|
||||
}
|
||||
return size + u + o;
|
||||
}
|
||||
|
||||
template <class Index, class Axis, class Value>
|
||||
std::size_t linearize(Index& out, const std::size_t stride, const Axis& ax,
|
||||
const Value& v) {
|
||||
// mask options to reduce no. of template instantiations
|
||||
constexpr auto opts = axis::traits::get_options<Axis>{} &
|
||||
(axis::option::underflow | axis::option::overflow);
|
||||
return linearize(opts, out, stride, ax.size(), axis::traits::index(ax, v));
|
||||
}
|
||||
|
||||
// initial offset of out must be zero
|
||||
template <class Index, class Axis, class Value>
|
||||
std::size_t linearize_growth(Index& out, axis::index_type& shift,
|
||||
const std::size_t stride, Axis& a, const Value& v) {
|
||||
axis::index_type idx;
|
||||
std::tie(idx, shift) = axis::traits::update(a, v);
|
||||
constexpr bool u = axis::traits::get_options<Axis>::test(axis::option::underflow);
|
||||
if (u) ++idx;
|
||||
if (std::is_same<Index, std::size_t>::value) {
|
||||
assert(idx < axis::traits::extent(a));
|
||||
out += idx * stride;
|
||||
} else {
|
||||
if (0 <= idx && idx < axis::traits::extent(a))
|
||||
out += idx * stride;
|
||||
else
|
||||
out = invalid_index;
|
||||
}
|
||||
return axis::traits::extent(a);
|
||||
}
|
||||
|
||||
// initial offset of out must be zero
|
||||
template <class A>
|
||||
std::size_t linearize_index(optional_index& out, const std::size_t stride, const A& ax,
|
||||
const axis::index_type idx) noexcept {
|
||||
const auto opt = axis::traits::get_options<A>();
|
||||
const axis::index_type begin = opt & axis::option::underflow ? -1 : 0;
|
||||
const axis::index_type end = opt & axis::option::overflow ? ax.size() + 1 : ax.size();
|
||||
const axis::index_type extent = end - begin;
|
||||
// i may be arbitrarily out of range
|
||||
if (begin <= idx && idx < end)
|
||||
out += (idx - begin) * stride;
|
||||
else
|
||||
out = invalid_index;
|
||||
return extent;
|
||||
}
|
||||
|
||||
template <class A, std::size_t N>
|
||||
optional_index linearize_indices(const A& axes, const multi_index<N>& indices) noexcept {
|
||||
assert(axes_rank(axes) == detail::size(indices));
|
||||
|
||||
optional_index idx{0}; // offset not used by linearize_index
|
||||
auto stride = static_cast<std::size_t>(1);
|
||||
using std::begin;
|
||||
auto i = begin(indices);
|
||||
for_each_axis(axes,
|
||||
[&](const auto& a) { stride *= linearize_index(idx, stride, a, *i++); });
|
||||
return idx;
|
||||
}
|
||||
|
||||
template <class Index, class... Ts, class Value>
|
||||
std::size_t linearize(Index& o, const std::size_t s, const axis::variant<Ts...>& a,
|
||||
const Value& v) {
|
||||
return axis::visit([&o, &s, &v](const auto& a) { return linearize(o, s, a, v); }, a);
|
||||
}
|
||||
|
||||
template <class Index, class... Ts, class Value>
|
||||
std::size_t linearize_growth(Index& o, axis::index_type& sh, const std::size_t st,
|
||||
axis::variant<Ts...>& a, const Value& v) {
|
||||
return axis::visit([&](auto& a) { return linearize_growth(o, sh, st, a, v); }, a);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_HISTOGRAM_DETAIL_LINEARIZE_HPP
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2015-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_MAKE_DEFAULT_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_MAKE_DEFAULT_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
T make_default_impl(const T& t, decltype(t.get_allocator(), 0)) {
|
||||
return T(t.get_allocator());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T make_default_impl(const T&, float) {
|
||||
return T{};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T make_default(const T& t) {
|
||||
return make_default_impl(t, 0);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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_NOOP_MUTEX_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_NOOP_MUTEX_HPP
|
||||
|
||||
#include <boost/core/empty_value.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/mp11/utility.hpp> // mp_if
|
||||
#include <mutex>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
struct null_mutex {
|
||||
bool try_lock() noexcept { return true; }
|
||||
void lock() noexcept {}
|
||||
void unlock() noexcept {}
|
||||
};
|
||||
|
||||
template <class Axes, class Storage,
|
||||
class DetailMutex = mp11::mp_if_c<(Storage::has_threading_support &&
|
||||
detail::has_growing_axis<Axes>::value),
|
||||
std::mutex, detail::null_mutex>>
|
||||
struct mutex_base : empty_value<DetailMutex> {
|
||||
mutex_base() = default;
|
||||
// do not copy or move mutex
|
||||
mutex_base(const mutex_base&) : empty_value<DetailMutex>() {}
|
||||
// do not copy or move mutex
|
||||
mutex_base& operator=(const mutex_base&) { return *this; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
// 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_NONMEMBER_CONTAINER_ACCESS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_NONMEMBER_CONTAINER_ACCESS_HPP
|
||||
|
||||
#if __cpp_lib_nonmember_container_access >= 201411
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
using std::data;
|
||||
using std::size;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#else // std implementations are not available
|
||||
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class C>
|
||||
constexpr auto data(C& c) -> decltype(c.data()) {
|
||||
return c.data();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
constexpr auto data(const C& c) -> decltype(c.data()) {
|
||||
return c.data();
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T* data(T (&array)[N]) noexcept {
|
||||
return array;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
constexpr const E* data(std::initializer_list<E> il) noexcept {
|
||||
return il.begin();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
constexpr auto size(const C& c) -> decltype(c.size()) {
|
||||
return c.size();
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::size_t size(const T (&)[N]) noexcept {
|
||||
return N;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BOOST_HISTOGRAM_DETAIL_NONMEMBER_CONTAINER_ACCESS_HPP
|
||||
@@ -0,0 +1,141 @@
|
||||
// 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_OPERATORS_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP
|
||||
|
||||
#include <boost/histogram/detail/detect.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
using if_not_same = std::enable_if_t<(!std::is_same<T, U>::value), bool>;
|
||||
|
||||
// template <class T, class U>
|
||||
// using if_not_same_and_has_eq =
|
||||
// std::enable_if_t<(!std::is_same<T, U>::value && !has_method_eq<T, U>::value),
|
||||
// bool>;
|
||||
|
||||
// totally_ordered is for types with a <= b == !(a > b) [floats with NaN violate this]
|
||||
// Derived must implement <,== for symmetric form and <,>,== for non-symmetric.
|
||||
|
||||
// partially_ordered is for types with a <= b == a < b || a == b [for floats with NaN]
|
||||
// Derived must implement <,== for symmetric form and <,>,== for non-symmetric.
|
||||
|
||||
template <class T, class U>
|
||||
struct mirrored {
|
||||
friend bool operator<(const U& a, const T& b) noexcept { return b > a; }
|
||||
friend bool operator>(const U& a, const T& b) noexcept { return b < a; }
|
||||
friend bool operator==(const U& a, const T& b) noexcept { return b == a; }
|
||||
friend bool operator<=(const U& a, const T& b) noexcept { return b >= a; }
|
||||
friend bool operator>=(const U& a, const T& b) noexcept { return b <= a; }
|
||||
friend bool operator!=(const U& a, const T& b) noexcept { return b != a; }
|
||||
}; // namespace histogram
|
||||
|
||||
template <class T>
|
||||
struct mirrored<T, void> {
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator<(const U& a, const T& b) noexcept {
|
||||
return b > a;
|
||||
}
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator>(const U& a, const T& b) noexcept {
|
||||
return b < a;
|
||||
}
|
||||
template <class U>
|
||||
friend std::enable_if_t<(!has_method_eq<U, T>::value), bool> operator==(
|
||||
const U& a, const T& b) noexcept {
|
||||
return b.operator==(a);
|
||||
}
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator<=(const U& a, const T& b) noexcept {
|
||||
return b >= a;
|
||||
}
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator>=(const U& a, const T& b) noexcept {
|
||||
return b <= a;
|
||||
}
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator!=(const U& a, const T& b) noexcept {
|
||||
return b != a;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct mirrored<T, T> {
|
||||
friend bool operator>(const T& a, const T& b) noexcept { return b.operator<(a); }
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct equality {
|
||||
friend bool operator!=(const T& a, const U& b) noexcept { return !a.operator==(b); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct equality<T, void> {
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator!=(const T& a, const U& b) noexcept {
|
||||
return !(a == b);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct totally_ordered_impl : equality<T, U>, mirrored<T, U> {
|
||||
friend bool operator<=(const T& a, const U& b) noexcept { return !(a > b); }
|
||||
friend bool operator>=(const T& a, const U& b) noexcept { return !(a < b); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct totally_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> {
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept {
|
||||
return !(a > b);
|
||||
}
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept {
|
||||
return !(a < b);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... Ts>
|
||||
using totally_ordered = mp11::mp_rename<
|
||||
mp11::mp_product<totally_ordered_impl, mp11::mp_list<T>, mp11::mp_list<Ts...> >,
|
||||
mp11::mp_inherit>;
|
||||
|
||||
template <class T, class U>
|
||||
struct partially_ordered_impl : equality<T, U>, mirrored<T, U> {
|
||||
friend bool operator<=(const T& a, const U& b) noexcept { return a < b || a == b; }
|
||||
friend bool operator>=(const T& a, const U& b) noexcept { return a > b || a == b; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct partially_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> {
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept {
|
||||
return a < b || a == b;
|
||||
}
|
||||
template <class U>
|
||||
friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept {
|
||||
return a > b || a == b;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... Ts>
|
||||
using partially_ordered = mp11::mp_rename<
|
||||
mp11::mp_product<partially_ordered_impl, mp11::mp_list<T>, mp11::mp_list<Ts...> >,
|
||||
mp11::mp_inherit>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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_OPTIONAL_INDEX_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_OPTIONAL_INDEX_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
constexpr auto invalid_index = ~static_cast<std::size_t>(0);
|
||||
|
||||
// integer with a persistent invalid state, similar to NaN
|
||||
struct optional_index {
|
||||
std::size_t value;
|
||||
|
||||
optional_index& operator=(std::size_t x) noexcept {
|
||||
value = x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional_index& operator+=(std::intptr_t x) noexcept {
|
||||
assert(x >= 0 || static_cast<std::size_t>(-x) <= value);
|
||||
if (value != invalid_index) { value += x; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional_index& operator+=(const optional_index& x) noexcept {
|
||||
if (value != invalid_index) return operator+=(x.value);
|
||||
value = invalid_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator std::size_t() const noexcept { return value; }
|
||||
|
||||
friend bool operator<=(std::size_t x, optional_index idx) noexcept {
|
||||
return x <= idx.value;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr inline bool is_valid(const std::size_t) noexcept { return true; }
|
||||
|
||||
inline bool is_valid(const optional_index x) noexcept { return x.value != invalid_index; }
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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_PRIORITY_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_PRIORITY_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
// priority is used to priorise ambiguous overloads
|
||||
|
||||
template <std::size_t N>
|
||||
struct priority : priority<(N - 1)> {};
|
||||
|
||||
template <>
|
||||
struct priority<0> {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2020 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_REDUCE_COMMAND_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_REDUCE_COMMAND_HPP
|
||||
|
||||
#include <boost/histogram/detail/span.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
struct reduce_command {
|
||||
static constexpr unsigned unset = static_cast<unsigned>(-1);
|
||||
unsigned iaxis = unset;
|
||||
enum class range_t : char {
|
||||
none,
|
||||
indices,
|
||||
values,
|
||||
} range = range_t::none;
|
||||
union {
|
||||
axis::index_type index;
|
||||
double value;
|
||||
} begin{0}, end{0};
|
||||
unsigned merge = 0; // default value indicates unset option
|
||||
bool crop = false;
|
||||
// for internal use by the reduce algorithm
|
||||
bool is_ordered = true;
|
||||
bool use_underflow_bin = true;
|
||||
bool use_overflow_bin = true;
|
||||
};
|
||||
|
||||
// - puts commands in correct axis order
|
||||
// - sets iaxis for positional commands
|
||||
// - detects and fails on invalid settings
|
||||
// - fuses merge commands with non-merge commands
|
||||
inline void normalize_reduce_commands(span<reduce_command> out,
|
||||
span<const reduce_command> in) {
|
||||
unsigned iaxis = 0;
|
||||
for (const auto& o_in : in) {
|
||||
assert(o_in.merge > 0);
|
||||
if (o_in.iaxis != reduce_command::unset && o_in.iaxis >= out.size())
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("invalid axis index"));
|
||||
auto& o_out = out.begin()[o_in.iaxis == reduce_command::unset ? iaxis : o_in.iaxis];
|
||||
if (o_out.merge == 0) {
|
||||
o_out = o_in;
|
||||
} else {
|
||||
// Some command was already set for this axis, try to fuse commands.
|
||||
if (!((o_in.range == reduce_command::range_t::none) ^
|
||||
(o_out.range == reduce_command::range_t::none)) ||
|
||||
(o_out.merge > 1 && o_in.merge > 1))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument(
|
||||
"multiple conflicting reduce commands for axis " +
|
||||
std::to_string(o_in.iaxis == reduce_command::unset ? iaxis : o_in.iaxis)));
|
||||
if (o_in.range != reduce_command::range_t::none) {
|
||||
o_out.range = o_in.range;
|
||||
o_out.begin = o_in.begin;
|
||||
o_out.end = o_in.end;
|
||||
} else {
|
||||
o_out.merge = o_in.merge;
|
||||
}
|
||||
}
|
||||
++iaxis;
|
||||
}
|
||||
|
||||
iaxis = 0;
|
||||
for (auto& o : out) o.iaxis = iaxis++;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2015-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_RELAXED_EQUAL_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_RELAXED_EQUAL_HPP
|
||||
|
||||
#include <boost/histogram/detail/priority.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
struct relaxed_equal {
|
||||
template <class T, class U>
|
||||
constexpr auto impl(const T& t, const U& u, priority<1>) const noexcept
|
||||
-> decltype(t == u) const {
|
||||
return t == u;
|
||||
}
|
||||
|
||||
// consider T and U not equal, if there is no operator== defined for them
|
||||
template <class T, class U>
|
||||
constexpr bool impl(const T&, const U&, priority<0>) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
// consider two T equal if they are stateless
|
||||
template <class T>
|
||||
constexpr bool impl(const T&, const T&, priority<0>) const noexcept {
|
||||
return std::is_empty<T>::value;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool operator()(const T& t, const U& u) const noexcept {
|
||||
return impl(t, u, priority<1>{});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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_RELAXED_TUPLE_SIZE_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_RELAXED_TUPLE_SIZE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
using dynamic_size = std::integral_constant<std::size_t, static_cast<std::size_t>(-1)>;
|
||||
|
||||
// Returns static size of tuple or dynamic_size
|
||||
template <class T>
|
||||
constexpr dynamic_size relaxed_tuple_size(const T&) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
constexpr std::integral_constant<std::size_t, sizeof...(Ts)> relaxed_tuple_size(
|
||||
const std::tuple<Ts...>&) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using relaxed_tuple_size_t = decltype(relaxed_tuple_size(std::declval<T>()));
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
// 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_REPLACE_TYPE_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_REPLACE_TYPE_HPP
|
||||
|
||||
#include <boost/core/use_default.hpp>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class From, class To>
|
||||
using replace_type = std::conditional_t<std::is_same<T, From>::value, To, T>;
|
||||
|
||||
template <class T, class Default>
|
||||
using replace_default = replace_type<T, boost::use_default, Default>;
|
||||
|
||||
template <class T>
|
||||
using replace_cstring = replace_type<T, const char*, std::string>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
// 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_SAFE_COMPARISON_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_SAFE_COMPARISON_HPP
|
||||
|
||||
#include <boost/mp11/utility.hpp>
|
||||
#include <boost/type.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
auto make_unsigned(const T& t) noexcept {
|
||||
static_assert(std::is_integral<T>::value, "");
|
||||
return static_cast<std::make_unsigned_t<T>>(t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using number_category =
|
||||
mp11::mp_if<std::is_integral<T>,
|
||||
mp11::mp_if<std::is_signed<T>, type<int>, type<unsigned>>, type<void>>;
|
||||
|
||||
// version of std::equal_to<> which handles signed and unsigned integers correctly
|
||||
struct safe_equal {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& t, const U& u) const noexcept {
|
||||
return impl(number_category<T>{}, number_category<U>{}, t, u);
|
||||
}
|
||||
|
||||
template <class C1, class C2, class T, class U>
|
||||
bool impl(C1, C2, const T& t, const U& u) const noexcept {
|
||||
return t == u;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool impl(type<int>, type<unsigned>, const T& t, const U& u) const noexcept {
|
||||
return t >= 0 && make_unsigned(t) == u;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool impl(type<unsigned>, type<int>, const T& t, const U& u) const noexcept {
|
||||
return impl(type<int>{}, type<unsigned>{}, u, t);
|
||||
}
|
||||
};
|
||||
|
||||
// version of std::less<> which handles signed and unsigned integers correctly
|
||||
struct safe_less {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& t, const U& u) const noexcept {
|
||||
return impl(number_category<T>{}, number_category<U>{}, t, u);
|
||||
}
|
||||
|
||||
template <class C1, class C2, class T, class U>
|
||||
bool impl(C1, C2, const T& t, const U& u) const noexcept {
|
||||
return t < u;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool impl(type<int>, type<unsigned>, const T& t, const U& u) const noexcept {
|
||||
return t < 0 || make_unsigned(t) < u;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
bool impl(type<unsigned>, type<int>, const T& t, const U& u) const noexcept {
|
||||
return 0 < u && t < make_unsigned(u);
|
||||
}
|
||||
};
|
||||
|
||||
// version of std::greater<> which handles signed and unsigned integers correctly
|
||||
struct safe_greater {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& t, const U& u) const noexcept {
|
||||
return safe_less()(u, t);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
277
install/boost_1_75_0/include/boost/histogram/detail/span.hpp
Normal file
277
install/boost_1_75_0/include/boost/histogram/detail/span.hpp
Normal file
@@ -0,0 +1,277 @@
|
||||
// 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_SPAN_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_SPAN_HPP
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#ifdef __cpp_lib_span
|
||||
#if __cpp_lib_span >= 201902
|
||||
#define BOOST_HISTOGRAM_DETAIL_HAS_STD_SPAN
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HISTOGRAM_DETAIL_HAS_STD_SPAN
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
using std::span;
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#else // C++17 span not available, so we use our implementation
|
||||
|
||||
// to be replaced by boost::span
|
||||
|
||||
#include <array>
|
||||
#include <boost/histogram/detail/nonmember_container_access.hpp>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
namespace dtl = ::boost::histogram::detail;
|
||||
|
||||
static constexpr std::size_t dynamic_extent = ~static_cast<std::size_t>(0);
|
||||
|
||||
template <class T, std::size_t N>
|
||||
class span_base {
|
||||
public:
|
||||
constexpr T* data() noexcept { return begin_; }
|
||||
constexpr const T* data() const noexcept { return begin_; }
|
||||
constexpr std::size_t size() const noexcept { return N; }
|
||||
|
||||
protected:
|
||||
constexpr span_base(T* b, std::size_t s) noexcept : begin_(b) {
|
||||
(void)s;
|
||||
assert(N == s);
|
||||
}
|
||||
constexpr void set(T* b, std::size_t s) noexcept {
|
||||
(void)s;
|
||||
begin_ = b;
|
||||
assert(N == s);
|
||||
}
|
||||
|
||||
private:
|
||||
T* begin_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class span_base<T, dynamic_extent> {
|
||||
public:
|
||||
constexpr span_base() noexcept : begin_(nullptr), size_(0) {}
|
||||
|
||||
constexpr T* data() noexcept { return begin_; }
|
||||
constexpr const T* data() const noexcept { return begin_; }
|
||||
constexpr std::size_t size() const noexcept { return size_; }
|
||||
|
||||
protected:
|
||||
constexpr span_base(T* b, std::size_t s) noexcept : begin_(b), size_(s) {}
|
||||
constexpr void set(T* b, std::size_t s) noexcept {
|
||||
begin_ = b;
|
||||
size_ = s;
|
||||
}
|
||||
|
||||
private:
|
||||
T* begin_;
|
||||
std::size_t size_;
|
||||
};
|
||||
|
||||
template <class T, std::size_t Extent = dynamic_extent>
|
||||
class span : public span_base<T, Extent> {
|
||||
using base = span_base<T, Extent>;
|
||||
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using index_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr std::size_t extent = Extent;
|
||||
|
||||
using base::base;
|
||||
|
||||
constexpr span(pointer first, pointer last)
|
||||
: span(first, static_cast<std::size_t>(last - first)) {
|
||||
assert(extent == dynamic_extent ||
|
||||
static_cast<difference_type>(extent) == (last - first));
|
||||
}
|
||||
|
||||
constexpr span(pointer ptr, index_type count) : base(ptr, count) {}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr span(element_type (&arr)[N]) noexcept : span(dtl::data(arr), N) {
|
||||
static_assert(extent == dynamic_extent || extent == N, "static sizes do not match");
|
||||
}
|
||||
|
||||
template <std::size_t N,
|
||||
class = std::enable_if_t<(extent == dynamic_extent || extent == N)> >
|
||||
constexpr span(std::array<value_type, N>& arr) noexcept : span(dtl::data(arr), N) {}
|
||||
|
||||
template <std::size_t N,
|
||||
class = std::enable_if_t<(extent == dynamic_extent || extent == N)> >
|
||||
constexpr span(const std::array<value_type, N>& arr) noexcept
|
||||
: span(dtl::data(arr), N) {}
|
||||
|
||||
template <class Container, class = std::enable_if_t<std::is_convertible<
|
||||
decltype(dtl::size(std::declval<const Container&>()),
|
||||
dtl::data(std::declval<const Container&>())),
|
||||
pointer>::value> >
|
||||
constexpr span(const Container& cont) : span(dtl::data(cont), dtl::size(cont)) {}
|
||||
|
||||
template <class Container, class = std::enable_if_t<std::is_convertible<
|
||||
decltype(dtl::size(std::declval<Container&>()),
|
||||
dtl::data(std::declval<Container&>())),
|
||||
pointer>::value> >
|
||||
constexpr span(Container& cont) : span(dtl::data(cont), dtl::size(cont)) {}
|
||||
|
||||
template <class U, std::size_t N,
|
||||
class = std::enable_if_t<((extent == dynamic_extent || extent == N) &&
|
||||
std::is_convertible<U, element_type>::value)> >
|
||||
constexpr span(const span<U, N>& s) noexcept : span(s.data(), s.size()) {}
|
||||
|
||||
template <class U, std::size_t N,
|
||||
class = std::enable_if_t<((extent == dynamic_extent || extent == N) &&
|
||||
std::is_convertible<U, element_type>::value)> >
|
||||
constexpr span(span<U, N>& s) noexcept : span(s.data(), s.size()) {}
|
||||
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
|
||||
constexpr iterator begin() { return base::data(); }
|
||||
constexpr const_iterator begin() const { return base::data(); }
|
||||
constexpr const_iterator cbegin() const { return base::data(); }
|
||||
|
||||
constexpr iterator end() { return base::data() + base::size(); }
|
||||
constexpr const_iterator end() const { return base::data() + base::size(); }
|
||||
constexpr const_iterator cend() const { return base::data() + base::size(); }
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const { return reverse_iterator(end()); }
|
||||
const_reverse_iterator crbegin() { return reverse_iterator(end()); }
|
||||
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator crend() { return reverse_iterator(begin()); }
|
||||
|
||||
constexpr reference front() { return *base::data(); }
|
||||
constexpr reference back() { return *(base::data() + base::size() - 1); }
|
||||
|
||||
constexpr reference operator[](index_type idx) const { return base::data()[idx]; }
|
||||
|
||||
constexpr std::size_t size_bytes() const noexcept {
|
||||
return base::size() * sizeof(element_type);
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept { return base::size() == 0; }
|
||||
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const {
|
||||
assert(Count <= base::size());
|
||||
return span<element_type, Count>(base::data(), Count);
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> first(std::size_t count) const {
|
||||
assert(count <= base::size());
|
||||
return span<element_type, dynamic_extent>(base::data(), count);
|
||||
}
|
||||
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> last() const {
|
||||
assert(Count <= base::size());
|
||||
return span<element_type, Count>(base::data() + base::size() - Count, Count);
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> last(std::size_t count) const {
|
||||
assert(count <= base::size());
|
||||
return span<element_type, dynamic_extent>(base::data() + base::size() - count, count);
|
||||
}
|
||||
|
||||
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
constexpr span<element_type,
|
||||
(Count != dynamic_extent
|
||||
? Count
|
||||
: (extent != dynamic_extent ? extent - Offset : dynamic_extent))>
|
||||
subspan() const {
|
||||
assert(Offset <= base::size());
|
||||
constexpr std::size_t E =
|
||||
(Count != dynamic_extent
|
||||
? Count
|
||||
: (extent != dynamic_extent ? extent - Offset : dynamic_extent));
|
||||
assert(E == dynamic_extent || E <= base::size());
|
||||
return span<element_type, E>(base::data() + Offset,
|
||||
Count == dynamic_extent ? base::size() - Offset : Count);
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> subspan(
|
||||
std::size_t offset, std::size_t count = dynamic_extent) const {
|
||||
assert(offset <= base::size());
|
||||
const std::size_t s = count == dynamic_extent ? base::size() - offset : count;
|
||||
assert(s <= base::size());
|
||||
return span<element_type, dynamic_extent>(base::data() + offset, s);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
#include <boost/histogram/detail/nonmember_container_access.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
namespace dtl = ::boost::histogram::detail;
|
||||
|
||||
template <class T>
|
||||
auto make_span(T* begin, T* end) {
|
||||
return dtl::span<T>{begin, end};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_span(T* begin, std::size_t size) {
|
||||
return dtl::span<T>{begin, size};
|
||||
}
|
||||
|
||||
template <class Container, class = decltype(dtl::size(std::declval<Container>()),
|
||||
dtl::data(std::declval<Container>()))>
|
||||
auto make_span(const Container& cont) {
|
||||
return make_span(dtl::data(cont), dtl::size(cont));
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
auto make_span(T (&arr)[N]) {
|
||||
return dtl::span<T, N>(arr, N);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2018-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_STATIC_IF_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_STATIC_IF_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class F, class... Args>
|
||||
constexpr decltype(auto) static_if_impl(
|
||||
std::true_type, T&& t, F&&,
|
||||
Args&&... args) noexcept(noexcept(std::declval<T>()(std::declval<Args>()...))) {
|
||||
return std::forward<T>(t)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class T, class F, class... Args>
|
||||
constexpr decltype(auto) static_if_impl(
|
||||
std::false_type, T&&, F&& f,
|
||||
Args&&... args) noexcept(noexcept(std::declval<F>()(std::declval<Args>()...))) {
|
||||
return std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <bool B, class... Ts>
|
||||
constexpr decltype(auto) static_if_c(Ts&&... ts) noexcept(
|
||||
noexcept(static_if_impl(std::integral_constant<bool, B>{}, std::declval<Ts>()...))) {
|
||||
return static_if_impl(std::integral_constant<bool, B>{}, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
template <class Bool, class... Ts>
|
||||
constexpr decltype(auto) static_if(Ts&&... ts) noexcept(
|
||||
noexcept(static_if_impl(Bool{}, std::declval<Ts>()...))) {
|
||||
return static_if_impl(Bool{}, std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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_SUB_ARRAY_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_SUB_ARRAY_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, std::size_t N>
|
||||
class sub_array {
|
||||
constexpr bool swap_element_is_noexcept() noexcept {
|
||||
using std::swap;
|
||||
return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = std::size_t;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
|
||||
sub_array() = default;
|
||||
|
||||
explicit sub_array(std::size_t s) noexcept : size_(s) { assert(size_ <= N); }
|
||||
|
||||
sub_array(std::size_t s, const T& value) noexcept(
|
||||
std::is_nothrow_assignable<T, const_reference>::value)
|
||||
: sub_array(s) {
|
||||
fill(value);
|
||||
}
|
||||
|
||||
reference at(size_type pos) noexcept {
|
||||
if (pos >= size()) BOOST_THROW_EXCEPTION(std::out_of_range{"pos is out of range"});
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
const_reference at(size_type pos) const noexcept {
|
||||
if (pos >= size()) BOOST_THROW_EXCEPTION(std::out_of_range{"pos is out of range"});
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
reference operator[](size_type pos) noexcept { return data_[pos]; }
|
||||
const_reference operator[](size_type pos) const noexcept { return data_[pos]; }
|
||||
|
||||
reference front() noexcept { return data_[0]; }
|
||||
const_reference front() const noexcept { return data_[0]; }
|
||||
|
||||
reference back() noexcept { return data_[size_ - 1]; }
|
||||
const_reference back() const noexcept { return data_[size_ - 1]; }
|
||||
|
||||
pointer data() noexcept { return static_cast<pointer>(data_); }
|
||||
const_pointer data() const noexcept { return static_cast<const_pointer>(data_); }
|
||||
|
||||
iterator begin() noexcept { return data_; }
|
||||
const_iterator begin() const noexcept { return data_; }
|
||||
|
||||
iterator end() noexcept { return begin() + size_; }
|
||||
const_iterator end() const noexcept { return begin() + size_; }
|
||||
|
||||
const_iterator cbegin() noexcept { return data_; }
|
||||
const_iterator cbegin() const noexcept { return data_; }
|
||||
|
||||
const_iterator cend() noexcept { return cbegin() + size_; }
|
||||
const_iterator cend() const noexcept { return cbegin() + size_; }
|
||||
|
||||
constexpr size_type max_size() const noexcept { return N; }
|
||||
size_type size() const noexcept { return size_; }
|
||||
bool empty() const noexcept { return size_ == 0; }
|
||||
|
||||
void fill(const_reference value) noexcept(
|
||||
std::is_nothrow_assignable<T, const_reference>::value) {
|
||||
std::fill(begin(), end(), value);
|
||||
}
|
||||
|
||||
void swap(sub_array& other) noexcept(swap_element_is_noexcept()) {
|
||||
using std::swap;
|
||||
for (auto i = begin(), j = other.begin(); i != end(); ++i, ++j) swap(*i, *j);
|
||||
}
|
||||
|
||||
private:
|
||||
size_type size_ = 0;
|
||||
value_type data_[N];
|
||||
};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
bool operator==(const sub_array<T, N>& a, const sub_array<T, N>& b) noexcept {
|
||||
return std::equal(a.begin(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
bool operator!=(const sub_array<T, N>& a, const sub_array<T, N>& b) noexcept {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
namespace std {
|
||||
template <class T, std::size_t N>
|
||||
void swap(::boost::histogram::detail::sub_array<T, N>& a,
|
||||
::boost::histogram::detail::sub_array<T, N>& b) noexcept(noexcept(a.swap(b))) {
|
||||
a.swap(b);
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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_TRY_CAST_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_TRY_CAST_HPP
|
||||
|
||||
#include <boost/config.hpp> // BOOST_NORETURN
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
constexpr T* ptr_cast(U*) noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr T* ptr_cast(T* p) noexcept {
|
||||
return p;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr const T* ptr_cast(const T* p) noexcept {
|
||||
return p;
|
||||
}
|
||||
|
||||
template <class T, class E, class U>
|
||||
BOOST_NORETURN T try_cast_impl(std::false_type, std::false_type, U&&) {
|
||||
BOOST_THROW_EXCEPTION(E("type cast error"));
|
||||
}
|
||||
|
||||
// converting cast
|
||||
template <class T, class E, class U>
|
||||
T try_cast_impl(std::false_type, std::true_type, U&& u) noexcept {
|
||||
return static_cast<T>(u); // cast to avoid warnings
|
||||
}
|
||||
|
||||
// pass-through cast
|
||||
template <class T, class E>
|
||||
T&& try_cast_impl(std::true_type, std::true_type, T&& t) noexcept {
|
||||
return std::forward<T>(t);
|
||||
}
|
||||
|
||||
// cast fails at runtime with exception E instead of compile-time, T must be a value
|
||||
template <class T, class E, class U>
|
||||
T try_cast(U&& u) noexcept(std::is_convertible<U, T>::value) {
|
||||
return try_cast_impl<T, E>(std::is_same<U, T>{}, std::is_convertible<U, T>{},
|
||||
std::forward<U>(u));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2015-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_TUPLE_SLICE_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_TUPLE_SLICE_HPP
|
||||
|
||||
#include <boost/mp11/integer_sequence.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <std::size_t I, class T, std::size_t... K>
|
||||
decltype(auto) tuple_slice_impl(T&& t, mp11::index_sequence<K...>) {
|
||||
return std::forward_as_tuple(std::get<(I + K)>(std::forward<T>(t))...);
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N, class Tuple>
|
||||
decltype(auto) tuple_slice(Tuple&& t) {
|
||||
constexpr auto S = std::tuple_size<std::decay_t<Tuple>>::value;
|
||||
static_assert(I + N <= S, "I, N must be a valid subset");
|
||||
return tuple_slice_impl<I>(std::forward<Tuple>(t), mp11::make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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_TYPE_NAME_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_TYPE_NAME_HPP
|
||||
|
||||
#include <boost/core/typeinfo.hpp>
|
||||
#include <boost/type.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
std::string type_name_impl(boost::type<T>) {
|
||||
return boost::core::demangled_name(BOOST_CORE_TYPEID(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string type_name_impl(boost::type<T const>) {
|
||||
return type_name_impl(boost::type<T>{}) + " const";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string type_name_impl(boost::type<T&>) {
|
||||
return type_name_impl(boost::type<T>{}) + " &";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string type_name_impl(boost::type<T&&>) {
|
||||
return type_name_impl(boost::type<T>{}) + " &&";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string type_name() {
|
||||
return type_name_impl(boost::type<T>{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user