Ruggero Turra 90867e24a4
Add collector accumulator (#390)
Co-authored-by: Hans Dembinski <hans.dembinski@gmail.com>
2024-04-25 09:05:40 +02:00

110 lines
3.9 KiB
C++

// Copyright 2024 Ruggero Turra, 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_ACCUMULATORS_COLLECTOR_HPP
#define BOOST_HISTOGRAM_ACCUMULATORS_COLLECTOR_HPP
#include <algorithm> // for std::equal
#include <boost/core/nvp.hpp>
#include <boost/histogram/detail/detect.hpp>
#include <boost/histogram/fwd.hpp> // for collector<>
#include <initializer_list>
#include <type_traits>
namespace boost {
namespace histogram {
namespace accumulators {
/** Collects samples.
Input samples are stored in an internal container for later retrival, which stores the
values consecutively in memory. The interface is designed to work with std::vector and
other containers which implement the same API.
Warning: The memory of the accumulator is unbounded.
*/
template <class ContainerType>
class collector {
public:
using container_type = ContainerType;
using value_type = typename container_type::value_type;
using allocator_type = typename container_type::allocator_type;
using const_reference = typename container_type::const_reference;
using iterator = typename container_type::iterator;
using const_iterator = typename container_type::const_iterator;
using size_type = typename container_type::size_type;
using const_pointer = typename container_type::const_pointer;
// make template only match if forwarding args to container is valid
template <typename... Args, class = decltype(container_type(std::declval<Args>()...))>
explicit collector(Args&&... args) : container_(std::forward<Args>(args)...) {}
// make template only match if forwarding args to container is valid
template <class T, typename... Args, class = decltype(container_type(std::initializer_list<T>(),std::declval<Args>()...))>
explicit collector(std::initializer_list<T> list, Args&&... args)
: container_(list, std::forward<Args>(args)...) {}
/// Append sample x.
void operator()(const_reference x) { container_.push_back(x); }
/// Append samples from another collector.
template <class C>
collector& operator+=(const collector<C>& rhs) {
container_.reserve(size() + rhs.size());
container_.insert(end(), rhs.begin(), rhs.end());
return *this;
}
/// Return true if collections are equal.
///
/// Two collections are equal if they have the same number of elements
/// which all compare equal.
template <class Iterable, class = detail::is_iterable<Iterable>>
bool operator==(const Iterable& rhs) const noexcept {
return std::equal(begin(), end(), rhs.begin(), rhs.end());
}
/// Return true if collections are not equal.
template <class Iterable, class = detail::is_iterable<Iterable>>
bool operator!=(const Iterable& rhs) const noexcept {
return !operator==(rhs);
}
/// Return number of samples.
size_type size() const noexcept { return container_.size(); }
/// Return number of samples (alias for size()).
size_type count() const noexcept { return container_.size(); }
/// Return readonly iterator to start of collection.
const const_iterator begin() const noexcept { return container_.begin(); }
/// Return readonly iterator to end of collection.
const const_iterator end() const noexcept { return container_.end(); }
/// Return const reference to value at index.
const_reference operator[](size_type idx) const noexcept { return container_[idx]; }
/// Return pointer to internal memory.
const_pointer data() const noexcept { return container_.data(); }
allocator_type get_allocator() const { return container_.get_allocator(); }
template <class Archive>
void serialize(Archive& ar, unsigned version) {
(void)version;
ar& make_nvp("container", container_);
}
private:
container_type container_;
};
} // namespace accumulators
} // namespace histogram
} // namespace boost
#endif