From e1fa2fa644282ccd2272f7b2dadbf5aec704cf9e Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Fri, 13 Jul 2018 23:21:04 +0200 Subject: [PATCH] work in progress --- include/boost/histogram/axis/any.hpp | 15 +++ include/boost/histogram/axis/axis.hpp | 14 +- .../boost/histogram/detail/axis_visitor.hpp | 1 + include/boost/histogram/detail/meta.hpp | 101 +++++++------- include/boost/histogram/dynamic_histogram.hpp | 127 ++++++++++-------- include/boost/histogram/literals.hpp | 4 +- include/boost/histogram/serialization.hpp | 2 +- include/boost/histogram/static_histogram.hpp | 98 +++++++------- test/detail_test.cpp | 116 ++++++++++------ 9 files changed, 271 insertions(+), 207 deletions(-) diff --git a/include/boost/histogram/axis/any.hpp b/include/boost/histogram/axis/any.hpp index e44dbee5..0c58ac23 100644 --- a/include/boost/histogram/axis/any.hpp +++ b/include/boost/histogram/axis/any.hpp @@ -96,6 +96,16 @@ struct lower : public static_visitor { } }; +struct bicmp : public static_visitor { + template bool operator()(const T& t, const U& u) const { + return false; + } + + template bool operator()(const T& t, const T& u) const { + return t == u; + } +}; + } // namespace detail /// Polymorphic axis type @@ -164,6 +174,11 @@ public: return base_type::operator==(static_cast(rhs)); } + template + bool operator==(const any& rhs) const { + return apply_visitor(detail::bicmp(), *this, rhs); + } + const_iterator begin() const { return const_iterator(*this, 0); } const_iterator end() const { return const_iterator(*this, size()); } const_reverse_iterator rbegin() const { diff --git a/include/boost/histogram/axis/axis.hpp b/include/boost/histogram/axis/axis.hpp index 27eb3ce1..60756bdd 100644 --- a/include/boost/histogram/axis/axis.hpp +++ b/include/boost/histogram/axis/axis.hpp @@ -40,9 +40,9 @@ namespace axis { enum class uoflow { off = false, on = true }; #ifdef BOOST_MSVC -# define BOOST_HISTOGRAM_ENUM_CLASS enum class +# define BOOST_HISTOGRAM_ENUM_CLASS_ARG enum class #else -# define BOOST_HISTOGRAM_ENUM_CLASS enum +# define BOOST_HISTOGRAM_ENUM_CLASS_ARG enum #endif /// Base class for all axes, uses CRTP to inject iterator logic. @@ -123,7 +123,7 @@ public: inline bool uoflow() const noexcept { return shape_ > base_type::size(); } protected: - axis_base_uoflow(unsigned n, string_view label, BOOST_HISTOGRAM_ENUM_CLASS uoflow uo) + axis_base_uoflow(unsigned n, string_view label, BOOST_HISTOGRAM_ENUM_CLASS_ARG uoflow uo) : base_type(n, label), shape_(n + 2 * static_cast(uo)) {} axis_base_uoflow() = default; @@ -226,7 +226,7 @@ public: */ regular(unsigned n, value_type lower, value_type upper, string_view label = {}, - BOOST_HISTOGRAM_ENUM_CLASS uoflow uo = ::boost::histogram::axis::uoflow::on, + BOOST_HISTOGRAM_ENUM_CLASS_ARG uoflow uo = ::boost::histogram::axis::uoflow::on, Transform trans = Transform()) : base_type(n, label, uo), Transform(trans), min_(trans.forward(lower)), delta_((trans.forward(upper) - trans.forward(lower)) / n) { @@ -372,7 +372,7 @@ public: * \param uoflow whether to add under-/overflow bins. */ variable(std::initializer_list x, string_view label = {}, - BOOST_HISTOGRAM_ENUM_CLASS uoflow uo = ::boost::histogram::axis::uoflow::on) + BOOST_HISTOGRAM_ENUM_CLASS_ARG uoflow uo = ::boost::histogram::axis::uoflow::on) : base_type(x.size() - 1, label, uo), x_(new value_type[x.size()]) { if (x.size() >= 2) { std::copy(x.begin(), x.end(), x_.get()); @@ -384,7 +384,7 @@ public: template variable(Iterator begin, Iterator end, string_view label = {}, - BOOST_HISTOGRAM_ENUM_CLASS uoflow uo = ::boost::histogram::axis::uoflow::on) + BOOST_HISTOGRAM_ENUM_CLASS_ARG uoflow uo = ::boost::histogram::axis::uoflow::on) : base_type(std::distance(begin, end) - 1, label, uo), x_(new value_type[std::distance(begin, end)]) { std::copy(begin, end, x_.get()); @@ -461,7 +461,7 @@ public: * \param uoflow whether to add under-/overflow bins. */ integer(value_type lower, value_type upper, string_view label = {}, - BOOST_HISTOGRAM_ENUM_CLASS uoflow uo = ::boost::histogram::axis::uoflow::on) + BOOST_HISTOGRAM_ENUM_CLASS_ARG uoflow uo = ::boost::histogram::axis::uoflow::on) : base_type(upper - lower, label, uo), min_(lower) { if (!(lower < upper)) { throw std::invalid_argument("lower < upper required"); diff --git a/include/boost/histogram/detail/axis_visitor.hpp b/include/boost/histogram/detail/axis_visitor.hpp index 6314b2c2..e7a4b341 100644 --- a/include/boost/histogram/detail/axis_visitor.hpp +++ b/include/boost/histogram/detail/axis_visitor.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include diff --git a/include/boost/histogram/detail/meta.hpp b/include/boost/histogram/detail/meta.hpp index 0e198252..ff496eeb 100644 --- a/include/boost/histogram/detail/meta.hpp +++ b/include/boost/histogram/detail/meta.hpp @@ -71,49 +71,28 @@ template (), ++std::declval())> struct requires_iterator {}; -template -using union_t = mp11::mp_unique>; +template +using requires_axis = decltype(std::declval().size(), + std::declval().shape(), + std::declval().uoflow(), + std::declval().label(), + std::declval()[0]); -struct bool_mask_op { - std::vector &b; - bool v; - template void operator()(const N &) const { b[N::value] = v; } -}; +namespace { + struct bool_mask_impl { + std::vector &b; + bool v; + template void operator()(Int) const { b[Int::value] = v; } + }; +} -template std::vector bool_mask(unsigned n, bool v) { +template +std::vector bool_mask(unsigned n, bool v) { std::vector b(n, !v); - mp11::mp_for_each(bool_mask_op{b, v}); + mp11::mp_for_each>(bool_mask_impl{b, v}); return b; } -template struct axes_assign_subset_op { - const Axes &axes_; - template - auto operator()(mp11::mp_int, R &r) const -> mp11::mp_int { - using I2 = typename mp11::mp_at_c::type; - r = std::get(axes_); - return {}; - } -}; - -template -void axes_assign_subset(Axes1 &axes1, const Axes &axes) { - // fusion::fold(axes1, mpl::int_<0>(), axes_assign_subset_op{axes}); -} - -template -using unique_sorted_t = mp11::mp_unique>; - -template -struct axes_select { - template - using axes_at = mp11::mp_at; - using type = mp11::mp_transform; -}; - -template -using axes_select_t = typename axes_select::type; - template using size_of = std::tuple_size::type>; @@ -121,25 +100,43 @@ template using type_of = typename std::tuple_element::type>::type; namespace { - template - struct for_each_fn { - Tuple&& t; - F&& f; - for_each_fn(Tuple&& tt, F&& ff) : - t(std::forward(tt)), f(std::forward(ff)) {} - template void operator()(Int) const { - f(std::get(t)); + 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 -void for_each(Tuple&& t, F&& f) { - auto fn = for_each_fn(std::forward(t), - std::forward(f)); - using size = mp11::mp_size::type>; - using nums = mp11::mp_iota; - mp11::mp_for_each(fn); +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 diff --git a/include/boost/histogram/dynamic_histogram.hpp b/include/boost/histogram/dynamic_histogram.hpp index ed859295..0729681a 100644 --- a/include/boost/histogram/dynamic_histogram.hpp +++ b/include/boost/histogram/dynamic_histogram.hpp @@ -53,7 +53,7 @@ class histogram { static_assert(mp11::mp_size::value > 0, "at least one axis required"); public: - using any_axis_type = axis::any; + using any_axis_type = mp11::mp_rename; using axes_type = std::vector; using element_type = typename Storage::element_type; using const_reference = typename Storage::const_reference; @@ -67,8 +67,9 @@ public: histogram &operator=(const histogram &) = default; histogram &operator=(histogram &&) = default; - template - explicit histogram(const Axes1 &... axes) : axes_({any_axis_type(axes)...}) { + template + explicit histogram(Axis &&... axis) : + axes_({any_axis_type(std::forward(axis))...}) { storage_ = Storage(bincount_from_axes()); } @@ -93,11 +94,11 @@ public: } template - explicit histogram(histogram &&rhs) + explicit histogram(dynamic_histogram &&rhs) : axes_(std::move(rhs.axes_)), storage_(std::move(rhs.storage_)) {} template - histogram &operator=(histogram &&rhs) { + histogram &operator=(dynamic_histogram &&rhs) { if (static_cast(this) != static_cast(&rhs)) { axes_ = std::move(rhs.axes_); storage_ = std::move(rhs.storage_); @@ -466,65 +467,85 @@ private: template void serialize(Archive &, unsigned); }; -template -histogram>> -make_dynamic_histogram(Axes &&... axes) { - return histogram>>( - std::forward(axes)...); -} - -template -histogram>, - array_storage>> -make_dynamic_weighted_histogram(Axes &&... axes) { - return histogram>, - array_storage>>( - std::forward(axes)...); +template +dynamic_histogram< + mp11::mp_set_push_back +> +make_dynamic_histogram(Axis &&... axis) { + using H = dynamic_histogram< + mp11::mp_set_push_back + >; + return H(std::forward(axis)...); } template -histogram>, - Storage> +dynamic_histogram< + mp11::mp_set_push_back, + Storage +> make_dynamic_histogram_with(Axes &&... axes) { - return histogram>, - Storage>(std::forward(axes)...); + using H = dynamic_histogram< + mp11::mp_set_push_back, + Storage + >; + return H(std::forward(axes)...); } template > -histogram> +dynamic_histogram< + mp11::mp_unique< + mp11::mp_append< + axis::builtins, + typename Iterator::value_type::types + > + > +> make_dynamic_histogram(Iterator begin, Iterator end) { - return histogram< - dynamic_tag, - detail::union_t>( - begin, end); + using H = dynamic_histogram< + mp11::mp_unique< + mp11::mp_append< + axis::builtins, + typename Iterator::value_type::types + > + > + >; + return H(begin, end); } -template > -histogram, - array_storage>> -make_dynamic_weighted_histogram(Iterator begin, Iterator end) { - return histogram< - dynamic_tag, - detail::union_t, - array_storage>>(begin, end); -} +// template +// dynamic_histogram< + +// detail::union_t>, +// array_storage>> +// make_dynamic_weighted_histogram(Axes &&... axes) { +// return dynamic_histogram, +// detail::union_t>, +// array_storage>>( +// std::forward(axes)...); +// } -template > -histogram, - Storage> -make_dynamic_histogram_with(Iterator begin, Iterator end) { - return histogram< - dynamic_tag, - detail::union_t, - Storage>(begin, end); -} +// template > +// dynamic_histogram, +// detail::union_t, +// array_storage>> +// make_dynamic_weighted_histogram(Iterator begin, Iterator end) { +// return histogram< +// dynamic_tag, +// detail::union_t, +// array_storage>>(begin, end); +// } + +// template > +// dynamic_histogram, +// detail::union_t, +// Storage> +// make_dynamic_histogram_with(Iterator begin, Iterator end) { +// return histogram< +// dynamic_tag, +// detail::union_t, +// Storage>(begin, end); +// } } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/literals.hpp b/include/boost/histogram/literals.hpp index d39e104e..96bb2930 100644 --- a/include/boost/histogram/literals.hpp +++ b/include/boost/histogram/literals.hpp @@ -34,8 +34,8 @@ template constexpr int parse() { } // namespace detail template -auto operator"" _c() -> mp11::mp_int()> { - return {}; +auto operator"" _c() -> decltype(mpl::int_()>()) { + return ::boost::mp11::mp_int()>(); } } // namespace literals diff --git a/include/boost/histogram/serialization.hpp b/include/boost/histogram/serialization.hpp index ddda9840..bf0bb9e3 100644 --- a/include/boost/histogram/serialization.hpp +++ b/include/boost/histogram/serialization.hpp @@ -193,7 +193,7 @@ template void histogram::serialize(Archive &ar, unsigned /* version */) { detail::serialize_helper sh(ar); - detail::for_each(axes_, sh); + mp11::tuple_for_each(axes_, sh); ar &storage_; } diff --git a/include/boost/histogram/static_histogram.hpp b/include/boost/histogram/static_histogram.hpp index b815b778..2bea5f3c 100644 --- a/include/boost/histogram/static_histogram.hpp +++ b/include/boost/histogram/static_histogram.hpp @@ -38,7 +38,7 @@ class histogram { static_assert(axes_size::value > 0, "at least one axis required"); public: - using axes_type = mp11::mp_apply; + using axes_type = mp11::mp_rename; using element_type = typename Storage::element_type; using const_reference = typename Storage::const_reference; using const_iterator = iterator_over; @@ -50,8 +50,10 @@ public: histogram &operator=(const histogram &rhs) = default; histogram &operator=(histogram &&rhs) = default; - template - explicit histogram(Axis &&... axis) : axes_(std::forward(axis)...) { + template > + explicit histogram(Axis0 && axis0, Axis &&... axis) + : axes_(std::forward(axis0), std::forward(axis)...) { storage_ = Storage(bincount_from_axes()); } @@ -60,11 +62,11 @@ public: } template - explicit histogram(const histogram &rhs) + explicit histogram(const static_histogram &rhs) : axes_(rhs.axes_), storage_(rhs.storage_) {} template - histogram &operator=(const histogram &rhs) { + histogram &operator=(const static_histogram &rhs) { if (static_cast(this) != static_cast(&rhs)) { axes_ = rhs.axes_; storage_ = rhs.storage_; @@ -73,13 +75,13 @@ public: } template - explicit histogram(const histogram &rhs) + explicit histogram(const dynamic_histogram &rhs) : storage_(rhs.storage_) { detail::axes_assign(axes_, rhs.axes_); } template - histogram &operator=(const histogram &rhs) { + histogram &operator=(const dynamic_histogram &rhs) { if (static_cast(this) != static_cast(&rhs)) { detail::axes_assign(axes_, rhs.axes_); storage_ = rhs.storage_; @@ -88,36 +90,35 @@ public: } template - bool operator==(const histogram &) const noexcept { + bool operator==(const static_histogram &) const noexcept { return false; } template - bool operator==(const histogram &rhs) const noexcept { + bool operator==(const static_histogram &rhs) const noexcept { return detail::axes_equal(axes_, rhs.axes_) && storage_ == rhs.storage_; } template - bool operator==(const histogram &rhs) const noexcept { + 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 histogram &rhs) { + histogram &operator+=(const static_histogram &rhs) { BOOST_ASSERT_MSG(detail::axes_equal(axes_, rhs.axes_), "axes of histograms differ"); storage_ += rhs.storage_; return *this; } template - histogram &operator+=(const histogram &rhs) { - if (!detail::axes_equal(axes_, rhs.axes_)) - throw std::invalid_argument("axes of histograms differ"); + histogram &operator+=(const dynamic_histogram &rhs) { + BOOST_ASSERT_MSG(detail::axes_equal(axes_, rhs.axes_), "axes of histograms differ"); storage_ += rhs.storage_; return *this; } @@ -149,6 +150,7 @@ public: detail::classify_container_t>(), std::forward(t)); } + // TODO: merge this with unpacking template void operator()(detail::weight&& w, Ts &&... ts) { // case with one argument is ambiguous, is specialized below @@ -158,6 +160,7 @@ public: fill_storage_impl(idx, std::move(w)); } + // TODO: remove as obsolete template void operator()(detail::weight&& w, T&&t) { // check whether we need to unpack argument @@ -166,13 +169,13 @@ public: detail::classify_container_t>(), std::forward(t), std::move(w)); } - template - const_reference at(Indices &&... indices) const { + template + const_reference at(Ts &&... ts) const { // case with one argument is ambiguous, is specialized below - static_assert(sizeof...(indices) == axes_size::value, + static_assert(sizeof...(ts) == axes_size::value, "bin arguments do not match histogram dimension"); std::size_t idx = 0, stride = 1; - lin<0>(idx, stride, static_cast(indices)...); + lin<0>(idx, stride, static_cast(ts)...); if (stride == 0) throw std::out_of_range("bin index out of range"); return storage_[idx]; @@ -232,24 +235,21 @@ public: /// Apply unary functor/function to each axis template void for_each_axis(Unary &&unary) const { - detail::for_each(axes_, std::forward(unary)); + mp11::tuple_for_each(axes_, std::forward(unary)); } /// Returns a lower-dimensional histogram - template - auto reduce_to(mp11::mp_int, Rest...) const -> histogram< - static_tag, - detail::axes_select_t, Rest...>, + template + auto reduce_to(mp11::mp_int, Ns...) const -> static_histogram< + detail::selection, Ns...>, Storage> { - using HR = histogram< - static_tag, - detail::axes_select_t, Rest...>, - Storage>; - typename HR::axes_type axes; - detail::axes_assign_subset, Rest...>(axes, axes_); - auto hr = HR(std::move(axes)); + using HR = static_histogram< + detail::selection, Ns...>, + Storage + >; + auto hr = HR(detail::make_sub_axes, Ns...>(axes_)); const auto b = - detail::bool_mask, Rest...>(dim(), true); + detail::bool_mask, Ns...>(dim(), true); reduce_impl(hr, b); return hr; } @@ -268,7 +268,7 @@ private: std::size_t bincount_from_axes() const noexcept { detail::field_count_visitor fc; - detail::for_each(axes_, fc); + mp11::tuple_for_each(axes_, fc); return fc.value; } @@ -450,27 +450,27 @@ private: /// default static type factory template -inline histogram> +static_histogram> make_static_histogram(Axis &&... axis) { - using h = histogram>; - return h(typename h::axes_type(std::forward(axis)...)); -} - -template -inline histogram, - array_storage>> -make_static_weighted_histogram(Axis &&... axis) { - using h = histogram, - array_storage>>; - return h(typename h::axes_type(std::forward(axis)...)); + using H = static_histogram>; + return H(std::forward(axis)...); } /// static type factory with variable storage type template -inline histogram, Storage> +static_histogram, Storage> make_static_histogram_with(Axis &&... axis) { - using h = histogram, Storage>; - return h(typename h::axes_type(std::forward(axis)...)); + using H = static_histogram, Storage>; + return H(std::forward(axis)...); +} + +template +static_histogram, + array_storage>> +make_static_weighted_histogram(Axis &&... axis) { + using H = static_histogram, + array_storage>>; + return H(std::forward(axis)...); } } // namespace histogram diff --git a/test/detail_test.cpp b/test/detail_test.cpp index 3c9f9bc3..5ac84a06 100644 --- a/test/detail_test.cpp +++ b/test/detail_test.cpp @@ -20,26 +20,38 @@ #include using namespace boost::histogram::detail; +namespace mp11 = boost::mp11; -struct for_each_test_visitor { - int i = 0; - bool result = true; - template void operator()(T& t) { - // expect: int char float - switch (i++) { - case 0: - result &= std::is_same::value; - break; - case 1: - result &= std::is_same::value; - break; - case 2: - result &= std::is_same::value; - }; - t += 1; +using i0 = mp11::mp_int<0>; +using i1 = mp11::mp_int<1>; +using i2 = mp11::mp_int<2>; +using i3 = mp11::mp_int<3>; + +namespace boost { namespace detail { +template +std::ostream& operator<<(std::ostream& os, const std::vector& v) { + os << "["; + for (const auto& x : v) + os << x << " "; + os << "]"; + return os; +} + +struct ostreamer { + std::ostream& os; + template void operator()(const T& t) const { + os << t << " "; } }; +template +std::ostream& operator<<(std::ostream& os, const std::tuple& t) { + os << "["; + mp11::tuple_for_each(t, ostreamer{os}); + os << "]"; + return os; +} +}} int main() { // escape0 @@ -113,25 +125,9 @@ int main() { } // cat - { BOOST_TEST_EQ(cat("foo", 1, "bar"), std::string("foo1bar")); } - - // unique_sorted { - using input = ::boost::mp11::mp_list_c; - using result = unique_sorted_t; - using expected = ::boost::mp11::mp_list_c; - - BOOST_TEST_TRAIT_TRUE((std::is_same)); - } - - // union - { - using main_list = ::boost::mp11::mp_list; - using aux_list = ::boost::mp11::mp_list; - using result = union_t; - using expected = ::boost::mp11::mp_list; - - BOOST_TEST_TRAIT_TRUE((std::is_same)); + BOOST_TEST_EQ(cat("foo", 1, "bar"), + std::string("foo1bar")); } // has_variance_support @@ -183,16 +179,50 @@ int main() { BOOST_TEST_TRAIT_TRUE(( std::is_same )); } - // for_each + // bool mask { - for_each_test_visitor v; - std::tuple t(0, 0, 0); - ::boost::histogram::detail::for_each(t, v); - BOOST_TEST_EQ(v.i, 3); - BOOST_TEST_EQ(v.result, true); - BOOST_TEST_EQ(std::get<0>(t), 1); - BOOST_TEST_EQ(std::get<1>(t), 1); - BOOST_TEST_EQ(std::get<2>(t), 1); + 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})); + } + + // // literals + // { + // using c0 = 0_c; + // BOOST_TEST_TRAIT_TRUE((std::is_same>)); + // } + + // selection + { + struct A {}; + struct B {}; + struct C {}; + + using input = mp11::mp_list; + using result = selection; + using expected = mp11::mp_list; + + BOOST_TEST_TRAIT_TRUE((std::is_same)); + } + + // unique_sorted + { + using input = mp11::mp_list_c; + using result = unique_sorted; + using expected = mp11::mp_list_c; + + 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();