]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/histogram/storage_adaptor.hpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / boost / histogram / storage_adaptor.hpp
CommitLineData
92f5a8d4
TL
1// Copyright 2018-2019 Hans Dembinski
2//
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt
5// or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_HISTOGRAM_STORAGE_ADAPTOR_HPP
8#define BOOST_HISTOGRAM_STORAGE_ADAPTOR_HPP
9
10#include <algorithm>
11#include <boost/core/nvp.hpp>
12#include <boost/histogram/detail/array_wrapper.hpp>
13#include <boost/histogram/detail/detect.hpp>
14#include <boost/histogram/detail/iterator_adaptor.hpp>
15#include <boost/histogram/detail/safe_comparison.hpp>
16#include <boost/histogram/fwd.hpp>
17#include <boost/mp11/utility.hpp>
18#include <boost/throw_exception.hpp>
19#include <stdexcept>
20#include <type_traits>
21
22namespace boost {
23namespace histogram {
24namespace detail {
25
26template <class T>
27struct vector_impl : T {
28 using allocator_type = typename T::allocator_type;
29
30 static constexpr bool has_threading_support =
31 accumulators::is_thread_safe<typename T::value_type>::value;
32
33 vector_impl(const allocator_type& a = {}) : T(a) {}
34 vector_impl(const vector_impl&) = default;
35 vector_impl& operator=(const vector_impl&) = default;
36 vector_impl(vector_impl&&) = default;
37 vector_impl& operator=(vector_impl&&) = default;
38
39 explicit vector_impl(T&& t) : T(std::move(t)) {}
40 explicit vector_impl(const T& t) : T(t) {}
41
42 template <class U, class = requires_iterable<U>>
43 explicit vector_impl(const U& u, const allocator_type& a = {})
44 : T(std::begin(u), std::end(u), a) {}
45
46 template <class U, class = requires_iterable<U>>
47 vector_impl& operator=(const U& u) {
48 T::resize(u.size());
49 auto it = T::begin();
50 for (auto&& x : u) *it++ = x;
51 return *this;
52 }
53
54 void reset(std::size_t n) {
55 using value_type = typename T::value_type;
56 const auto old_size = T::size();
57 T::resize(n, value_type());
58 std::fill_n(T::begin(), (std::min)(n, old_size), value_type());
59 }
60
61 template <class Archive>
62 void serialize(Archive& ar, unsigned /* version */) {
63 ar& make_nvp("vector", static_cast<T&>(*this));
64 }
65};
66
67template <class T>
68struct array_impl : T {
69 static constexpr bool has_threading_support =
70 accumulators::is_thread_safe<typename T::value_type>::value;
71
72 array_impl() = default;
73 array_impl(const array_impl& t) : T(t), size_(t.size_) {}
74 array_impl& operator=(const array_impl& t) {
75 T::operator=(t);
76 size_ = t.size_;
77 return *this;
78 }
79
80 explicit array_impl(T&& t) : T(std::move(t)) {}
81 explicit array_impl(const T& t) : T(t) {}
82
83 template <class U, class = requires_iterable<U>>
84 explicit array_impl(const U& u) : size_(u.size()) {
85 using std::begin;
86 using std::end;
87 std::copy(begin(u), end(u), this->begin());
88 }
89
90 template <class U, class = requires_iterable<U>>
91 array_impl& operator=(const U& u) {
92 if (u.size() > T::max_size()) // for std::arra
93 BOOST_THROW_EXCEPTION(std::length_error("argument size exceeds maximum capacity"));
94 size_ = u.size();
95 using std::begin;
96 using std::end;
97 std::copy(begin(u), end(u), T::begin());
98 return *this;
99 }
100
101 void reset(std::size_t n) {
102 using value_type = typename T::value_type;
103 if (n > T::max_size()) // for std::array
104 BOOST_THROW_EXCEPTION(std::length_error("argument size exceeds maximum capacity"));
105 std::fill_n(T::begin(), n, value_type());
106 size_ = n;
107 }
108
109 typename T::iterator end() noexcept { return T::begin() + size_; }
110 typename T::const_iterator end() const noexcept { return T::begin() + size_; }
111
112 std::size_t size() const noexcept { return size_; }
113
114 template <class Archive>
115 void serialize(Archive& ar, unsigned /* version */) {
116 ar& make_nvp("size", size_);
117 auto w = detail::make_array_wrapper(T::data(), size_);
118 ar& make_nvp("array", w);
119 }
120
121 std::size_t size_ = 0;
122};
123
124template <class T>
125struct map_impl : T {
126 static_assert(std::is_same<typename T::key_type, std::size_t>::value,
127 "requires std::size_t as key_type");
128
129 using value_type = typename T::mapped_type;
130 using const_reference = const value_type&;
131
132 static constexpr bool has_threading_support = false;
133 static_assert(
134 !accumulators::is_thread_safe<value_type>::value,
135 "std::map and std::unordered_map do not support thread-safe element access. "
136 "If you have a map with thread-safe element access, please file an issue and"
137 "support will be added.");
138
139 struct reference {
140 reference(map_impl* m, std::size_t i) noexcept : map(m), idx(i) {}
141
142 reference(const reference&) noexcept = default;
143 reference& operator=(const reference& o) {
144 if (this != &o) operator=(static_cast<const_reference>(o));
145 return *this;
146 }
147
148 operator const_reference() const noexcept {
149 return static_cast<const map_impl*>(map)->operator[](idx);
150 }
151
152 reference& operator=(const_reference u) {
153 auto it = map->find(idx);
154 if (u == value_type{}) {
155 if (it != static_cast<T*>(map)->end()) { map->erase(it); }
156 } else {
157 if (it != static_cast<T*>(map)->end()) {
158 it->second = u;
159 } else {
160 map->emplace(idx, u);
161 }
162 }
163 return *this;
164 }
165
166 template <class U, class V = value_type,
167 class = std::enable_if_t<has_operator_radd<V, U>::value>>
168 reference& operator+=(const U& u) {
169 auto it = map->find(idx);
170 if (it != static_cast<T*>(map)->end()) {
171 it->second += u;
172 } else {
173 map->emplace(idx, u);
174 }
175 return *this;
176 }
177
178 template <class U, class V = value_type,
179 class = std::enable_if_t<has_operator_rsub<V, U>::value>>
180 reference& operator-=(const U& u) {
181 auto it = map->find(idx);
182 if (it != static_cast<T*>(map)->end()) {
183 it->second -= u;
184 } else {
185 map->emplace(idx, -u);
186 }
187 return *this;
188 }
189
190 template <class U, class V = value_type,
191 class = std::enable_if_t<has_operator_rmul<V, U>::value>>
192 reference& operator*=(const U& u) {
193 auto it = map->find(idx);
194 if (it != static_cast<T*>(map)->end()) it->second *= u;
195 return *this;
196 }
197
198 template <class U, class V = value_type,
199 class = std::enable_if_t<has_operator_rdiv<V, U>::value>>
200 reference& operator/=(const U& u) {
201 auto it = map->find(idx);
202 if (it != static_cast<T*>(map)->end()) {
203 it->second /= u;
204 } else if (!(value_type{} / u == value_type{})) {
205 map->emplace(idx, value_type{} / u);
206 }
207 return *this;
208 }
209
210 template <class V = value_type,
211 class = std::enable_if_t<has_operator_preincrement<V>::value>>
212 reference operator++() {
213 auto it = map->find(idx);
214 if (it != static_cast<T*>(map)->end()) {
215 ++it->second;
216 } else {
217 value_type tmp{};
218 ++tmp;
219 map->emplace(idx, tmp);
220 }
221 return *this;
222 }
223
224 template <class V = value_type,
225 class = std::enable_if_t<has_operator_preincrement<V>::value>>
226 value_type operator++(int) {
227 const value_type tmp = *this;
228 operator++();
229 return tmp;
230 }
231
232 template <class U, class = std::enable_if_t<has_operator_equal<value_type, U>::value>>
233 bool operator==(const U& rhs) const {
234 return operator const_reference() == rhs;
235 }
236
237 template <class U, class = std::enable_if_t<has_operator_equal<value_type, U>::value>>
238 bool operator!=(const U& rhs) const {
239 return !operator==(rhs);
240 }
241
f67539c2 242 template <class CharT, class Traits>
92f5a8d4
TL
243 friend std::basic_ostream<CharT, Traits>& operator<<(
244 std::basic_ostream<CharT, Traits>& os, reference x) {
245 os << static_cast<const_reference>(x);
246 return os;
247 }
248
249 template <class... Ts>
f67539c2
TL
250 auto operator()(const Ts&... args) -> decltype(std::declval<value_type>()(args...)) {
251 return (*map)[idx](args...);
92f5a8d4
TL
252 }
253
254 map_impl* map;
255 std::size_t idx;
256 };
257
258 template <class Value, class Reference, class MapPtr>
259 struct iterator_t
260 : iterator_adaptor<iterator_t<Value, Reference, MapPtr>, std::size_t, Reference> {
261 iterator_t() = default;
262 template <class V, class R, class M, class = requires_convertible<M, MapPtr>>
263 iterator_t(const iterator_t<V, R, M>& it) noexcept : iterator_t(it.map_, it.base()) {}
264 iterator_t(MapPtr m, std::size_t i) noexcept
265 : iterator_t::iterator_adaptor_(i), map_(m) {}
266 template <class V, class R, class M>
267 bool equal(const iterator_t<V, R, M>& rhs) const noexcept {
268 return map_ == rhs.map_ && iterator_t::base() == rhs.base();
269 }
270 Reference operator*() const { return (*map_)[iterator_t::base()]; }
271 MapPtr map_ = nullptr;
272 };
273
274 using iterator = iterator_t<value_type, reference, map_impl*>;
275 using const_iterator = iterator_t<const value_type, const_reference, const map_impl*>;
276
277 using allocator_type = typename T::allocator_type;
278
279 map_impl(const allocator_type& a = {}) : T(a) {}
280
281 map_impl(const map_impl&) = default;
282 map_impl& operator=(const map_impl&) = default;
283 map_impl(map_impl&&) = default;
284 map_impl& operator=(map_impl&&) = default;
285
286 map_impl(const T& t) : T(t), size_(t.size()) {}
287 map_impl(T&& t) : T(std::move(t)), size_(t.size()) {}
288
289 template <class U, class = requires_iterable<U>>
290 explicit map_impl(const U& u, const allocator_type& a = {}) : T(a), size_(u.size()) {
291 using std::begin;
292 using std::end;
293 std::copy(begin(u), end(u), this->begin());
294 }
295
296 template <class U, class = requires_iterable<U>>
297 map_impl& operator=(const U& u) {
298 if (u.size() < size_)
299 reset(u.size());
300 else
301 size_ = u.size();
302 using std::begin;
303 using std::end;
304 std::copy(begin(u), end(u), this->begin());
305 return *this;
306 }
307
308 void reset(std::size_t n) {
309 T::clear();
310 size_ = n;
311 }
312
313 reference operator[](std::size_t i) noexcept { return {this, i}; }
314 const_reference operator[](std::size_t i) const noexcept {
315 auto it = T::find(i);
316 static const value_type null = value_type{};
317 if (it == T::end()) return null;
318 return it->second;
319 }
320
321 iterator begin() noexcept { return {this, 0}; }
322 iterator end() noexcept { return {this, size_}; }
323
324 const_iterator begin() const noexcept { return {this, 0}; }
325 const_iterator end() const noexcept { return {this, size_}; }
326
327 std::size_t size() const noexcept { return size_; }
328
329 template <class Archive>
330 void serialize(Archive& ar, unsigned /* version */) {
331 ar& make_nvp("size", size_);
332 ar& make_nvp("map", static_cast<T&>(*this));
333 }
334
335 std::size_t size_ = 0;
336};
337
338template <class T>
339struct ERROR_type_passed_to_storage_adaptor_not_recognized;
340
341// clang-format off
342template <class T>
343using storage_adaptor_impl =
344 mp11::mp_cond<
345 is_vector_like<T>, vector_impl<T>,
346 is_array_like<T>, array_impl<T>,
347 is_map_like<T>, map_impl<T>,
348 std::true_type, ERROR_type_passed_to_storage_adaptor_not_recognized<T>
349 >;
350// clang-format on
351} // namespace detail
352
353/// Turns any vector-like, array-like, and map-like container into a storage type.
354template <class T>
355class storage_adaptor : public detail::storage_adaptor_impl<T> {
356 using impl_type = detail::storage_adaptor_impl<T>;
357
358public:
359 // standard copy, move, assign
360 storage_adaptor(storage_adaptor&&) = default;
361 storage_adaptor(const storage_adaptor&) = default;
362 storage_adaptor& operator=(storage_adaptor&&) = default;
363 storage_adaptor& operator=(const storage_adaptor&) = default;
364
365 // forwarding constructor
366 template <class... Ts>
367 storage_adaptor(Ts&&... ts) : impl_type(std::forward<Ts>(ts)...) {}
368
369 // forwarding assign
370 template <class U>
371 storage_adaptor& operator=(U&& u) {
372 impl_type::operator=(std::forward<U>(u));
373 return *this;
374 }
375
376 template <class U, class = detail::requires_iterable<U>>
377 bool operator==(const U& u) const {
378 using std::begin;
379 using std::end;
380 return std::equal(this->begin(), this->end(), begin(u), end(u), detail::safe_equal{});
381 }
382
383 template <class Archive>
384 void serialize(Archive& ar, unsigned /* version */) {
385 ar& make_nvp("impl", static_cast<impl_type&>(*this));
386 }
387
388private:
389 friend struct unsafe_access;
390};
391
392} // namespace histogram
393} // namespace boost
394
395#endif