diff --git a/examples/guide_axis_with_uoflow_off.cpp b/examples/guide_axis_with_uoflow_off.cpp index a7b70e95..69e5fc65 100644 --- a/examples/guide_axis_with_uoflow_off.cpp +++ b/examples/guide_axis_with_uoflow_off.cpp @@ -7,7 +7,7 @@ namespace bh = boost::histogram; int main() { // create a 1d-histogram for dice throws with integer values from 1 to 6 auto h = bh::make_static_histogram( - bh::axis::integer<>(1, 7, "eyes", bh::axis::uoflow::off)); + bh::axis::integer<>(1, 7, "eyes", bh::axis::uoflow_type::off)); // do something with h } diff --git a/examples/guide_custom_storage.cpp b/examples/guide_custom_storage.cpp index 0e64179b..2114b19d 100644 --- a/examples/guide_custom_storage.cpp +++ b/examples/guide_custom_storage.cpp @@ -7,8 +7,8 @@ namespace bh = boost::histogram; int main() { // create static histogram with array_storage, using int as counter type - auto h = bh::make_static_histogram_with>( - bh::axis::regular<>(10, 0, 1)); + auto h = bh::make_static_histogram_with(bh::array_storage(), + bh::axis::regular<>(10, 0, 1)); // do something with h } diff --git a/examples/guide_histogram_streaming.cpp b/examples/guide_histogram_streaming.cpp index e49267e5..1c465671 100644 --- a/examples/guide_histogram_streaming.cpp +++ b/examples/guide_histogram_streaming.cpp @@ -12,12 +12,12 @@ int main() { enum { A, B, C }; auto h = bh::make_static_histogram( - axis::regular<>(2, -1, 1, "regular1", axis::uoflow::off), - axis::regular(2, 1, 10, "regular2"), + axis::regular<>(2, -1, 1, "regular1", axis::uoflow_type::off), + axis::regular(2, 1, 10, "regular2"), axis::circular<>(4, 0.1, 1.0, "polar"), - axis::variable<>({-1, 0, 1}, "variable", axis::uoflow::off), + axis::variable<>({-1, 0, 1}, "variable", axis::uoflow_type::off), axis::category<>({A, B, C}, "category"), - axis::integer<>(-1, 1, "integer", axis::uoflow::off)); + axis::integer<>(-1, 1, "integer", axis::uoflow_type::off)); std::cout << h << std::endl; diff --git a/examples/guide_mixed_cpp_python.cpp b/examples/guide_mixed_cpp_python.cpp index a2c05ebc..a96ca4eb 100644 --- a/examples/guide_mixed_cpp_python.cpp +++ b/examples/guide_mixed_cpp_python.cpp @@ -7,7 +7,7 @@ namespace bh = boost::histogram; namespace bp = boost::python; // function that runs in C++ and accepts reference to dynamic histogram -void process(bh::dynamic_histogram<>& h) { +void process(bh::histogram<>& h) { // fill histogram, in reality this would be arbitrarily complex code for (int i = 0; i < 4; ++i) h(0.25 * i, i); } diff --git a/include/boost/histogram.hpp b/include/boost/histogram.hpp index bfdd305e..53ac7f15 100644 --- a/include/boost/histogram.hpp +++ b/include/boost/histogram.hpp @@ -9,9 +9,8 @@ #include #include -#include +#include #include -#include #include #include #include diff --git a/include/boost/histogram/arithmetic_operators.hpp b/include/boost/histogram/arithmetic_operators.hpp index 1aa9d1e5..b177a1e6 100644 --- a/include/boost/histogram/arithmetic_operators.hpp +++ b/include/boost/histogram/arithmetic_operators.hpp @@ -12,69 +12,66 @@ namespace boost { namespace histogram { -template -histogram&& operator+(histogram&& a, - const histogram& b) { +template +histogram&& operator+(histogram&& a, const histogram& b) { a += b; return std::move(a); } -template -histogram&& operator+(histogram&& a, - histogram&& b) { +template +histogram&& operator+(histogram&& a, histogram&& b) { a += b; return std::move(a); } -template -histogram&& operator+(const histogram& a, - histogram&& b) { +template +histogram&& operator+(const histogram& a, histogram&& b) { b += a; return std::move(b); } -template -histogram operator+(const histogram& a, - const histogram& b) { - histogram r(a); +template +histogram operator+(const histogram& a, + const histogram& b) { + histogram r(a); r += b; return r; } -template -histogram&& operator*(histogram&& a, const double x) { +template +histogram&& operator*(histogram&& a, const double x) { a *= x; return std::move(a); } -template -histogram&& operator*(const double x, histogram&& b) { +template +histogram&& operator*(const double x, histogram&& b) { b *= x; return std::move(b); } -template -histogram operator*(const histogram& a, const double x) { +template +histogram operator*(const histogram& a, const double x) { auto r = a; r *= x; return r; } -template -histogram operator*(const double x, const histogram& b) { +template +histogram operator*(const double x, const histogram& b) { auto r = b; r *= x; return r; } -template -histogram&& operator/(histogram&& a, const double x) { +template +histogram&& operator/(histogram&& a, const double x) { a /= x; return std::move(a); } -template -histogram operator/(const histogram& a, const double x) { +template +histogram operator/(const histogram& a, const double x) { auto r = a; r /= x; return r; diff --git a/include/boost/histogram/detail/axes.hpp b/include/boost/histogram/detail/axes.hpp new file mode 100644 index 00000000..20fd42df --- /dev/null +++ b/include/boost/histogram/detail/axes.hpp @@ -0,0 +1,359 @@ +// Copyright 2015-2017 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace histogram { +namespace detail { + +namespace { + +template +struct axes_equal_static_dynamic_impl { + bool& equal; + const StaticAxes& t; + const DynamicAxes& v; + axes_equal_static_dynamic_impl(bool& eq, const StaticAxes& tt, + const DynamicAxes& vv) + : equal(eq), t(tt), v(vv) {} + template + void operator()(Int) const { + using T = mp11::mp_at; + auto tp = boost::get(&v[Int::value]); + equal &= (tp && *tp == std::get(t)); + } +}; + +template +bool axes_equal_static_static_impl(mp11::mp_true, const static_axes& t, + const static_axes& u) { + return t == u; +} + +template +bool axes_equal_static_static_impl(mp11::mp_false, const static_axes&, + const static_axes&) { + return false; +} + +template +struct axes_assign_static_dynamic_impl { + StaticAxes& t; + const DynamicAxes& v; + axes_assign_static_dynamic_impl(StaticAxes& tt, const DynamicAxes& vv) + : t(tt), v(vv) {} + template + void operator()(Int) const { + using T = mp11::mp_at; + std::get(t) = boost::get(v[Int::value]); + } +}; + +template +struct axes_assign_dynamic_static_impl { + DynamicAxes& v; + const StaticAxes& t; + axes_assign_dynamic_static_impl(DynamicAxes& vv, const StaticAxes& tt) + : v(vv), t(tt) {} + template + void operator()(Int) const { + v[Int::value] = std::get(t); + } +}; +} // namespace + +template +bool axes_equal(const static_axes& t, const static_axes& u) { + return axes_equal_static_static_impl( + mp11::mp_same, mp11::mp_list>(), t, u); +} + +template +bool axes_equal(const static_axes& t, const dynamic_axes& u) { + if (sizeof...(Ts) != u.size()) return false; + bool equal = true; + auto fn = + axes_equal_static_dynamic_impl, dynamic_axes>( + equal, t, u); + mp11::mp_for_each>(fn); + return equal; +} + +template +bool axes_equal(const dynamic_axes& t, const static_axes& u) { + return axes_equal(u, t); +} + +template +bool axes_equal(const dynamic_axes& t, const dynamic_axes& u) { + if (t.size() != u.size()) return false; + return std::equal(t.begin(), t.end(), u.begin()); +} + +template +void axes_assign(static_axes& t, const static_axes& u) { + static_assert( + std::is_same, mp11::mp_list>::value, + "cannot assign incompatible axes"); + t = u; +} + +template +void axes_assign(static_axes& t, const dynamic_axes& u) { + auto fn = axes_assign_static_dynamic_impl, + dynamic_axes>(t, u); + mp11::mp_for_each>(fn); +} + +template +void axes_assign(dynamic_axes& t, const static_axes& u) { + t.resize(sizeof...(Us)); + auto fn = axes_assign_dynamic_static_impl, + static_axes>(t, u); + mp11::mp_for_each>(fn); +} + +template +void axes_assign(dynamic_axes& t, const dynamic_axes& u) { + t.assign(u.begin(), u.end()); +} + +template +constexpr unsigned axes_size(const static_axes&) { + return sizeof...(Ts); +} + +template +unsigned axes_size(const dynamic_axes& axes) { + return axes.size(); +} + +template +void range_check(const dynamic_axes& axes) { + BOOST_ASSERT_MSG(N < axes.size(), "index out of range"); +} + +template +void range_check(const static_axes&) { + static_assert(N < sizeof...(Ts), "index out of range"); +} + +namespace { +template +struct at_impl {}; + +template +struct at_impl> { + using type = mp11::mp_at_c, N>; +}; + +template +struct at_impl> { + using type = axis::any; +}; +} + +template +using at = typename at_impl::type; + +template +auto get(static_axes& axes) -> at>& { + return std::get(axes); +} + +template +auto get(const static_axes& axes) -> const at>& { + return std::get(axes); +} + +template +axis::any& get(dynamic_axes& axes) { + return axes[N]; +} + +template +const axis::any& get(const dynamic_axes& axes) { + return axes[N]; +} + +template +void for_each_axis(const static_axes& axes, F&& f) { + mp11::tuple_for_each(axes, std::forward(f)); +} + +namespace { +template +struct unary_adaptor : public boost::static_visitor { + Unary&& unary; + unary_adaptor(Unary&& u) : unary(std::forward(u)) {} + template + void operator()(const T& a) const { + unary(a); + } +}; +} + +template +void for_each_axis(const dynamic_axes& axes, F&& f) { + for (const auto& x : axes) { + boost::apply_visitor(unary_adaptor(std::forward(f)), x); + } +} + +namespace { +struct field_counter { + std::size_t value = 1; + template + void operator()(const T& t) { + value *= t.shape(); + } +}; +} + +template +std::size_t bincount(const T& axes) { + field_counter fc; + for_each_axis(axes, fc); + return fc.value; +} + +template +void dimension_check(const static_axes&, mp11::mp_size_t) { + static_assert(sizeof...(Ts) == N, "number of arguments does not match"); +} + +template +void dimension_check(const dynamic_axes& axes, mp11::mp_size_t) { + BOOST_ASSERT_MSG(axes.size() == N, "number of arguments does not match"); +} + +struct shape_collector { + std::vector::iterator iter; + shape_collector(std::vector::iterator i) : iter(i) {} + template + void operator()(const T& a) { + *iter++ = a.shape(); + } +}; + +namespace { +template +struct sub_axes_impl {}; + +template +struct sub_axes_impl> { + template + using at = mp11::mp_at, I>; + using L = mp11::mp_rename, static_axes>; + using type = mp11::mp_transform; +}; + +template +struct sub_axes_impl> { + using type = dynamic_axes; +}; +} + +template +using sub_axes = typename sub_axes_impl, T>::type; + +namespace { +template +struct sub_static_assign_impl { + const Src& src; + Dst& dst; + template + void operator()(std::pair) const { + std::get(dst) = std::get(src); + } +}; +} + +template +sub_axes, Ns...> make_sub_axes(const static_axes& t, + Ns...) { + using T = static_axes; + using U = sub_axes, Ns...>; + U u; + using N1 = unique_sorted>; + using N2 = mp11::mp_iota>; + using N3 = mp11::mp_transform; + mp11::mp_for_each(sub_static_assign_impl{t, u}); + return u; +} + +namespace { +template +struct sub_dynamic_assign_impl { + const T& src; + T& dst; + template + void operator()(I) const { + dst.emplace_back(src[I::value]); + } +}; +} + +template +sub_axes, Ns...> make_sub_axes( + const dynamic_axes& t, Ns...) { + using T = dynamic_axes; + T u; + u.reserve(sizeof...(Ns)); + using N = unique_sorted>; + mp11::mp_for_each(sub_dynamic_assign_impl{t, u}); + return u; +} + +struct optional_index { + std::size_t idx = 0; + std::size_t shape = 0; + operator bool() const { return shape > 0; } + std::size_t operator*() const { return idx; } +}; + +template +optional_index args_to_index(const static_axes&, const Us&...) { + auto index = optional_index(); + return index; +} + +template +optional_index args_to_index(const dynamic_axes&, const Us&...) { + auto index = optional_index(); + return index; +} + +template +optional_index indices_to_index(const static_axes&, const Us&...) { + auto index = optional_index(); + return index; +} + +template +optional_index indices_to_index(const dynamic_axes&, const Us&...) { + auto index = optional_index(); + return index; +} + +} // namespace detail +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/detail/axis_visitor.hpp b/include/boost/histogram/detail/axis_visitor.hpp deleted file mode 100644 index c81fa25d..00000000 --- a/include/boost/histogram/detail/axis_visitor.hpp +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2015-2017 Hans Demsizeki -// -// 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_HISTOGARM_AXIS_VISITOR_HPP_ -#define _BOOST_HISTOGARM_AXIS_VISITOR_HPP_ - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace histogram { -namespace detail { - -template -using dynamic_axes = std::vector>; - -template -using static_axes = std::tuple; - -namespace { - -template -struct axes_equal_static_dynamic_impl { - bool& equal; - const StaticAxes& t; - const DynamicAxes& v; - axes_equal_static_dynamic_impl(bool& eq, const StaticAxes& tt, - const DynamicAxes& vv) - : equal(eq), t(tt), v(vv) {} - template - void operator()(Int) const { - using T = mp11::mp_at; - auto tp = boost::get(&v[Int::value]); - equal &= (tp && *tp == std::get(t)); - } -}; - -template -bool axes_equal_static_static_impl(mp11::mp_true, const static_axes& t, - const static_axes& u) { - return t == u; -} - -template -bool axes_equal_static_static_impl(mp11::mp_false, const static_axes&, - const static_axes&) { - return false; -} - -template -struct axes_assign_static_dynamic_impl { - StaticAxes& t; - const DynamicAxes& v; - axes_assign_static_dynamic_impl(StaticAxes& tt, const DynamicAxes& vv) - : t(tt), v(vv) {} - template - void operator()(Int) const { - using T = mp11::mp_at; - std::get(t) = boost::get(v[Int::value]); - } -}; - -template -struct axes_assign_dynamic_static_impl { - DynamicAxes& v; - const StaticAxes& t; - axes_assign_dynamic_static_impl(DynamicAxes& vv, const StaticAxes& tt) - : v(vv), t(tt) {} - template - void operator()(Int) const { - v[Int::value] = std::get(t); - } -}; -} // namespace - -template -bool axes_equal(const static_axes& t, const static_axes& u) { - return axes_equal_static_static_impl( - mp11::mp_same, mp11::mp_list>(), t, u); -} - -template -void axes_assign(static_axes& t, const static_axes& u) { - static_assert( - std::is_same, mp11::mp_list>::value, - "cannot assign incompatible axes"); - t = u; -} - -template -bool axes_equal(const static_axes& t, const dynamic_axes& u) { - if (sizeof...(Ts) != u.size()) return false; - bool equal = true; - auto fn = - axes_equal_static_dynamic_impl, dynamic_axes>( - equal, t, u); - mp11::mp_for_each>(fn); - return equal; -} - -template -void axes_assign(static_axes& t, const dynamic_axes& u) { - auto fn = axes_assign_static_dynamic_impl, - dynamic_axes>(t, u); - mp11::mp_for_each>(fn); -} - -template -bool axes_equal(const dynamic_axes& t, const static_axes& u) { - return axes_equal(u, t); -} - -template -void axes_assign(dynamic_axes& t, const static_axes& u) { - t.resize(sizeof...(Us)); - auto fn = axes_assign_dynamic_static_impl, - static_axes>(t, u); - mp11::mp_for_each>(fn); -} - -template -bool axes_equal(const dynamic_axes& t, const dynamic_axes& u) { - if (t.size() != u.size()) return false; - for (std::size_t i = 0; i < t.size(); ++i) { - if (t[i] != u[i]) return false; - } - return true; -} - -template -void axes_assign(dynamic_axes& t, const dynamic_axes& u) { - for (std::size_t i = 0; i < t.size(); ++i) { t[i] = u[i]; } -} - -struct shape_collector { - std::vector::iterator iter; - shape_collector(std::vector::iterator i) : iter(i) {} - template - void operator()(const T& a) { - *iter++ = a.shape(); - } -}; - -struct field_counter { - std::size_t value = 1; - template - void operator()(const T& t) { - value *= t.shape(); - } -}; - -template -struct unary_adaptor_visitor : public static_visitor { - Unary&& unary; - unary_adaptor_visitor(Unary&& u) : unary(std::forward(u)) {} - template - void operator()(const T& a) const { - unary(a); - } -}; - -} // namespace detail -} // namespace histogram -} // namespace boost - -#endif diff --git a/include/boost/histogram/detail/meta.hpp b/include/boost/histogram/detail/meta.hpp index e3a08e45..479b0bd5 100644 --- a/include/boost/histogram/detail/meta.hpp +++ b/include/boost/histogram/detail/meta.hpp @@ -69,6 +69,9 @@ template (), ++std::declval())> struct requires_iterator {}; +template ()[0])> +struct requires_dynamic_axes {}; + template using requires_axis = decltype(std::declval().size(), std::declval().shape(), @@ -116,46 +119,9 @@ template using mp_set_union = mp11::mp_apply_q, L>; -namespace { -template -struct selection_impl { - template - using at = mp11::mp_at; - using N = mp11::mp_list; - using LNs = mp11::mp_assign; - using type = mp11::mp_transform; -}; -} - -template -using selection = typename selection_impl::type; - template using unique_sorted = mp11::mp_unique>; -namespace { -template -struct sub_tuple_assign_impl { - const Src& src; - Dst& dst; - template - void operator()(std::pair) const { - std::get(dst) = std::get(src); - } -}; -} - -template -selection make_sub_tuple(const T& t) { - using U = selection; - U u; - using N1 = mp11::mp_list; - using Len = mp11::mp_size; - using N2 = mp11::mp_iota; - using N3 = mp11::mp_transform; - mp11::mp_for_each(sub_tuple_assign_impl{t, u}); - return u; -} } // namespace detail } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/detail/utility.hpp b/include/boost/histogram/detail/utility.hpp index e640fb0c..1c2084ac 100644 --- a/include/boost/histogram/detail/utility.hpp +++ b/include/boost/histogram/detail/utility.hpp @@ -7,38 +7,14 @@ #ifndef _BOOST_HISTOGRAM_DETAIL_UTILITY_HPP_ #define _BOOST_HISTOGRAM_DETAIL_UTILITY_HPP_ -#include #include -#include #include -#include -#include -#include -#include -#include -#include #include -#include namespace boost { namespace histogram { namespace detail { -// two_pi can be found in boost/math, but it is defined here to reduce deps -constexpr double two_pi = 6.283185307179586; - -inline void escape(std::ostream& os, const string_view s) { - os << '\''; - for (auto sit = s.begin(); sit != s.end(); ++sit) { - if (*sit == '\'' && (sit == s.begin() || *(sit - 1) != '\\')) { - os << "\\\'"; - } else { - os << *sit; - } - } - os << '\''; -} - // the following is highly optimized code that runs in a hot loop; // please measure the performance impact of changes inline void lin(std::size_t& out, std::size_t& stride, const int axis_size, @@ -66,23 +42,6 @@ indirect_int_cast(T&&) noexcept { return 0; } -template -void fill_storage(S& s, std::size_t idx, weight&& w) { - s.add(idx, w); -} - -template -void fill_storage(S& s, std::size_t idx) { - s.increase(idx); -} - -template -auto storage_get(const S& s, std::size_t idx, bool error) -> - typename S::const_reference { - if (error) throw std::out_of_range("bin index out of range"); - return s[idx]; -} - } // namespace detail } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/histogram.hpp b/include/boost/histogram/histogram.hpp new file mode 100644 index 00000000..c1d93e07 --- /dev/null +++ b/include/boost/histogram/histogram.hpp @@ -0,0 +1,349 @@ +// Copyright 2015-2017 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_HISTOGRAM_HPP_ +#define _BOOST_HISTOGRAM_HISTOGRAM_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// forward declaration for serialization +namespace boost { +namespace serialization { +class access; +} +} + +namespace boost { +namespace histogram { + +template +class histogram { + using axes_size = mp11::mp_size; + static_assert(axes_size::value > 0, "at least one axis required"); + +public: + using axes_type = Axes; + using storage_type = Storage; + using element_type = typename storage_type::element_type; + using const_reference = typename storage_type::const_reference; + using const_iterator = iterator_over; + + histogram() = default; + histogram(const histogram& rhs) = default; + histogram(histogram&& rhs) = default; + histogram& operator=(const histogram& rhs) = default; + histogram& operator=(histogram&& rhs) = default; + + template + explicit histogram(const histogram& rhs) : storage_(rhs.storage_) { + detail::axes_assign(axes_, rhs.axes_); + } + + template + histogram& operator=(const histogram& rhs) { + storage_ = rhs.storage_; + detail::axes_assign(axes_, rhs.axes_); + return *this; + } + + explicit histogram(const axes_type& a, + const storage_type& s = storage_type()) + : axes_(a), storage_(s) { + storage_.reset(detail::bincount(axes_)); + } + + explicit histogram(axes_type&& a, storage_type&& s = storage_type()) + : axes_(std::move(a)), storage_(std::move(s)) { + storage_.reset(detail::bincount(axes_)); + } + + template + bool operator==(const histogram& rhs) const noexcept { + return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_; + } + + template + bool operator!=(const histogram& rhs) const noexcept { + return !operator==(rhs); + } + + template + histogram& operator+=(const histogram& rhs) { + if (!detail::axes_equal(axes_, rhs.axes_)) + throw std::invalid_argument("axes of histograms differ"); + storage_ += rhs.storage_; + return *this; + } + + histogram& operator*=(const double rhs) { + storage_ *= rhs; + return *this; + } + + histogram& operator/=(const double rhs) { + storage_ *= 1.0 / rhs; + return *this; + } + + /// Number of axes (dimensions) of histogram + unsigned dim() const noexcept { return detail::axes_size(axes_); } + + /// Total number of bins in the histogram (including underflow/overflow) + std::size_t size() const noexcept { return storage_.size(); } + + /// Reset bin counters to zero + void reset() { storage_.reset(storage_.size()); } + + /// Get N-th axis (const version) + template + auto axis(mp11::mp_int) const -> const detail::at& { + detail::range_check(axes_); + return detail::get(axes_); + } + + /// Get N-th axis + template + auto axis(mp11::mp_int) -> detail::at& { + detail::range_check(axes_); + return detail::get(axes_); + } + + /// Get first axis (convenience for 1-d histograms, const version) + const detail::at<0, axes_type>& axis() const { + return axis(mp11::mp_int<0>()); + } + + /// Get first axis (convenience for 1-d histograms) + detail::at<0, axes_type>& axis() { return axis(mp11::mp_int<0>()); } + + /// Get N-th axis with runtime index (const version) + template > + const detail::at<0, U>& axis(int i) const { + return axes_[i]; + } + + /// Get N-th axis with runtime index + template > + detail::at<0, U>& axis(int i) { + return axes_[i]; + } + + /// Apply unary functor/function to each axis + template + void for_each_axis(Unary&& unary) const { + detail::for_each_axis(axes_, std::forward(unary)); + } + + /// Fill histogram with a value tuple + template + void operator()(const Ts&... ts) { + // case with one argument needs special treatment, specialized below + detail::dimension_check(axes_, mp11::mp_size_t()); + auto index = detail::args_to_index(axes_, ts...); + if (index) storage_.increase(*index); + } + + template + void operator()(const T&) { + // check whether we need to unpack argument + } + + /// Fill histogram with a value tuple and a weight + template + void operator()(detail::weight_type&& w, const Ts&... ts) { + // case with one argument is ambiguous, is specialized below + detail::dimension_check(axes_, mp11::mp_size_t()); + auto index = detail::args_to_index(axes_, ts...); + if (index) storage_.add(*index, w); + } + + template + void operator()(detail::weight_type&&, const U&) { + // check whether we need to unpack argument + } + + /// Access bin counter at indices + template + const_reference at(const Ts&... ts) const { + // case with one argument is ambiguous, is specialized below + detail::dimension_check(axes_, mp11::mp_size_t()); + auto index = detail::indices_to_index(axes_, static_cast(ts)...); + BOOST_ASSERT_MSG(index, "indices out of bounds"); + return storage_[*index]; + } + + template + const_reference at(const T&) const { + // check whether we need to unpack argument + return storage_[0]; + } + + /// Access bin counter at index + template + const_reference operator[](const T& t) const { + return at(t); + } + + /// Returns a lower-dimensional histogram + template + auto reduce_to(mp11::mp_int, Ns...) const + -> histogram, Ns...>, + storage_type> { + using sub_axes_type = detail::sub_axes, Ns...>; + using HR = histogram; + auto sub_axes = detail::make_sub_axes(axes_, mp11::mp_int(), Ns()...); + auto hr = HR(std::move(sub_axes), storage_type(storage_.get_allocator())); + const auto b = detail::bool_mask, Ns...>(dim(), true); + std::vector shape(dim()); + for_each_axis(detail::shape_collector(shape.begin())); + detail::index_mapper m(shape, b); + do { hr.storage_.add(m.second, storage_[m.first]); } while (m.next()); + return hr; + } + + template , + typename = detail::requires_iterator> + histogram reduce_to(Iterator begin, Iterator end) const { + std::set indices(begin, end); + BOOST_ASSERT_MSG(*indices.rbegin() < dim(), "index out of range"); + auto sub_axes = histogram::axes_type(axes_.get_allocator()); + sub_axes.reserve(indices.size()); + auto b = std::vector(dim(), false); + for (auto k : indices) { + sub_axes.push_back(axes_[k]); + b[k] = true; + } + auto hr = histogram(std::move(sub_axes), + storage_type(storage_.get_allocator())); + std::vector shape(dim()); + for_each_axis(detail::shape_collector(shape.begin())); + detail::index_mapper m(shape, b); + do { hr.storage_.add(m.second, storage_[m.first]); } while (m.next()); + return hr; + } + + const_iterator begin() const noexcept { return const_iterator(*this, 0); } + + const_iterator end() const noexcept { + return const_iterator(*this, size()); + } + +private: + axes_type axes_; + Storage storage_; + + template + friend class histogram; + template + friend class iterator_over; + friend class python_access; + friend class ::boost::serialization::access; + template + void serialize(Archive&, unsigned); +}; + +/// static type factory +template +histogram...>> make_static_histogram( + Ts&&... axis) { + using histogram_type = histogram...>>; + auto axes = typename histogram_type::axes_type(std::forward(axis)...); + return histogram_type(std::move(axes)); +} + +/// static type factory with custom storage type +template +histogram...>, detail::rm_cv_ref> +make_static_histogram_with(Storage&& s, Ts&&... axis) { + using histogram_type = histogram...>, + detail::rm_cv_ref>; + auto axes = typename histogram_type::axes_type(std::forward(axis)...); + return histogram_type(std::move(axes), std::move(s)); +} + +/// dynamic type factory +template +histogram...>, + dynamic_axes>> +make_dynamic_histogram(Ts&&... axis) { + using histogram_type = histogram...>, + dynamic_axes>>; + using value_type = typename histogram_type::axes_type::value_type; + auto axes = typename histogram_type::axes_type( + {value_type(std::forward(axis))...}); + return histogram_type(std::move(axes)); +} + +/// dynamic type factory with custom storage type +template +histogram...>, + dynamic_axes>, + detail::rm_cv_ref> +make_dynamic_histogram_with(Storage&& s, Ts&&... axis) { + using histogram_type = + histogram...>, + dynamic_axes>, + detail::rm_cv_ref>; + using value_type = typename histogram_type::axes_type::value_type; + auto axes = typename histogram_type::axes_type( + {value_type(std::forward(axis))...}); + return histogram_type(std::move(axes), std::move(s)); +} + +/// dynamic type factory from axis iterators +template > +histogram, + dynamic_axes>> +make_dynamic_histogram(Iterator begin, Iterator end) { + using histogram_type = histogram, + dynamic_axes>>; + auto axes = typename histogram_type::axes_type(begin, end); + return histogram_type(std::move(axes)); +} + +template > +histogram< + mp11::mp_rename, + dynamic_axes>, + Storage> +make_dynamic_histogram_with(Storage&& s, Iterator begin, Iterator end) { + using histogram_type = histogram< + mp11::mp_rename, + dynamic_axes>, + Storage>; + auto axes = typename histogram_type::axes_type(begin, end); + return histogram_type(std::move(axes), std::move(s)); +} + +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/histogram_fwd.hpp b/include/boost/histogram/histogram_fwd.hpp index fb53320b..c9971dfa 100644 --- a/include/boost/histogram/histogram_fwd.hpp +++ b/include/boost/histogram/histogram_fwd.hpp @@ -54,12 +54,20 @@ class adaptive_storage; template > class array_storage; +namespace { template -using dynamic_axes = std::vector>; +using rebind = + typename std::allocator_traits>::allocator_type>::template rebind_alloc>; +} + +template +using dynamic_axes = std::vector, rebind>; template using static_axes = std::tuple; -template +template , + class Storage = adaptive_storage<>> class histogram; } // namespace histogram diff --git a/include/boost/histogram/iterator.hpp b/include/boost/histogram/iterator.hpp index 1f0794f3..383dc6dc 100644 --- a/include/boost/histogram/iterator.hpp +++ b/include/boost/histogram/iterator.hpp @@ -34,8 +34,9 @@ public: unsigned dim() const noexcept { return histogram_.dim(); } int idx(unsigned dim = 0) const noexcept { - histogram_.index_cache_(idx_); - return histogram_.index_cache_[dim]; + // histogram_.index_cache_(idx_); + // return histogram_.index_cache_[dim]; + return dim; } auto bin() const diff --git a/include/boost/histogram/ostream_operators.hpp b/include/boost/histogram/ostream_operators.hpp index 7a2f6de7..bb998262 100644 --- a/include/boost/histogram/ostream_operators.hpp +++ b/include/boost/histogram/ostream_operators.hpp @@ -8,6 +8,7 @@ #define _BOOST_HISTOGRAM_OSTREAM_OPERATORS_HPP_ #include +#include #include #include @@ -25,8 +26,8 @@ struct axis_ostream_visitor { }; } // namespace detail -template -std::ostream& operator<<(std::ostream& os, const histogram& h) { +template +std::ostream& operator<<(std::ostream& os, const histogram& h) { os << "histogram("; h.for_each_axis(detail::axis_ostream_visitor(os)); os << (h.dim() ? "\n)" : ")"); diff --git a/include/boost/histogram/serialization.hpp b/include/boost/histogram/serialization.hpp index fb404c5a..f215caa6 100644 --- a/include/boost/histogram/serialization.hpp +++ b/include/boost/histogram/serialization.hpp @@ -8,10 +8,12 @@ #define BOOST_HISTOGRAM_SERIALIZATION_HPP_ #include +#include +#include +#include #include #include -#include -#include +#include #include #include #include @@ -26,16 +28,6 @@ */ namespace boost { -namespace container { -template -void serialize(Archive& ar, string& s, unsigned /* version */) { - auto size = s.size(); - ar& size; - if (Archive::is_loading::value) { s.resize(size); } - ar& serialization::make_array(s.data(), size); -} -} - namespace histogram { namespace detail { @@ -50,14 +42,14 @@ struct serialize_t { }; struct serializer { - template - void operator()(T*, Buffer& b, Alloc& a, Archive& ar) { - if (Archive::is_loading::value) { create(type_tag(), b, a); } + template + void operator()(T*, Buffer& b, Archive& ar) { + if (Archive::is_loading::value) { create(type_tag(), b); } ar& boost::serialization::make_array(reinterpret_cast(b.ptr), b.size); } - template - void operator()(void*, Buffer& b, Alloc&, Archive&) { + template + void operator()(void*, Buffer& b, Archive&) { if (Archive::is_loading::value) { b.ptr = nullptr; } } }; @@ -72,20 +64,21 @@ void weight_counter::serialize(Archive& ar, ar& w2; } -template -void serialize(Archive& ar, array_storage& store, unsigned /* version */) { +template +void serialize(Archive& ar, array_storage& store, + unsigned /* version */) { ar& store.array_; } -template +template template -void adaptive_storage::serialize(Archive& ar, unsigned /* version */) { +void adaptive_storage::serialize(Archive& ar, unsigned /* version */) { if (Archive::is_loading::value) { - detail::apply(detail::destroyer(), buffer_, alloc_); + detail::apply(detail::destroyer(), buffer_); } ar& buffer_.type; ar& buffer_.size; - detail::apply(detail::serializer(), buffer_, alloc_, ar); + detail::apply(detail::serializer(), buffer_, ar); } namespace axis { @@ -94,7 +87,16 @@ template void base::serialize(Archive& ar, unsigned /* version */) { ar& size_; ar& shape_; - ar& label_; +} + +template +template +void labeled_base::serialize(Archive& ar, unsigned /* version */) { + ar& boost::serialization::base_object(*this); + auto size = label_.size(); + ar& size; + if (Archive::is_loading::value) { label_.resize(size); } + ar& serialization::make_array(label_.data(), size); } namespace transform { @@ -104,45 +106,42 @@ void pow::serialize(Archive& ar, unsigned /* version */) { } } // namespace transform -template +template template -void regular::serialize(Archive& ar, - unsigned /* version */) { - ar& boost::serialization::base_object(*this); - ar& boost::serialization::base_object(*this); +void regular::serialize(Archive& ar, unsigned /* version */) { + ar& boost::serialization::base_object>(*this); + ar& boost::serialization::base_object(*this); ar& min_; ar& delta_; } -template +template template -void circular::serialize(Archive& ar, unsigned /* version */) { - ar& boost::serialization::base_object(*this); +void circular::serialize(Archive& ar, unsigned /* version */) { + ar& boost::serialization::base_object>(*this); ar& phase_; ar& perimeter_; } -template +template template -void variable::serialize(Archive& ar, unsigned /* version */) { - ar& boost::serialization::base_object(*this); - if (Archive::is_loading::value) { - x_.reset(new RealType[base::size() + 1]); - } +void variable::serialize(Archive& ar, unsigned /* version */) { + ar& boost::serialization::base_object>(*this); + if (Archive::is_loading::value) { x_.reset(new T[base::size() + 1]); } ar& boost::serialization::make_array(x_.get(), base::size() + 1); } -template +template template -void integer::serialize(Archive& ar, unsigned /* version */) { - ar& boost::serialization::base_object(*this); +void integer::serialize(Archive& ar, unsigned /* version */) { + ar& boost::serialization::base_object>(*this); ar& min_; } -template +template template -void category::serialize(Archive& ar, unsigned /* version */) { - ar& boost::serialization::base_object(*this); +void category::serialize(Archive& ar, unsigned /* version */) { + ar& boost::serialization::base_object>(*this); ar& map_; } @@ -154,20 +153,23 @@ void any::serialize(Archive& ar, unsigned /* version */) { } // namespace axis -template -template -void histogram::serialize(Archive& ar, - unsigned /* version */) { +namespace { +template +void serialize_axes(Archive& ar, static_axes& axes) { detail::serialize_t sh(ar); - mp11::tuple_for_each(axes_, sh); - ar& storage_; + mp11::tuple_for_each(axes, sh); +} + +template +void serialize_axes(Archive& ar, dynamic_axes& axes) { + ar& axes; +} } template template -void histogram::serialize(Archive& ar, - unsigned /* version */) { - ar& axes_; +void histogram::serialize(Archive& ar, unsigned /* version */) { + serialize_axes(ar, axes_); ar& storage_; } diff --git a/include/boost/histogram/static_histogram.hpp b/include/boost/histogram/static_histogram.hpp index 9bd9c91e..5a851f31 100644 --- a/include/boost/histogram/static_histogram.hpp +++ b/include/boost/histogram/static_histogram.hpp @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include @@ -35,16 +33,16 @@ namespace boost { namespace histogram { template -class histogram { +class histogram { using axes_size = mp11::mp_size; static_assert(axes_size::value > 0, "at least one axis required"); public: using axes_type = mp11::mp_rename; - using element_type = typename Storage::element_type; - using const_reference = typename Storage::const_reference; + using storage_type = Storage; + using element_type = typename storage_type::element_type; + using const_reference = typename storage_type::const_reference; using const_iterator = iterator_over; - using iterator = const_iterator; histogram() = default; histogram(const histogram& rhs) = default; @@ -52,82 +50,34 @@ public: histogram& operator=(const histogram& rhs) = default; histogram& operator=(histogram&& rhs) = default; - template > - explicit histogram(Axis0&& axis0, Axis&&... axis) - : axes_(std::forward(axis0), std::forward(axis)...) { - storage_ = Storage(size_from_axes()); - index_cache_.reset(*this); - } - - explicit histogram(axes_type&& axes) : axes_(std::move(axes)) { - storage_ = Storage(size_from_axes()); - index_cache_.reset(*this); - } - - template - explicit histogram(const static_histogram& rhs) - : axes_(rhs.axes_), storage_(rhs.storage_) { - index_cache_.reset(*this); - } - - template - histogram& operator=(const static_histogram& rhs) { - if (static_cast(this) != static_cast(&rhs)) { - axes_ = rhs.axes_; - storage_ = rhs.storage_; - index_cache_.reset(*this); - } - return *this; - } - - template - explicit histogram(const dynamic_histogram& rhs) - : storage_(rhs.storage_) { + template + explicit histogram(const histogram& rhs) : storage_(rhs.storage_) { detail::axes_assign(axes_, rhs.axes_); - index_cache_.reset(*this); } - template - histogram& operator=(const dynamic_histogram& rhs) { - if (static_cast(this) != static_cast(&rhs)) { - detail::axes_assign(axes_, rhs.axes_); - storage_ = rhs.storage_; - index_cache_.reset(*this); - } + template + histogram& operator=(const histogram& rhs) { + storage_ = rhs.storage_; + detail::axes_assign(axes_, rhs.axes_); return *this; } - template - bool operator==(const static_histogram&) const noexcept { - return false; - } + template + histogram(T&& axes, S&& storage) + : axes_(std::forward(axes)), storage_(std::forward(storage)) {} - template - bool operator==(const static_histogram& rhs) const noexcept { + template + bool operator==(const histogram& rhs) const noexcept { return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_; } - template - bool operator==(const dynamic_histogram& rhs) const noexcept { - return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_; - } - - template - bool operator!=(const histogram& rhs) const noexcept { + template + bool operator!=(const histogram& rhs) const noexcept { return !operator==(rhs); } - template - histogram& operator+=(const static_histogram& rhs) { - if (!detail::axes_equal(axes_, rhs.axes_)) - throw std::invalid_argument("axes of histograms differ"); - storage_ += rhs.storage_; - return *this; - } - - template - histogram& operator+=(const dynamic_histogram& rhs) { + template + histogram& operator+=(const histogram& rhs) { if (!detail::axes_equal(axes_, rhs.axes_)) throw std::invalid_argument("axes of histograms differ"); storage_ += rhs.storage_; @@ -208,7 +158,7 @@ public: std::size_t size() const noexcept { return storage_.size(); } /// Reset bin counters to zero - void reset() { storage_ = Storage(size_from_axes()); } + void reset() { storage_ = storage_type(storage_.size(), storage_.alloc()); } /// Get N-th axis (const version) template @@ -267,7 +217,6 @@ public: private: axes_type axes_; Storage storage_; - mutable detail::index_cache index_cache_; std::size_t size_from_axes() const noexcept { detail::field_counter v; diff --git a/include/boost/histogram/storage/adaptive_storage.hpp b/include/boost/histogram/storage/adaptive_storage.hpp index cde3ac91..bf28b212 100644 --- a/include/boost/histogram/storage/adaptive_storage.hpp +++ b/include/boost/histogram/storage/adaptive_storage.hpp @@ -135,11 +135,11 @@ typename std::result_of::type apply(F&& f, A&& a, return f(a.ptr, std::forward(a), std::forward(ts)...); } -template -void create(type_tag, Buffer& b, Alloc& a, const U* init = nullptr) { - using alloc_type = - typename std::allocator_traits::template rebind_alloc; - alloc_type alloc(a); // rebind allocator +template +void create(type_tag, Buffer& b, const U* init = nullptr) { + using alloc_type = typename std::allocator_traits< + typename Buffer::allocator_type>::template rebind_alloc; + alloc_type alloc(b.alloc); // rebind allocator T* p = std::allocator_traits::allocate(alloc, b.size); if (init) { for (std::size_t i = 0; i < b.size; ++i) @@ -152,8 +152,8 @@ void create(type_tag, Buffer& b, Alloc& a, const U* init = nullptr) { b.ptr = p; } -template -void create(type_tag, Buffer& b, Alloc&, const U* init = nullptr) { +template +void create(type_tag, Buffer& b, const U* init = nullptr) { boost::ignore_unused(init); BOOST_ASSERT(!init); b.ptr = nullptr; @@ -161,65 +161,66 @@ void create(type_tag, Buffer& b, Alloc&, const U* init = nullptr) { } struct destroyer { - template - void operator()(T* tp, Buffer& b, Alloc& a) { - using alloc_type = - typename std::allocator_traits::template rebind_alloc; - alloc_type alloc(a); // rebind allocator + template + void operator()(T* tp, Buffer& b) { + using alloc_type = typename std::allocator_traits< + typename Buffer::allocator_type>::template rebind_alloc; + alloc_type alloc(b.alloc); // rebind allocator for (std::size_t i = 0; i < b.size; ++i) std::allocator_traits::destroy(alloc, tp + i); std::allocator_traits::deallocate(alloc, tp, b.size); } - template - void operator()(void*, Buffer&, Alloc&) {} + template + void operator()(void*, Buffer&) {} }; struct replacer { - template - void operator()(T* optr, const OBuffer& ob, Buffer& b, Alloc& a) { + template + void operator()(T* optr, const OBuffer& ob, Buffer& b) { if (b.size == ob.size && b.type == ob.type) { std::copy(optr, optr + ob.size, reinterpret_cast(b.ptr)); } else { - apply(destroyer(), b, a); + apply(destroyer(), b); + b.alloc = ob.alloc; b.size = ob.size; - create(type_tag(), b, a, optr); + create(type_tag(), b, optr); } } - template - void operator()(void*, const OBuffer& ob, Buffer& b, Alloc& a) { - apply(destroyer(), b, a); + template + void operator()(void*, const OBuffer& ob, Buffer& b) { + apply(destroyer(), b); b.type = 0; b.size = ob.size; } }; struct increaser { - template - void operator()(T* tp, Buffer& b, Alloc& a, std::size_t i) { + template + void operator()(T* tp, Buffer& b, std::size_t i) { if (!safe_increase(tp[i])) { using U = next_type; - create(type_tag(), b, a, tp); - destroyer()(tp, b, a); + create(type_tag(), b, tp); + destroyer()(tp, b); ++reinterpret_cast(b.ptr)[i]; } } - template - void operator()(void*, Buffer& b, Alloc& a, std::size_t i) { + template + void operator()(void*, Buffer& b, std::size_t i) { using U = next_type; - create(type_tag(), b, a); + create(type_tag(), b); ++reinterpret_cast(b.ptr)[i]; } - template - void operator()(mp_int* tp, Buffer&, Alloc&, std::size_t i) { + template + void operator()(mp_int* tp, Buffer&, std::size_t i) { ++tp[i]; } - template - void operator()(wcount* tp, Buffer&, Alloc&, std::size_t i) { + template + void operator()(wcount* tp, Buffer&, std::size_t i) { ++tp[i]; } }; @@ -232,79 +233,75 @@ struct adder { template using is_integral = typename std::is_integral::type; - template - void if_integral(std::true_type, T* tp, Buffer& b, Alloc& a, std::size_t i, + template + void if_integral(std::true_type, T* tp, Buffer& b, std::size_t i, const U& x) { if (!safe_radd(tp[i], x)) { using V = next_type; - create(type_tag(), b, a, tp); - destroyer()(tp, b, a); - operator()(reinterpret_cast(b.ptr), b, a, i, x); + create(type_tag(), b, tp); + destroyer()(tp, b); + operator()(reinterpret_cast(b.ptr), b, i, x); } } - template - void if_integral(std::false_type, T* tp, Buffer& b, Alloc& a, std::size_t i, + template + void if_integral(std::false_type, T* tp, Buffer& b, std::size_t i, const U& x) { - create(type_tag(), b, a, tp); - destroyer()(tp, b, a); - operator()(reinterpret_cast(b.ptr), b, a, i, x); + create(type_tag(), b, tp); + destroyer()(tp, b); + operator()(reinterpret_cast(b.ptr), b, i, x); } - template - void operator()(T* tp, Buffer& b, Alloc& a, std::size_t i, const U& x) { - if_integral(is_integral(), tp, b, a, i, x); + template + void operator()(T* tp, Buffer& b, std::size_t i, const U& x) { + if_integral(is_integral(), tp, b, i, x); } - template - void operator()(void*, Buffer& b, Alloc& a, std::size_t i, const U& x) { + template + void operator()(void*, Buffer& b, std::size_t i, const U& x) { using V = next_type; - create(type_tag(), b, a); - operator()(reinterpret_cast(b.ptr), b, a, i, x); + create(type_tag(), b); + operator()(reinterpret_cast(b.ptr), b, i, x); } - template - void if_convertible_to_mp_int(std::true_type, mp_int* tp, Buffer&, Alloc&, + template + void if_convertible_to_mp_int(std::true_type, mp_int* tp, Buffer&, std::size_t i, const U& x) { tp[i] += static_cast(x); } - template + template void if_convertible_to_mp_int(std::false_type, mp_int* tp, Buffer& b, - Alloc& a, std::size_t i, const U& x) { - create(type_tag(), b, a, tp); - destroyer()(tp, b, a); - operator()(reinterpret_cast(b.ptr), b, a, i, x); + std::size_t i, const U& x) { + create(type_tag(), b, tp); + destroyer()(tp, b); + operator()(reinterpret_cast(b.ptr), b, i, x); } - template - void operator()(mp_int* tp, Buffer& b, Alloc& a, std::size_t i, - const U& x) { - if_convertible_to_mp_int(is_convertible_to_mp_int(), tp, b, a, i, x); + template + void operator()(mp_int* tp, Buffer& b, std::size_t i, const U& x) { + if_convertible_to_mp_int(is_convertible_to_mp_int(), tp, b, i, x); } - template - void operator()(wcount* tp, Buffer&, Alloc&, std::size_t i, const U& x) { + template + void operator()(wcount* tp, Buffer&, std::size_t i, const U& x) { tp[i] += x; } - template - void operator()(wcount* tp, Buffer&, Alloc&, std::size_t i, - const mp_int& x) { + template + void operator()(wcount* tp, Buffer&, std::size_t i, const mp_int& x) { tp[i] += static_cast(x); } }; struct buffer_adder { - template - void operator()(T* tp, const OBuffer&, Buffer& b, Alloc& a) { - for (std::size_t i = 0; i < b.size; ++i) { - apply(adder(), b, a, i, tp[i]); - } + template + void operator()(T* tp, const OBuffer&, Buffer& b) { + for (std::size_t i = 0; i < b.size; ++i) { apply(adder(), b, i, tp[i]); } } - template - void operator()(void*, const OBuffer&, Buffer&, Alloc&) {} + template + void operator()(void*, const OBuffer&, Buffer&) {} }; struct getter { @@ -352,128 +349,114 @@ struct comparer { }; struct multiplier { - template - void operator()(T* tp, Buffer& b, Alloc& a, const double x) { - create(type_tag(), b, a, tp); - operator()(reinterpret_cast(b.ptr), b, a, x); + template + void operator()(T* tp, Buffer& b, const double x) { + create(type_tag(), b, tp); + operator()(reinterpret_cast(b.ptr), b, x); } - template - void operator()(void*, Buffer&, Alloc&, const double) {} + template + void operator()(void*, Buffer&, const double) {} - template - void operator()(wcount* tp, Buffer& b, Alloc&, const double x) { + template + void operator()(wcount* tp, Buffer& b, const double x) { for (std::size_t i = 0; i < b.size; ++i) tp[i] *= x; } }; } // namespace detail -template +template class adaptive_storage { - struct buffer_type { - char type; - std::size_t size; - void* ptr; - buffer_type(std::size_t s = 0) : type(0), size(s), ptr(nullptr) {} - }; - public: + using allocator_type = Allocator; using element_type = weight_counter; using const_reference = element_type; - adaptive_storage() = default; +private: + struct buffer_type { + using allocator_type = Allocator; + allocator_type alloc; + char type; + std::size_t size; + void* ptr; + buffer_type(std::size_t s = 0, const allocator_type& a = allocator_type()) + : alloc(a), type(0), size(s), ptr(nullptr) {} + }; - explicit adaptive_storage(const Alloc& a) : alloc_(a) {} +public: + ~adaptive_storage() { detail::apply(detail::destroyer(), buffer_); } - adaptive_storage(const adaptive_storage& o) : alloc_(o.alloc_) { - detail::apply(detail::replacer(), o.buffer_, buffer_, alloc_); + adaptive_storage(const adaptive_storage& o) { + detail::apply(detail::replacer(), o.buffer_, buffer_); } adaptive_storage& operator=(const adaptive_storage& o) { - if (this != &o) { - alloc_ = o.alloc_; - detail::apply(detail::replacer(), o.buffer_, buffer_, alloc_); - } + if (this != &o) { detail::apply(detail::replacer(), o.buffer_, buffer_); } return *this; } - adaptive_storage(adaptive_storage&& o) - : alloc_(std::move(o.alloc_)), buffer_(std::move(o.buffer_)) { + adaptive_storage(adaptive_storage&& o) : buffer_(std::move(o.buffer_)) { o.buffer_.type = 0; o.buffer_.size = 0; o.buffer_.ptr = nullptr; } adaptive_storage& operator=(adaptive_storage&& o) { - if (this != &o) { - std::swap(alloc_, o.alloc_); - std::swap(buffer_, o.buffer_); - } + if (this != &o) { std::swap(buffer_, o.buffer_); } return *this; } - ~adaptive_storage() { detail::apply(detail::destroyer(), buffer_, alloc_); } - - template - explicit adaptive_storage(const S& s) : buffer_(s.size()) { - create(detail::type_tag(), buffer_, alloc_); + template > + explicit adaptive_storage(const S& s) + : buffer_(s.size(), s.get_allocator()) { + create(detail::type_tag(), buffer_); for (std::size_t i = 0; i < size(); ++i) { reinterpret_cast(buffer_.ptr)[i] = s[i]; } } - template - explicit adaptive_storage(const S& s, const Alloc& a) - : alloc_(a), buffer_(s.size()) { - create(detail::type_tag(), buffer_, alloc_); - for (std::size_t i = 0; i < size(); ++i) { - reinterpret_cast(buffer_.ptr)[i] = s[i]; - } - } - - template + template > adaptive_storage& operator=(const S& s) { // no check for self-assign needed, since S is different type - detail::apply(detail::destroyer(), buffer_, alloc_); + detail::apply(detail::destroyer(), buffer_); + buffer_.alloc = s.get_allocator(); buffer_.size = s.size(); - create(detail::type_tag(), buffer_, alloc_); + create(detail::type_tag(), buffer_); for (std::size_t i = 0; i < size(); ++i) { add(i, s[i]); } return *this; } - explicit adaptive_storage(std::size_t s) : buffer_(s) { - detail::create(detail::type_tag(), buffer_, alloc_); + explicit adaptive_storage(const allocator_type& a = allocator_type()) + : buffer_(0, a) { + detail::create(detail::type_tag(), buffer_); } - explicit adaptive_storage(std::size_t s, const Alloc& a) - : alloc_(a), buffer_(s) { - detail::create(detail::type_tag(), buffer_, alloc_); - } + allocator_type get_allocator() const { return buffer_.alloc; } - // used by unit tests, not part of generic storage interface - template - adaptive_storage(std::size_t s, const T* p) : buffer_(s) { - detail::create(detail::type_tag(), buffer_, alloc_, p); + void reset(std::size_t s) { + detail::apply(detail::destroyer(), buffer_); + buffer_.size = s; + create(detail::type_tag(), buffer_); } std::size_t size() const { return buffer_.size; } void increase(std::size_t i) { BOOST_ASSERT(i < size()); - detail::apply(detail::increaser(), buffer_, alloc_, i); + detail::apply(detail::increaser(), buffer_, i); } template void add(std::size_t i, const T& x) { BOOST_ASSERT(i < size()); - detail::apply(detail::adder(), buffer_, alloc_, i, x); + detail::apply(detail::adder(), buffer_, i, x); } template - void add(std::size_t i, const detail::weight& x) { + void add(std::size_t i, const detail::weight_type& x) { BOOST_ASSERT(i < size()); - detail::apply(detail::adder(), buffer_, alloc_, i, x); + detail::apply(detail::adder(), buffer_, i, static_cast(x.value)); } const_reference operator[](std::size_t i) const { @@ -490,16 +473,16 @@ public: BOOST_ASSERT(o.size() == size()); if (this == &o) { /* - Self-adding needs to be special-cased, because the source buffer ptr - may be invalided by growth. We avoid this by making a copy of the - source. This is a simple, but expensive solution. This is ok, because - self-adding is mostly used in the unit-tests to grow a histogram - quickly. It does not occur frequently in real applications. + Self-adding is a special-case, because the source buffer ptr may be + invalided by growth. We avoid this by making a copy of the source. + This is the simplest solution, but expensive. The cost is ok, because + self-adding is only used by the unit-tests. It does not occur + frequently in real applications. */ - const auto o_copy = o; - detail::apply(detail::buffer_adder(), o_copy.buffer_, buffer_, alloc_); + const auto copy = o; + detail::apply(detail::buffer_adder(), copy.buffer_, buffer_); } else { - detail::apply(detail::buffer_adder(), o.buffer_, buffer_, alloc_); + detail::apply(detail::buffer_adder(), o.buffer_, buffer_); } return *this; } @@ -513,14 +496,23 @@ public: } adaptive_storage& operator*=(const double x) { - detail::apply(detail::multiplier(), buffer_, alloc_, x); + detail::apply(detail::multiplier(), buffer_, x); return *this; } + // used by unit tests, not part of generic storage interface + template + adaptive_storage(std::size_t s, const T* p, + const allocator_type& a = allocator_type()) + : buffer_(s, a) { + detail::create(detail::type_tag(), buffer_, p); + } + private: - Alloc alloc_; buffer_type buffer_; + template + friend class adaptive_storage; friend class python_access; friend class ::boost::serialization::access; template diff --git a/include/boost/histogram/storage/array_storage.hpp b/include/boost/histogram/storage/array_storage.hpp index f2ed7555..ac5821d0 100644 --- a/include/boost/histogram/storage/array_storage.hpp +++ b/include/boost/histogram/storage/array_storage.hpp @@ -60,17 +60,17 @@ public: return *this; } - array_storage() : array_storage(0) {} + explicit array_storage(const allocator_type& a = allocator_type()) + : array_(a) {} - array_storage(const allocator_type& a) : array_storage(0, a) {} + allocator_type get_allocator() const { return array_.get_allocator(); } - array_storage(std::size_t s) : array_storage(s, allocator_type()) {} - - array_storage(std::size_t s, const allocator_type& a) - : array_(s, element_type(0), a) {} - - allocator_type get_allocator() const noexcept { - return array_.get_allocator(); + void reset(std::size_t s) { + if (s == size()) { + std::fill(array_.begin(), array_.end(), element_type(0)); + } else { + array_ = array_type(s, element_type(0), array_.get_allocator()); + } } std::size_t size() const noexcept { return array_.size(); } diff --git a/include/boost/histogram/storage/weight_counter.hpp b/include/boost/histogram/storage/weight_counter.hpp index 37d0bb77..7fd3bab6 100644 --- a/include/boost/histogram/storage/weight_counter.hpp +++ b/include/boost/histogram/storage/weight_counter.hpp @@ -57,7 +57,7 @@ public: } template - weight_counter& operator+=(const detail::weight& rhs) { + weight_counter& operator+=(const detail::weight_type& rhs) { const auto x = static_cast(rhs.value); w += x; w2 += x * x; diff --git a/include/boost/histogram/weight.hpp b/include/boost/histogram/weight.hpp index fbc4f077..6efa10f0 100644 --- a/include/boost/histogram/weight.hpp +++ b/include/boost/histogram/weight.hpp @@ -11,23 +11,23 @@ namespace boost { namespace histogram { namespace detail { template -struct weight { +struct weight_type { T value; }; template -struct sample { +struct sample_type { T value; }; } // namespace detail template -detail::weight weight(T&& t) { +detail::weight_type weight(T&& t) { return {t}; } template -detail::sample sample(T&& t) { +detail::sample_type sample(T&& t) { return {t}; } } diff --git a/src/python/axis.cpp b/src/python/axis.cpp index 5d76aa30..140958c9 100644 --- a/src/python/axis.cpp +++ b/src/python/axis.cpp @@ -84,7 +84,7 @@ bp::object variable_init(bp::tuple args, bp::dict kwargs) { } boost::string_view label; - auto uo = bha::uoflow::on; + auto uo = bha::uoflow_type::on; while (bp::len(kwargs) > 0) { bp::tuple kv = kwargs.popitem(); const char* key_cstr = bp::extract(kv[0]); @@ -93,7 +93,7 @@ bp::object variable_init(bp::tuple args, bp::dict kwargs) { if (k == "label") label = boost::string_view(bp::extract(v), bp::len(v)); else if (k == "uoflow") { - if (!bp::extract(v)) uo = bha::uoflow::off; + if (!bp::extract(v)) uo = bha::uoflow_type::off; } else { std::stringstream s; s << "keyword " << k << " not recognized"; @@ -227,22 +227,22 @@ struct axis_suite : public bp::def_visitor> { }; template -bha::regular* regular_init(unsigned bin, double lower, - double upper, bp::str pylabel, - bool with_uoflow) { - const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off; - return new bha::regular( +bha::regular* regular_init(unsigned bin, double lower, + double upper, bp::str pylabel, + bool with_uoflow) { + const auto uo = with_uoflow ? bha::uoflow_type::on : bha::uoflow_type::off; + return new bha::regular( bin, lower, upper, {bp::extract(pylabel)(), static_cast(bp::len(pylabel))}, uo); } -bha::regular* regular_pow_init( +bha::regular* regular_pow_init( unsigned bin, double lower, double upper, double power, bp::str pylabel, bool with_uoflow) { using namespace ::boost::python; - const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off; - return new bha::regular( + const auto uo = with_uoflow ? bha::uoflow_type::on : bha::uoflow_type::off; + return new bha::regular( bin, lower, upper, {extract(pylabel)(), static_cast(bp::len(pylabel))}, uo, power); @@ -251,7 +251,7 @@ bha::regular* regular_pow_init( bha::integer<>* integer_init(int lower, int upper, bp::str pylabel, bool with_uoflow) { using namespace ::boost::python; - const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off; + const auto uo = with_uoflow ? bha::uoflow_type::on : bha::uoflow_type::off; return new bha::integer<>(lower, upper, {extract(pylabel)(), static_cast(bp::len(pylabel))}, @@ -281,7 +281,7 @@ void register_axis_types() { .def(axis_suite>()); #define BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(x) \ - class_>( \ + class_>( \ "regular_" #x, \ "Axis for real-valued data and bins of equal width in " #x \ "-space." \ @@ -292,13 +292,13 @@ void register_axis_types() { default_call_policies(), \ (arg("bin"), arg("lower"), arg("upper"), \ arg("label") = "", arg("uoflow") = true))) \ - .def(axis_suite>()) + .def(axis_suite>()) BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(log); BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(sqrt); // BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(cos); - class_>( + class_>( "regular_pow", "Axis for real-valued data and bins of equal width in power-space." "\nBinning is a O(1) operation.", @@ -308,7 +308,7 @@ void register_axis_types() { regular_pow_init, default_call_policies(), (arg("bin"), arg("lower"), arg("upper"), arg("power"), arg("label") = "", arg("uoflow") = true))) - .def(axis_suite>()); + .def(axis_suite>()); class_>( "circular", @@ -319,7 +319,7 @@ void register_axis_types() { no_init) .def(init( (arg("self"), arg("bin"), arg("phase") = 0.0, - arg("perimeter") = bh::detail::two_pi, arg("label") = ""))) + arg("perimeter") = bha::circular<>::two_pi, arg("label") = ""))) .def(axis_suite>()); class_>( diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index 1f71eaf0..4a36b6cb 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -5,10 +5,11 @@ // or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include #include #include #include +#include #include #include #include @@ -23,14 +24,20 @@ namespace np = boost::python::numpy; #include #ifndef BOOST_HISTOGRAM_AXIS_LIMIT -#define BOOST_HISTOGRAM_AXIS_LIMIT 32 +#define BOOST_HISTOGRAM_AXIS_LIMIT 16 #endif -namespace mpl = boost::mpl; namespace bh = boost::histogram; namespace bp = boost::python; +namespace mp11 = boost::mp11; -using pyhistogram = bh::dynamic_histogram<>; +class pyhistogram : public bh::histogram<> { + using base_type = bh::histogram<>; + +public: + using base_type::base_type; + using iterator = bh::histogram<>::const_iterator; +}; #ifdef HAVE_NUMPY namespace boost { @@ -161,7 +168,7 @@ bp::object histogram_init(bp::tuple args, bp::dict kwargs) { for (unsigned i = 0; i < dim; ++i) { bp::object pa = args[i + 1]; bool success = false; - boost::mp11::mp_for_each( + boost::mp11::mp_for_each( axes_appender(pa, axes, success)); if (!success) { std::string msg = "require an axis object, got "; @@ -170,7 +177,7 @@ bp::object histogram_init(bp::tuple args, bp::dict kwargs) { bp::throw_error_already_set(); } } - pyhistogram h(axes.begin(), axes.end()); + pyhistogram h(axes, typename pyhistogram::storage_type()); return self.attr("__init__")(std::move(h)); } diff --git a/test/adaptive_storage_test.cpp b/test/adaptive_storage_test.cpp index f9d798a2..a8d158c0 100644 --- a/test/adaptive_storage_test.cpp +++ b/test/adaptive_storage_test.cpp @@ -4,10 +4,10 @@ // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) -#include -#include #include #ifndef BOOST_HISTOGRAM_NO_SERIALIZATION +#include +#include #include #endif #include @@ -116,7 +116,7 @@ void serialization_impl() { template <> void serialization_impl() { - adaptive_storage_type a(std::size_t(1)); + const auto a = prepare(1); std::ostringstream os; std::string buf; { @@ -138,7 +138,7 @@ void serialization_impl() { template void equal_impl() { - adaptive_storage_type a(std::size_t(1)); + auto a = prepare(1); auto b = prepare(1, T(0)); BOOST_TEST_EQ(a[0].value(), 0.0); BOOST_TEST_EQ(a[0].variance(), 0.0); @@ -146,7 +146,8 @@ void equal_impl() { b.increase(0); BOOST_TEST(!(a == b)); - array_storage c(std::size_t(1)); + array_storage c; + c.reset(1); auto d = prepare(1, T(0)); BOOST_TEST(c == d); c.increase(0); @@ -155,10 +156,10 @@ void equal_impl() { template <> void equal_impl() { - adaptive_storage_type a(std::size_t(1)); + auto a = prepare(1); auto b = prepare(1, 0); auto c = prepare(2, 0); - auto d = array_storage(std::size_t(1)); + auto d = prepare(1); BOOST_TEST_EQ(a[0].value(), 0.0); BOOST_TEST_EQ(a[0].variance(), 0.0); BOOST_TEST(a == b); @@ -184,7 +185,7 @@ void increase_and_grow_impl() { n.increase(0); - adaptive_storage_type x(std::size_t(2)); + auto x = prepare(2); x.increase(0); n2.add(0, x[0].value()); @@ -198,7 +199,7 @@ void increase_and_grow_impl() { template <> void increase_and_grow_impl() { - adaptive_storage_type s(std::size_t(2)); + auto s = prepare(2); BOOST_TEST_EQ(s[0].value(), 0); BOOST_TEST_EQ(s[1].value(), 0); s.increase(0); @@ -209,7 +210,8 @@ void increase_and_grow_impl() { template void convert_array_storage_impl() { const auto aref = prepare(1, T(0)); - array_storage s(std::size_t(1)); + array_storage s; + s.reset(1); s.increase(0); auto a = aref; @@ -231,7 +233,8 @@ void convert_array_storage_impl() { BOOST_TEST(c == s); BOOST_TEST(s == c); - array_storage t(std::size_t(1)); + array_storage t; + t.reset(1); t.increase(0); while (t[0] < 1e20) t.add(0, t[0]); auto d = aref; @@ -257,7 +260,8 @@ void convert_array_storage_impl() { BOOST_TEST(g == s); BOOST_TEST(s == g); - array_storage u(std::size_t(2)); + array_storage u; + u.reset(2); u.increase(0); auto h = aref; BOOST_TEST(!(h == u)); @@ -267,9 +271,10 @@ void convert_array_storage_impl() { template <> void convert_array_storage_impl() { - const auto aref = adaptive_storage_type(std::size_t(1)); + const auto aref = prepare(1); BOOST_TEST_EQ(aref[0].value(), 0.0); - array_storage s(std::size_t(1)); + array_storage s; + s.reset(1); s.increase(0); auto a = aref; @@ -285,7 +290,8 @@ void convert_array_storage_impl() { BOOST_TEST(c == s); BOOST_TEST(s == c); - array_storage t(std::size_t(2)); + array_storage t; + t.reset(2); t.increase(0); auto d = aref; BOOST_TEST(!(d == t)); @@ -401,12 +407,12 @@ int main() { // add_and_grow { - adaptive_storage_type a(std::size_t(1)); + auto a = prepare(1); a += a; BOOST_TEST_EQ(a[0].value(), 0); a.increase(0); double x = 1; - adaptive_storage_type b(std::size_t(1)); + auto b = prepare(1); b.increase(0); BOOST_TEST_EQ(b[0].value(), x); for (unsigned i = 0; i < 80; ++i) { @@ -417,14 +423,14 @@ int main() { BOOST_TEST_EQ(a[0].variance(), x); BOOST_TEST_EQ(b[0].value(), x); BOOST_TEST_EQ(b[0].variance(), x); - adaptive_storage_type c(std::size_t(1)); + auto c = prepare(1); c.add(0, a[0].value()); BOOST_TEST_EQ(c[0].value(), x); BOOST_TEST_EQ(c[0].variance(), x); c.add(0, weight(0)); BOOST_TEST_EQ(c[0].value(), x); BOOST_TEST_EQ(c[0].variance(), x); - adaptive_storage_type d(std::size_t(1)); + auto d = prepare(1); d.add(0, weight(a[0].value())); BOOST_TEST_EQ(d[0].value(), x); BOOST_TEST_EQ(d[0].variance(), x * x); @@ -433,7 +439,7 @@ int main() { // multiply { - adaptive_storage_type a(std::size_t(2)); + auto a = prepare(2); a *= 2; BOOST_TEST_EQ(a[0].value(), 0); BOOST_TEST_EQ(a[1].value(), 0); diff --git a/test/array_storage_test.cpp b/test/array_storage_test.cpp index 36ffb7fa..13b962fa 100644 --- a/test/array_storage_test.cpp +++ b/test/array_storage_test.cpp @@ -17,15 +17,20 @@ int main() { // ctor { - array_storage a(1); + array_storage a; + a.reset(1); BOOST_TEST_EQ(a.size(), 1u); BOOST_TEST_EQ(a[0], 0); } // increase { - array_storage a(1), b(1); - array_storage c(1), d(2); + array_storage a, b; + a.reset(1); + b.reset(1); + array_storage c, d; + c.reset(1); + d.reset(2); a.increase(0); b.increase(0); c.increase(0); @@ -46,7 +51,8 @@ int main() { // multiply { - array_storage a(2); + array_storage a; + a.reset(2); a.increase(0); a *= 3; BOOST_TEST_EQ(a[0], 3); @@ -61,9 +67,11 @@ int main() { // copy { - array_storage a(1); + array_storage a; + a.reset(1); a.increase(0); - decltype(a) b(2); + decltype(a) b; + b.reset(2); BOOST_TEST(!(a == b)); b = a; BOOST_TEST(a == b); @@ -75,7 +83,8 @@ int main() { BOOST_TEST_EQ(c.size(), 1); BOOST_TEST_EQ(c[0], 1); - array_storage d(1); + array_storage d; + d.reset(1); BOOST_TEST(!(a == d)); d = a; BOOST_TEST(a == d); @@ -85,7 +94,8 @@ int main() { // move { - array_storage a(1); + array_storage a; + a.reset(1); a.increase(0); decltype(a) b; BOOST_TEST(!(a == b)); @@ -101,7 +111,8 @@ int main() { // with weight_counter { - array_storage> a(1); + array_storage> a; + a.reset(1); a.increase(0); a.add(0, 1); a.add(0, weight_counter(1, 0)); diff --git a/test/axis_test.cpp b/test/axis_test.cpp index b409cf6d..cb984890 100644 --- a/test/axis_test.cpp +++ b/test/axis_test.cpp @@ -5,16 +5,17 @@ // or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include #include #include -#include #include #include #include #include #include +#include "utility.hpp" using namespace boost::histogram; @@ -422,5 +423,47 @@ int main() { BOOST_TEST(detail::axes_equal(tuple2, tuple1)); } + // sub_axes + { + using ra = axis::regular<>; + using ia = axis::integer<>; + using ca = axis::category<>; + using T = static_axes; + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, + static_axes>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, + static_axes>)); + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE( + (std::is_same, static_axes>)); + BOOST_TEST_TRAIT_TRUE((std::is_same, + static_axes>)); + } + + // make_sub_tuple + { + using ia = axis::integer<>; + using T = static_axes; + auto axes = T(ia(0, 1), ia(1, 2), ia(2, 3)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i1(), i2()), + (static_axes(ia(1, 2), ia(2, 3)))); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i1(), i0()), + (static_axes(ia(0, 1), ia(1, 2)))); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i1(), i1()), + (static_axes(ia(1, 2)))); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i0(), i1(), i2()), axes); + } + return boost::report_errors(); } diff --git a/test/detail_test.cpp b/test/detail_test.cpp index 711618cd..dfb90e69 100644 --- a/test/detail_test.cpp +++ b/test/detail_test.cpp @@ -5,56 +5,39 @@ // or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include -#include +#include #include -#include -#include -#include -#include #include #include -#include -#include -#include -#include #include "utility.hpp" -using namespace boost::histogram::detail; +namespace bhd = boost::histogram::detail; +namespace bhad = boost::histogram::axis::detail; int main() { // escape0 { std::ostringstream os; - escape(os, std::string("abc")); + bhad::escape_string(os, std::string("abc")); BOOST_TEST_EQ(os.str(), std::string("'abc'")); } // escape1 { std::ostringstream os; - escape(os, std::string("abc\n")); + bhad::escape_string(os, std::string("abc\n")); BOOST_TEST_EQ(os.str(), std::string("'abc\n'")); } // escape2 { std::ostringstream os; - escape(os, std::string("'abc'")); + bhad::escape_string(os, std::string("'abc'")); BOOST_TEST_EQ(os.str(), std::string("'\\\'abc\\\''")); } // cat - { BOOST_TEST_EQ(cat("foo", 1, "bar"), std::string("foo1bar")); } - - // bool mask - { - auto v1 = bool_mask(4, false); - BOOST_TEST_EQ(v1, std::vector({true, false, false, true})); - - auto v2 = bool_mask(4, true); - BOOST_TEST_EQ(v2, std::vector({false, true, false, true})); - } + { BOOST_TEST_EQ(bhd::cat("foo", 1, "bar"), std::string("foo1bar")); } return boost::report_errors(); } diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index 4926dcaf..c56a1a60 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #ifndef BOOST_HISTOGRAM_NO_SERIALIZATION @@ -15,7 +15,6 @@ #include #endif #include -#include #include #include #include @@ -32,16 +31,21 @@ using namespace boost::histogram; using namespace boost::histogram::literals; // to get _c suffix namespace mp11 = boost::mp11; +struct static_tag {}; +struct dynamic_tag {}; + template auto make_histogram(static_tag, Axes&&... axes) - -> decltype(make_static_histogram_with(std::forward(axes)...)) { - return make_static_histogram_with(std::forward(axes)...); + -> decltype(make_static_histogram_with(S(), + std::forward(axes)...)) { + return make_static_histogram_with(S(), std::forward(axes)...); } template auto make_histogram(dynamic_tag, Axes&&... axes) - -> decltype(make_dynamic_histogram_with(std::forward(axes)...)) { - return make_dynamic_histogram_with(std::forward(axes)...); + -> decltype(make_dynamic_histogram_with(S(), + std::forward(axes)...)) { + return make_dynamic_histogram_with(S(), std::forward(axes)...); } int expected_moved_from_dim(static_tag, int static_value) { @@ -56,8 +60,8 @@ typename Histogram::element_type sum(const Histogram& h) { typename Histogram::element_type(0)); } -template -void pass_histogram(boost::histogram::histogram&) {} +template +void pass_histogram(boost::histogram::histogram&) {} template void run_tests() { @@ -136,9 +140,8 @@ void run_tests() { h(0, 0); auto h2 = decltype(h)(h); BOOST_TEST(h2 == h); - auto h3 = - static_histogram, axis::integer<>>, - array_storage>(h); + auto h3 = histogram, axis::integer<>>, + array_storage>(h); BOOST_TEST_EQ(h3, h); } @@ -154,9 +157,8 @@ void run_tests() { // test self-assign h2 = h2; BOOST_TEST_EQ(h, h2); - auto h3 = - static_histogram, axis::integer<>>, - array_storage>(); + auto h3 = histogram, axis::integer<>>, + array_storage>(); h3 = h; BOOST_TEST_EQ(h, h3); } @@ -271,7 +273,7 @@ void run_tests() { // d1_2 { auto h = make_histogram>( - Type(), axis::integer<>(0, 2, "", axis::uoflow::off)); + Type(), axis::integer<>(0, 2, "", axis::uoflow_type::off)); h(0); h(-0); h(-1); @@ -332,7 +334,7 @@ void run_tests() { { auto h = make_histogram>( Type(), axis::regular<>(2, -1, 1), - axis::integer<>(-1, 2, "", axis::uoflow::off)); + axis::integer<>(-1, 2, "", axis::uoflow_type::off)); h(-1, -1); h(-1, 0); h(-1, -10); @@ -366,7 +368,7 @@ void run_tests() { { auto h = make_histogram>( Type(), axis::regular<>(2, -1, 1), - axis::integer<>(-1, 2, "", axis::uoflow::off)); + axis::integer<>(-1, 2, "", axis::uoflow_type::off)); h(-1, 0); // -> 0, 1 h(weight(10), -1, -1); // -> 0, 0 h(weight(5), -1, -10); // is ignored @@ -564,9 +566,9 @@ void run_tests() { auto a = make_histogram>( Type(), axis::regular<>(3, -1, 1, "r"), axis::circular<>(4, 0.0, 1.0, "p"), - axis::regular(3, 1, 100, "lr"), - axis::regular(3, 1, 100, "pr", - axis::uoflow::on, 0.5), + axis::regular(3, 1, 100, "lr"), + axis::regular(3, 1, 100, "pr", + axis::uoflow_type::on, 0.5), axis::variable<>({0.1, 0.2, 0.3, 0.4, 0.5}, "v"), axis::category<>{A, B, C}, axis::integer<>(0, 2, "i")); a(0.5, 0.2, 20, 20, 0.25, 1, 1); @@ -604,7 +606,7 @@ void run_tests() { // histogram_reset { auto h = make_histogram>( - Type(), axis::integer<>(0, 2, "", axis::uoflow::off)); + Type(), axis::integer<>(0, 2, "", axis::uoflow_type::off)); h(0); h(1); BOOST_TEST_EQ(h.at(0), 1); @@ -780,7 +782,7 @@ void run_tests() { { auto h = make_histogram>( Type(), axis::integer<>(0, 1), - axis::integer<>(2, 4, "", axis::uoflow::off)); + axis::integer<>(2, 4, "", axis::uoflow_type::off)); const auto& a0 = h.axis(0_c); const auto& a1 = h.axis(1_c); h(weight(2), 0, 2); @@ -973,7 +975,7 @@ int main() { BOOST_TEST_EQ(h.axis(1), v[1]); auto h2 = - make_dynamic_histogram_with>(v.begin(), v.end()); + make_dynamic_histogram_with(array_storage(), v.begin(), v.end()); BOOST_TEST_EQ(h.axis(0), v[0]); BOOST_TEST_EQ(h.axis(1), v[1]); } @@ -1001,14 +1003,18 @@ int main() { h1(1, 1); h1(1, 2); - auto h1_0 = h1.reduce_to(0); + std::vector x; + + x = {0}; + auto h1_0 = h1.reduce_to(x.begin(), x.end()); BOOST_TEST_EQ(h1_0.dim(), 1); BOOST_TEST_EQ(sum(h1_0), 5); BOOST_TEST_EQ(h1_0.at(0), 2); BOOST_TEST_EQ(h1_0.at(1), 3); BOOST_TEST(h1_0.axis() == h1.axis(0_c)); - auto h1_1 = h1.reduce_to(1); + x = {1}; + auto h1_1 = h1.reduce_to(x.begin(), x.end()); BOOST_TEST_EQ(h1_1.dim(), 1); BOOST_TEST_EQ(sum(h1_1), 5); BOOST_TEST_EQ(h1_1.at(0), 2); diff --git a/test/meta_test.cpp b/test/meta_test.cpp index a8f622de..1787948b 100644 --- a/test/meta_test.cpp +++ b/test/meta_test.cpp @@ -148,24 +148,6 @@ int main() { BOOST_TEST_TRAIT_TRUE((std::is_same)); } - // selection - { - using T = std::tuple; - BOOST_TEST_TRAIT_TRUE((std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE(( - std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - } - // unique_sorted { using input = mp11::mp_list_c; @@ -175,14 +157,5 @@ int main() { BOOST_TEST_TRAIT_TRUE((std::is_same)); } - // make_sub_tuple - { - std::tuple t(1, 2, 3); - auto result = make_sub_tuple(t); - auto expected = std::tuple(2, 3); - - BOOST_TEST_EQ(result, expected); - } - return boost::report_errors(); }