diff --git a/include/boost/histogram.hpp b/include/boost/histogram.hpp index 85107ccc..f94d910f 100644 --- a/include/boost/histogram.hpp +++ b/include/boost/histogram.hpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/boost/histogram/multi_storage.hpp b/include/boost/histogram/multi_storage.hpp new file mode 100644 index 00000000..b22ef7ef --- /dev/null +++ b/include/boost/histogram/multi_storage.hpp @@ -0,0 +1,112 @@ +// Copyright 2022 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_MULTI_STORAGE_HPP +#define BOOST_HISTOGRAM_MULTI_STORAGE_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace histogram { + +template +class multi_storage { +public: + using element_type = ElementType; + + struct accumulator : public span { + using span::span; + + void operator()(span values) { + if (values.size() != this->size()) throw std::runtime_error("size does not match"); + + auto it = this->begin(); + for (const element_type& v : values) { + // TODO make this more flexible, support operator++ and operator() + *it++ += v; + } + } + }; + + using value_type = std::vector; + using reference = span; + using const_reference = span; + + template + struct iterator_base + : public detail::iterator_adaptor, T*, span, value_type> { + using reference = typename iterator_base::reference; + using difference_type = typename iterator_base::difference_type; + + iterator_base(T* ptr, std::size_t nelem) + : iterator_base::iterator_adaptor_{ptr}, nelem_{nelem} {} + iterator_base(const iterator_base& other) + : iterator_base::iterator_adaptor_(other), nelem_{other.nelem_} {} + iterator_base& operator=(const iterator_base& other) { + if (this != &other) { + iterator_base::iterator_adaptor_::operator=(other); + nelem_ = other.nelem_; + } + return *this; + } + + iterator_base& operator+=(difference_type n) { + iterator_base::iterator_adaptor_::operator+=(n* nelem_); + return *this; + } + + reference operator*() { return {this->base(), nelem_}; } + + std::size_t nelem_; + }; + + using iterator = iterator_base; + using const_iterator = iterator_base; + + static constexpr bool has_threading_support() { return false; } + + multi_storage(const std::size_t nelem) : nelem_{nelem} {} + + std::size_t size() const { return size_; } + std::size_t width() const { return nelem_; } + + void reset(std::size_t n) { + size_ = n; + buffer_.reset(new element_type[n * nelem_]); + } + + iterator begin() { return {buffer_.get(), nelem_}; } + iterator end() { return {buffer_.get() + size_ * nelem_, nelem_}; } + + const_iterator begin() const { return {buffer_.get(), nelem_}; } + const_iterator end() const { return {buffer_.get() + size_ * nelem_, nelem_}; } + + reference operator[](std::size_t i) { return {buffer_.get() + i * nelem_, nelem_}; } + const_reference operator[](std::size_t i) const { + return {buffer_.get() + i * nelem_, nelem_}; + } + + template + bool operator==(const multi_storage& other) const { + if (size() != other.size()) return false; + return std::equal(buffer_._get(), buffer_.get() + size_ * nelem_, other.ptr_.get()); + } + +public: + std::size_t size_ = 0; + std::size_t nelem_; + std::unique_ptr buffer_; +}; + +} // namespace histogram +} // namespace boost + +#endif \ No newline at end of file diff --git a/include/boost/histogram/multi_sum_storage.hpp b/include/boost/histogram/multi_sum_storage.hpp deleted file mode 100644 index d24ca626..00000000 --- a/include/boost/histogram/multi_sum_storage.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef BOOST_HISTOGRAM_MULTI_SUM_STORAGE_HPP -#define BOOST_HISTOGRAM_MULTI_SUM_STORAGE_HPP - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace histogram { - -namespace accumulators { -template -struct multi_sum : public boost::span { - using boost::span::span; - - void operator()(boost::span values) { - if (values.size() != this->size()) throw std::runtime_error("size does not match"); - - auto it = this->begin(); - for (const T& x : values) *it++ += x; - } -}; -} // namespace accumulators - -template -class multi_sum_storage { -public: - template - using multi_sum = accumulators::multi_sum; - using element_type = ElementType; - - using value_type = multi_sum; - using reference = value_type; - using const_reference = multi_sum; - - template - struct iterator_base - : public detail::iterator_adaptor, std::size_t, multi_sum> { - using base_type = - detail::iterator_adaptor, std::size_t, multi_sum>; - - iterator_base(T* ptr, std::size_t idx, std::size_t nelem) - : base_type{idx}, ptr_{ptr}, nelem_{nelem} {} - iterator_base(const iterator_base& other) - : base_type(other), ptr_{other.ptr_}, nelem_{other.nelem_} {} - iterator_base& operator=(const iterator_base& other) { - if (this != &other) { - base_type::operator=(other); - ptr_ = other.ptr_; - nelem_ = other.nelem_; - } - return *this; - } - - decltype(auto) operator*() { - return multi_sum{ptr_ + this->base() * nelem_, nelem_}; - } - - T* ptr_; - std::size_t nelem_; - }; - - using iterator = iterator_base; - using const_iterator = iterator_base; - - static constexpr bool has_threading_support() { return false; } - - multi_sum_storage(const std::size_t nelem) : nelem_{nelem} {} - - std::size_t size() const { return size_; } - - void reset(std::size_t n) { - size_ = n; - buffer_.reset(new element_type[n * nelem_]); - } - - iterator begin() { return {buffer_.get(), 0, nelem_}; } - iterator end() { return {buffer_.get(), size_, nelem_}; } - - const_iterator begin() const { return {buffer_.get(), 0, nelem_}; } - const_iterator end() const { return {buffer_.get(), size_, nelem_}; } - - reference operator[](std::size_t i) { - return reference{buffer_.get() + i * nelem_, nelem_}; - } - const_reference operator[](std::size_t i) const { - return const_reference{buffer_.get() + i * nelem_, nelem_}; - } - - template - bool operator==(const multi_sum_storage& other) const { - if (size() != other.size()) return false; - return std::equal(buffer_._get(), buffer_.get() + size_ * nelem_, other.ptr_.get()); - } - -public: - std::size_t size_ = 0; - std::size_t nelem_; - std::unique_ptr buffer_; -}; - -} // namespace histogram -} // namespace boost - -#endif \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3340dcee..40b1f79c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -88,6 +88,7 @@ set_tests_properties(run-boost_histogram-histogram_ostream_ascii_test PROPERTIES ENVIRONMENT "LANG=FOO;COLUMNS=20") boost_test(TYPE run SOURCES histogram_test.cpp) boost_test(TYPE run SOURCES indexed_test.cpp) +boost_test(TYPE run SOURCES multi_storage_test.cpp) boost_test(TYPE run SOURCES storage_adaptor_test.cpp) boost_test(TYPE run SOURCES unlimited_storage_test.cpp) boost_test(TYPE run SOURCES utility_test.cpp) diff --git a/test/Jamfile b/test/Jamfile index 056025d0..d73ca71f 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -84,6 +84,7 @@ alias cxx14 : [ run histogram_operators_test.cpp ] [ run histogram_test.cpp ] [ run indexed_test.cpp ] + [ run multi_storage_test.cpp ] [ run storage_adaptor_test.cpp ] [ run unlimited_storage_test.cpp ] [ run utility_test.cpp ] diff --git a/test/multi_storage_test.cpp b/test/multi_storage_test.cpp new file mode 100644 index 00000000..9b1028db --- /dev/null +++ b/test/multi_storage_test.cpp @@ -0,0 +1,35 @@ +// Copyright 2022 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) + +#include +#include +#include +#include "throw_exception.hpp" + +using namespace boost::histogram; + +template +void test() { + using M = multi_storage; + + M m(2); + + BOOST_TEST_EQ(m.width(), 2); + BOOST_TEST_EQ(m.size(), 0); + + m.reset(3); + + BOOST_TEST_EQ(m.width(), 2); + BOOST_TEST_EQ(m.size(), 3); +} + +int main() { + + test(); + test>(); + + return boost::report_errors(); +} \ No newline at end of file