/usr/include/boost/histogram
Edit: /usr/include/boost/histogram/storage_adaptor.hpp (12171B)
// Copyright 2018-2019 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_STORAGE_ADAPTOR_HPP
#define BOOST_HISTOGRAM_STORAGE_ADAPTOR_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace boost {
namespace histogram {
namespace detail {
template
struct vector_impl : T {
using allocator_type = typename T::allocator_type;
static constexpr bool has_threading_support =
accumulators::is_thread_safe::value;
vector_impl(const allocator_type& a = {}) : T(a) {}
vector_impl(const vector_impl&) = default;
vector_impl& operator=(const vector_impl&) = default;
vector_impl(vector_impl&&) = default;
vector_impl& operator=(vector_impl&&) = default;
explicit vector_impl(T&& t) : T(std::move(t)) {}
explicit vector_impl(const T& t) : T(t) {}
template >
explicit vector_impl(const U& u, const allocator_type& a = {})
: T(std::begin(u), std::end(u), a) {}
template >
vector_impl& operator=(const U& u) {
T::resize(u.size());
auto it = T::begin();
for (auto&& x : u) *it++ = x;
return *this;
}
void reset(std::size_t n) {
using value_type = typename T::value_type;
const auto old_size = T::size();
T::resize(n, value_type());
std::fill_n(T::begin(), (std::min)(n, old_size), value_type());
}
template
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("vector", static_cast(*this));
}
};
template
struct array_impl : T {
static constexpr bool has_threading_support =
accumulators::is_thread_safe::value;
array_impl() = default;
array_impl(const array_impl& t) : T(t), size_(t.size_) {}
array_impl& operator=(const array_impl& t) {
T::operator=(t);
size_ = t.size_;
return *this;
}
explicit array_impl(T&& t) : T(std::move(t)) {}
explicit array_impl(const T& t) : T(t) {}
template >
explicit array_impl(const U& u) : size_(u.size()) {
using std::begin;
using std::end;
std::copy(begin(u), end(u), this->begin());
}
template >
array_impl& operator=(const U& u) {
if (u.size() > T::max_size()) // for std::arra
BOOST_THROW_EXCEPTION(std::length_error("argument size exceeds maximum capacity"));
size_ = u.size();
using std::begin;
using std::end;
std::copy(begin(u), end(u), T::begin());
return *this;
}
void reset(std::size_t n) {
using value_type = typename T::value_type;
if (n > T::max_size()) // for std::array
BOOST_THROW_EXCEPTION(std::length_error("argument size exceeds maximum capacity"));
std::fill_n(T::begin(), n, value_type());
size_ = n;
}
typename T::iterator end() noexcept { return T::begin() + size_; }
typename T::const_iterator end() const noexcept { return T::begin() + size_; }
std::size_t size() const noexcept { return size_; }
template
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("size", size_);
auto w = detail::make_array_wrapper(T::data(), size_);
ar& make_nvp("array", w);
}
std::size_t size_ = 0;
};
template
struct map_impl : T {
static_assert(std::is_same::value,
"requires std::size_t as key_type");
using value_type = typename T::mapped_type;
using const_reference = const value_type&;
static constexpr bool has_threading_support = false;
static_assert(
!accumulators::is_thread_safe::value,
"std::map and std::unordered_map do not support thread-safe element access. "
"If you have a map with thread-safe element access, please file an issue and"
"support will be added.");
struct reference {
reference(map_impl* m, std::size_t i) noexcept : map(m), idx(i) {}
reference(const reference&) noexcept = default;
reference& operator=(const reference& o) {
if (this != &o) operator=(static_cast(o));
return *this;
}
operator const_reference() const noexcept {
return static_cast(map)->operator[](idx);
}
reference& operator=(const_reference u) {
auto it = map->find(idx);
if (u == value_type{}) {
if (it != static_cast(map)->end()) { map->erase(it); }
} else {
if (it != static_cast(map)->end()) {
it->second = u;
} else {
map->emplace(idx, u);
}
}
return *this;
}
template ::value>>
reference& operator+=(const U& u) {
auto it = map->find(idx);
if (it != static_cast(map)->end()) {
it->second += u;
} else {
map->emplace(idx, u);
}
return *this;
}
template ::value>>
reference& operator-=(const U& u) {
auto it = map->find(idx);
if (it != static_cast(map)->end()) {
it->second -= u;
} else {
map->emplace(idx, -u);
}
return *this;
}
template ::value>>
reference& operator*=(const U& u) {
auto it = map->find(idx);
if (it != static_cast(map)->end()) it->second *= u;
return *this;
}
template ::value>>
reference& operator/=(const U& u) {
auto it = map->find(idx);
if (it != static_cast(map)->end()) {
it->second /= u;
} else if (!(value_type{} / u == value_type{})) {
map->emplace(idx, value_type{} / u);
}
return *this;
}
template ::value>>
reference operator++() {
auto it = map->find(idx);
if (it != static_cast(map)->end()) {
++it->second;
} else {
value_type tmp{};
++tmp;
map->emplace(idx, tmp);
}
return *this;
}
template ::value>>
value_type operator++(int) {
const value_type tmp = *this;
operator++();
return tmp;
}
template ::value>>
bool operator==(const U& rhs) const {
return operator const_reference() == rhs;
}
template ::value>>
bool operator!=(const U& rhs) const {
return !operator==(rhs);
}
template
friend std::basic_ostream& operator<<(
std::basic_ostream& os, reference x) {
os << static_cast(x);
return os;
}
template
auto operator()(const Ts&... args) -> decltype(std::declval()(args...)) {
return (*map)[idx](args...);
}
map_impl* map;
std::size_t idx;
};
template
struct iterator_t
: iterator_adaptor, std::size_t, Reference> {
iterator_t() = default;
template ::value>>
iterator_t(const iterator_t& it) noexcept : iterator_t(it.map_, it.base()) {}
iterator_t(MapPtr m, std::size_t i) noexcept
: iterator_t::iterator_adaptor_(i), map_(m) {}
template
bool equal(const iterator_t& rhs) const noexcept {
return map_ == rhs.map_ && iterator_t::base() == rhs.base();
}
Reference operator*() const { return (*map_)[iterator_t::base()]; }
MapPtr map_ = nullptr;
};
using iterator = iterator_t;
using const_iterator = iterator_t;
using allocator_type = typename T::allocator_type;
map_impl(const allocator_type& a = {}) : T(a) {}
map_impl(const map_impl&) = default;
map_impl& operator=(const map_impl&) = default;
map_impl(map_impl&&) = default;
map_impl& operator=(map_impl&&) = default;
map_impl(const T& t) : T(t), size_(t.size()) {}
map_impl(T&& t) : T(std::move(t)), size_(t.size()) {}
template >
explicit map_impl(const U& u, const allocator_type& a = {}) : T(a), size_(u.size()) {
using std::begin;
using std::end;
std::copy(begin(u), end(u), this->begin());
}
template >
map_impl& operator=(const U& u) {
if (u.size() < size_)
reset(u.size());
else
size_ = u.size();
using std::begin;
using std::end;
std::copy(begin(u), end(u), this->begin());
return *this;
}
void reset(std::size_t n) {
T::clear();
size_ = n;
}
reference operator[](std::size_t i) noexcept { return {this, i}; }
const_reference operator[](std::size_t i) const noexcept {
auto it = T::find(i);
static const value_type null = value_type{};
if (it == T::end()) return null;
return it->second;
}
iterator begin() noexcept { return {this, 0}; }
iterator end() noexcept { return {this, size_}; }
const_iterator begin() const noexcept { return {this, 0}; }
const_iterator end() const noexcept { return {this, size_}; }
std::size_t size() const noexcept { return size_; }
template
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("size", size_);
ar& make_nvp("map", static_cast(*this));
}
std::size_t size_ = 0;
};
template
struct ERROR_type_passed_to_storage_adaptor_not_recognized;
// clang-format off
template
using storage_adaptor_impl =
mp11::mp_cond<
is_vector_like, vector_impl,
is_array_like, array_impl,
is_map_like, map_impl,
std::true_type, ERROR_type_passed_to_storage_adaptor_not_recognized
>;
// clang-format on
} // namespace detail
/// Turns any vector-like, array-like, and map-like container into a storage type.
template
class storage_adaptor : public detail::storage_adaptor_impl {
using impl_type = detail::storage_adaptor_impl;
public:
// standard copy, move, assign
storage_adaptor(storage_adaptor&&) = default;
storage_adaptor(const storage_adaptor&) = default;
storage_adaptor& operator=(storage_adaptor&&) = default;
storage_adaptor& operator=(const storage_adaptor&) = default;
// forwarding constructor
template
storage_adaptor(Ts&&... ts) : impl_type(std::forward(ts)...) {}
// forwarding assign
template
storage_adaptor& operator=(U&& u) {
impl_type::operator=(std::forward(u));
return *this;
}
template >
bool operator==(const U& u) const {
using std::begin;
using std::end;
return std::equal(this->begin(), this->end(), begin(u), end(u), detail::safe_equal{});
}
template
void serialize(Archive& ar, unsigned /* version */) {
ar& make_nvp("impl", static_cast(*this));
}
private:
friend struct unsafe_access;
};
} // namespace histogram
} // namespace boost
#endif