This commit is contained in:
Hans Dembinski 2022-09-19 17:44:44 +02:00
parent 98f634e232
commit 78dbdd52e5
6 changed files with 150 additions and 109 deletions

View File

@ -31,7 +31,7 @@
#include <boost/histogram/literals.hpp>
#include <boost/histogram/make_histogram.hpp>
#include <boost/histogram/make_profile.hpp>
#include <boost/histogram/multi_sum_storage.hpp>
#include <boost/histogram/multi_storage.hpp>
#include <boost/histogram/storage_adaptor.hpp>
#include <boost/histogram/unlimited_storage.hpp>

View File

@ -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 <algorithm>
#include <boost/core/span.hpp>
#include <boost/histogram/detail/iterator_adaptor.hpp>
#include <boost/histogram/fwd.hpp>
#include <memory>
#include <vector>
namespace boost {
namespace histogram {
template <class ElementType = double>
class multi_storage {
public:
using element_type = ElementType;
struct accumulator : public span<element_type> {
using span<element_type>::span;
void operator()(span<const element_type> 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<element_type>;
using reference = span<element_type>;
using const_reference = span<const element_type>;
template <class T>
struct iterator_base
: public detail::iterator_adaptor<iterator_base<T>, T*, span<T>, 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<element_type>;
using const_iterator = iterator_base<const element_type>;
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 <class T>
bool operator==(const multi_storage<T>& 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<element_type[]> buffer_;
};
} // namespace histogram
} // namespace boost
#endif

View File

@ -1,108 +0,0 @@
#ifndef BOOST_HISTOGRAM_MULTI_SUM_STORAGE_HPP
#define BOOST_HISTOGRAM_MULTI_SUM_STORAGE_HPP
#include <algorithm>
#include <boost/core/span.hpp>
#include <boost/histogram.hpp>
#include <boost/histogram/detail/iterator_adaptor.hpp>
#include <iostream>
#include <memory>
namespace boost {
namespace histogram {
namespace accumulators {
template <class T>
struct multi_sum : public boost::span<T> {
using boost::span<T>::span;
void operator()(boost::span<T> 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 ElementType = double>
class multi_sum_storage {
public:
template <class T>
using multi_sum = accumulators::multi_sum<T>;
using element_type = ElementType;
using value_type = multi_sum<element_type>;
using reference = value_type;
using const_reference = multi_sum<const element_type>;
template <class T>
struct iterator_base
: public detail::iterator_adaptor<iterator_base<T>, std::size_t, multi_sum<T>> {
using base_type =
detail::iterator_adaptor<iterator_base<T>, std::size_t, multi_sum<T>>;
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<T>{ptr_ + this->base() * nelem_, nelem_};
}
T* ptr_;
std::size_t nelem_;
};
using iterator = iterator_base<element_type>;
using const_iterator = iterator_base<const element_type>;
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 <class T>
bool operator==(const multi_sum_storage<T>& 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<element_type[]> buffer_;
};
} // namespace histogram
} // namespace boost
#endif

View File

@ -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)

View File

@ -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 ]

View File

@ -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 <boost/core/lightweight_test.hpp>
#include <boost/histogram/accumulators/sum.hpp>
#include <boost/histogram/multi_storage.hpp>
#include "throw_exception.hpp"
using namespace boost::histogram;
template <class T>
void test() {
using M = multi_storage<T>;
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<double>();
test<accumulators::sum<double>>();
return boost::report_errors();
}