From 7d0bd00adba82fa6fa2e53e90cc61bb02b220f0b Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Sun, 16 Dec 2018 20:32:38 +0100 Subject: [PATCH] use indexed in reduce and project, making index_mapper obsolete --- include/boost/histogram/algorithm/project.hpp | 112 ++++++------------ include/boost/histogram/algorithm/reduce.hpp | 9 +- include/boost/histogram/detail/axes.hpp | 6 +- .../boost/histogram/detail/index_mapper.hpp | 101 ---------------- include/boost/histogram/detail/meta.hpp | 7 ++ include/boost/histogram/indexed.hpp | 8 +- test/Jamfile | 1 - test/meta_test.cpp | 13 ++ 8 files changed, 64 insertions(+), 193 deletions(-) delete mode 100644 include/boost/histogram/detail/index_mapper.hpp diff --git a/include/boost/histogram/algorithm/project.hpp b/include/boost/histogram/algorithm/project.hpp index d0184073..005fb0ad 100644 --- a/include/boost/histogram/algorithm/project.hpp +++ b/include/boost/histogram/algorithm/project.hpp @@ -9,8 +9,9 @@ #include #include -#include -#include +#include +#include +#include #include #include #include @@ -29,38 +30,22 @@ namespace algorithm { histogram is summed over the removed axes. */ template -auto project(const histogram& h, std::integral_constant n, Ns... ns) { +auto project(const histogram& hist, std::integral_constant n, + Ns... ns) { using LN = mp11::mp_list; static_assert(mp11::mp_is_set::value, "indices must be unique"); - const auto& axes = unsafe_access::axes(h); - auto r_axes = detail::make_sub_axes(axes, n, ns...); - auto r_h = histogram( - std::move(r_axes), - detail::static_if>( - [&h](auto) { return S(unsafe_access::storage(h).get_allocator()); }, - [](auto) { return S(); }, 0)); + auto axes = detail::make_sub_axes(unsafe_access::axes(hist), n, ns...); + auto result = histogram( + std::move(axes), detail::make_default(unsafe_access::storage(hist))); - detail::index_mapper im(h.rank()); - auto iter = im.begin(); - std::size_t s = 1; - h.for_each_axis([&](const auto& a) { - const auto n = axis::traits::extend(a); - im.total *= n; - iter->stride[0] = s; - s *= n; - iter->stride[1] = 0; - ++iter; - }); - - s = 1; - mp11::mp_for_each([&](auto J) { - im[J].stride[1] = s; - s *= axis::traits::extend(detail::axis_get(axes)); - }); - - im(unsafe_access::storage(r_h), unsafe_access::storage(h)); - return r_h; + detail::axes_buffer idx(result.rank()); + for (auto x : indexed(hist, true)) { + auto i = idx.begin(); + mp11::mp_for_each([&i, &x](auto I) { *i++ = x[I]; }); + unsafe_access::add_value(result, idx, *x); + } + return result; } /** @@ -69,59 +54,32 @@ auto project(const histogram& h, std::integral_constant n, Ns This version accepts a source histogram and an iterable range containing the remaining indices. */ -template > -auto project(const histogram& h, const C& c) { +template > +auto project(const histogram& hist, const Iterable& c) { static_assert(detail::is_axis_vector::value, "dynamic version of project requires a histogram with dynamic axis"); - using H = histogram; - - const auto& axes = unsafe_access::axes(h); - auto r_axes = detail::static_if>( - [](const auto& axes) { - using T = detail::unqual; - return T(axes.get_allocator()); - }, - [](const auto& axes) { - using T = detail::unqual; - return T(); - }, - axes); - - using std::begin; - using std::end; - r_axes.reserve(std::distance(begin(c), end(c))); - - detail::index_mapper im(h.rank()); - auto iter = im.begin(); - std::size_t stride = 1; - h.for_each_axis([&](const auto& a) { - const auto n = axis::traits::extend(a); - im.total *= n; - iter->stride[0] = stride; - stride *= n; - iter->stride[1] = 0; - ++iter; - }); - - stride = 1; - for (auto idx : c) { - r_axes.emplace_back(axes[idx]); - auto& stride_ref = im[idx].stride[1]; - if (stride_ref) - BOOST_THROW_EXCEPTION(std::invalid_argument("indices must be unique")); - else - stride_ref = stride; - stride *= axis::traits::extend(axes[idx]); + const auto& hist_axes = unsafe_access::axes(hist); + auto axes = detail::make_default(hist_axes); + axes.reserve(c.size()); + detail::axes_buffer seen(hist_axes.size(), false); + for (auto d : c) { + if (seen[d]) BOOST_THROW_EXCEPTION(std::invalid_argument("indices must be unique")); + seen[d] = true; + axes.emplace_back(hist_axes[d]); } - auto r_h = H(std::move(r_axes), - detail::static_if>( - [&h](auto) { return S(unsafe_access::storage(h).get_allocator()); }, - [](auto) { return S(); }, 0)); + auto result = histogram(std::move(axes), + detail::make_default(unsafe_access::storage(hist))); - im(unsafe_access::storage(r_h), unsafe_access::storage(h)); - return r_h; + detail::axes_buffer idx(result.rank()); + for (auto x : indexed(hist, true)) { + auto i = idx.begin(); + for (auto d : c) *i++ = x[d]; + unsafe_access::add_value(result, idx, *x); + } + return result; } } // namespace algorithm diff --git a/include/boost/histogram/algorithm/reduce.hpp b/include/boost/histogram/algorithm/reduce.hpp index e0ad3b52..cd0539ab 100644 --- a/include/boost/histogram/algorithm/reduce.hpp +++ b/include/boost/histogram/algorithm/reduce.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -112,12 +111,8 @@ histogram reduce(const histogram& hist, const C& options) { ++iaxis; }); - const auto& storage = unsafe_access::storage(hist); - using storage_type = detail::unqual; - auto result = histogram( - std::move(axes), detail::static_if>( - [](auto& x) { return storage_type(x.get_allocator()); }, - [](auto&) { return storage_type(); }, storage)); + auto result = histogram(std::move(axes), + detail::make_default(unsafe_access::storage(hist))); detail::axes_buffer idx(hist.rank()); for (auto x : indexed(hist, true)) { diff --git a/include/boost/histogram/detail/axes.hpp b/include/boost/histogram/detail/axes.hpp index bd8f7ff8..a9bdf45b 100644 --- a/include/boost/histogram/detail/axes.hpp +++ b/include/boost/histogram/detail/axes.hpp @@ -172,9 +172,9 @@ using axes_buffer = boost::container::static_vector< std::tuple_size, Axes>::value>; template -auto make_empty_axes(const T& t) { - auto r = T(); - static_if>([&](auto) { r.reserve(t.size()); }, [](auto) {}, 0); +auto make_empty_axes(const std::vector& t) { + auto r = std::vector(t.get_allocator()); + r.reserve(t.size()); for_each_axis(t, [&r](const auto& a) { using U = unqual; r.emplace_back(U()); diff --git a/include/boost/histogram/detail/index_mapper.hpp b/include/boost/histogram/detail/index_mapper.hpp deleted file mode 100644 index 691f9ebe..00000000 --- a/include/boost/histogram/detail/index_mapper.hpp +++ /dev/null @@ -1,101 +0,0 @@ -// 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_INDEX_MAPPER_HPP -#define BOOST_HISTOGRAM_DETAIL_INDEX_MAPPER_HPP - -#include -#include -#include -#include - -namespace boost { -namespace histogram { -namespace detail { - -template -struct index_mapper { - struct item { - std::size_t stride[2]; - }; - using buffer_type = axes_buffer; - - index_mapper(unsigned dim) : buffer(dim) {} - - template - void operator()(T& dst, const U& src) { - for (std::size_t i = 0; i < total; ++i) { - std::size_t j = 0; - auto imod = i; - for (auto it = end(); it != begin(); --it) { - const auto& d = *(it - 1); - // compiler usually optimizes div & mod into one div - const auto k = imod / d.stride[0]; - imod %= d.stride[0]; - j += k * d.stride[1]; - } - dst.add(j, src[i]); - } - } - - decltype(auto) begin() { return buffer.begin(); } - decltype(auto) end() { return buffer.end(); } - - decltype(auto) operator[](unsigned i) { return buffer[i]; } - - buffer_type buffer; - std::size_t total = 1; -}; - -template -class index_mapper_reduce { -public: - struct item { - std::size_t stride[2]; - int underflow[2], overflow[2], begin, end, merge; - }; - using buffer_type = axes_buffer; - - index_mapper_reduce(unsigned dim) : buffer(dim) {} - - template - void operator()(T& dst, const U& src) { - for (std::size_t i = 0; i < total; ++i) { - std::size_t j = 0; - auto imod = i; - bool drop = false; - for (auto it = end(); it != begin(); --it) { - const auto& d = *(it - 1); - // compiler usually optimizes div & mod into one div - int k = imod / d.stride[0]; - imod %= d.stride[0]; - if (k < d.begin || k == d.underflow[0]) { - k = d.underflow[1]; - } else if (k >= d.end || k == d.overflow[0]) { - k = d.overflow[1]; - } else { - k = (k - d.begin) / d.merge; - } - drop |= k < 0; - j += k * d.stride[1]; - } - if (!drop) dst.add(j, src[i]); - } - } - - decltype(auto) begin() { return buffer.begin(); } - decltype(auto) end() { return buffer.end(); } - - decltype(auto) operator[](unsigned i) { return buffer[i]; } - - buffer_type buffer; - std::size_t total = 1; -}; -} // namespace detail -} // namespace histogram -} // namespace boost - -#endif diff --git a/include/boost/histogram/detail/meta.hpp b/include/boost/histogram/detail/meta.hpp index b724c623..e0776f46 100644 --- a/include/boost/histogram/detail/meta.hpp +++ b/include/boost/histogram/detail/meta.hpp @@ -284,6 +284,13 @@ struct requires_axis_or_axis_variant {}; template >, void>> struct requires_axis_vector {}; +template +T make_default(const T& t) { + using U = unqual; + return static_if>([](const auto& t) { return U(t.get_allocator()); }, + [](const auto&) { return U(); }, t); +} + } // namespace detail } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/indexed.hpp b/include/boost/histogram/indexed.hpp index fb44a033..7098dae8 100644 --- a/include/boost/histogram/indexed.hpp +++ b/include/boost/histogram/indexed.hpp @@ -117,14 +117,14 @@ public: , cache_(hist_.rank()) { auto c = cache_.begin(); std::size_t stride = 1; - const auto extra = include_extra_bins_; - h.for_each_axis([&](const auto& a) { + h.for_each_axis([&, this](const auto& a) { const auto opt = axis::traits::options(a); const auto shift = opt & axis::option_type::underflow; c->extend = axis::traits::extend(a); - c->begin = extra ? -shift : 0; - c->end = c->extend - shift - (extra ? 0 : (opt & axis::option_type::overflow)); + c->begin = include_extra_bins_ ? -shift : 0; + c->end = c->extend - shift - + (include_extra_bins_ ? 0 : (opt & axis::option_type::overflow)); c->idx = c->begin; begin_ += (c->begin + shift) * stride; diff --git a/test/Jamfile b/test/Jamfile index 08043130..59af4cd1 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -27,7 +27,6 @@ alias run-tests : [ run histogram_mixed_test.cpp ] [ run histogram_serialization_test.cpp /boost/serialization//boost_serialization/static ] [ run histogram_test.cpp ] - [ run index_mapper_test.cpp ] [ run meta_test.cpp ] [ run storage_adaptor_test.cpp ] [ run storage_adaptor_serialization_test.cpp /boost/serialization//boost_serialization/static ] diff --git a/test/meta_test.cpp b/test/meta_test.cpp index 39a03075..1a18738c 100644 --- a/test/meta_test.cpp +++ b/test/meta_test.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "utility_allocator.hpp" #include "utility_meta.hpp" namespace bh = boost::histogram; @@ -435,5 +436,17 @@ int main() { BOOST_TEST(has_fixed_size::value); } + // make_default + { + struct A {}; + auto a = make_default(A()); + BOOST_TEST_TRAIT_TRUE((std::is_same)); + bh::tracing_allocator_db db; + using B = std::vector>; + B b = make_default(B(bh::tracing_allocator(db))); + b.resize(100); + BOOST_TEST_EQ(db[&BOOST_CORE_TYPEID(int)].first, 100); + } + return boost::report_errors(); }