diff --git a/include/boost/histogram/indexed.hpp b/include/boost/histogram/indexed.hpp index 7263202e..5cfc8604 100644 --- a/include/boost/histogram/indexed.hpp +++ b/include/boost/histogram/indexed.hpp @@ -21,94 +21,91 @@ namespace boost { namespace histogram { /// Range over histogram bins with multi-dimensional index. -template +template class BOOST_HISTOGRAM_NODISCARD indexed_range { - using value_type = typename Histogram::value_type; - using value_iterator = typename Histogram::const_iterator; + using value_type = typename detail::unqual::value_type; + using value_iterator = detail::unqual().begin())>; struct cache_item { int idx, begin, end, extend; }; - using cache_type = detail::axes_buffer; + using cache_type = + detail::axes_buffer::axes_type, cache_item>; public: class accessor { public: - class const_iterator - : public boost::iterator_adaptor { public: - const_iterator(typename cache_type::const_iterator i) - : const_iterator::iterator_adaptor_(i) {} - decltype(auto) operator*() const noexcept { - return const_iterator::base_reference()->idx; - } + index_iterator(typename cache_type::const_iterator i) + : index_iterator::iterator_adaptor_(i) {} + decltype(auto) operator*() const noexcept { return index_iterator::base()->idx; } }; - int operator[](unsigned d) const { return parent_.cache_[d].idx; } - auto begin() const { return const_iterator(parent_.cache_.begin()); } - auto end() const { return const_iterator(parent_.cache_.end()); } - auto size() const { return parent_.cache_.size(); } + int operator[](unsigned d) const { return parent_->cache_[d].idx; } + auto begin() const { return index_iterator(parent_->cache_.begin()); } + auto end() const { return index_iterator(parent_->cache_.end()); } + auto size() const { return parent_->cache_.size(); } template decltype(auto) bin(std::integral_constant) const { - return parent_.hist_.axis(std::integral_constant())[(*this)[N]]; + return parent_->hist_.axis(std::integral_constant())[(*this)[N]]; } - decltype(auto) bin(unsigned d) const { return parent_.hist_.axis(d)[(*this)[d]]; } + decltype(auto) bin(unsigned d) const { return parent_->hist_.axis(d)[(*this)[d]]; } double density() const { double x = 1; auto it = begin(); - parent_.hist_.for_each_axis([&](const auto& a) { + parent_->hist_.for_each_axis([&](const auto& a) { const auto w = axis::traits::width_as(a, *it++); x *= w ? w : 1; }); return *iter_ / x; } - accessor(const indexed_range& parent, value_iterator i) : parent_(parent), iter_(i) {} + accessor(indexed_range* parent, value_iterator i) : parent_(parent), iter_(i) {} decltype(auto) operator*() const noexcept { return *iter_; } auto operator-> () const noexcept { return iter_; } private: - const indexed_range& parent_; + indexed_range* parent_; value_iterator iter_; }; - class const_iterator - : public boost::iterator_adaptor { public: - const_iterator(const indexed_range& p, value_iterator i) noexcept - : const_iterator::iterator_adaptor_(i), parent_(p) {} + range_iterator(indexed_range* p, value_iterator i) noexcept + : range_iterator::iterator_adaptor_(i), parent_(p) {} - auto operator*() const noexcept { - return accessor(parent_, const_iterator::base_reference()); - } + accessor operator*() const noexcept { return {parent_, range_iterator::base()}; } private: friend class boost::iterator_core_access; void increment() noexcept { std::size_t stride = 1; - auto c = parent_.cache_.begin(); + auto c = parent_->cache_.begin(); ++c->idx; - ++const_iterator::base_reference(); - while (c->idx == c->end && ((c + 1) != parent_.cache_.end())) { + ++range_iterator::base_reference(); + while (c->idx == c->end && ((c + 1) != parent_->cache_.end())) { c->idx = c->begin; - const_iterator::base_reference() -= (c->end - c->idx) * stride; + range_iterator::base_reference() -= (c->end - c->idx) * stride; stride *= c->extend; ++c; ++c->idx; - const_iterator::base_reference() += stride; + range_iterator::base_reference() += stride; } } - const indexed_range& parent_; + mutable indexed_range* parent_; }; - indexed_range(const Histogram& h, bool include_extra_bins) + indexed_range(Histogram& h, bool include_extra_bins) : hist_(h) , include_extra_bins_(include_extra_bins) , begin_(hist_.begin()) @@ -137,19 +134,19 @@ public: }); } - decltype(auto) begin() const { return const_iterator(*this, begin_); } - decltype(auto) end() const { return const_iterator(*this, end_); } + range_iterator begin() noexcept { return {this, begin_}; } + range_iterator end() noexcept { return {this, end_}; } private: - const Histogram& hist_; + Histogram& hist_; const bool include_extra_bins_; value_iterator begin_, end_; mutable cache_type cache_; }; // namespace histogram template -indexed_range> indexed(Histogram&& h, - bool include_extra_bins = false) { +indexed_range> indexed( + Histogram&& h, bool include_extra_bins = false) { return {std::forward(h), include_extra_bins}; } diff --git a/test/indexed_test.cpp b/test/indexed_test.cpp index aec7ab91..0d2c0c3c 100644 --- a/test/indexed_test.cpp +++ b/test/indexed_test.cpp @@ -57,6 +57,11 @@ void run_1d_tests(mp_list) { ++it; } BOOST_TEST(it == ind.end()); + + for (auto&& x : indexed(h, IncludeExtraBins())) *x = 0; + + for (auto&& x : indexed(static_cast(h), IncludeExtraBins())) + BOOST_TEST_EQ(*x, 0); } template