]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/histogram/axis/category.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / histogram / axis / category.hpp
1 // Copyright 2015-2018 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_AXIS_CATEGORY_HPP
8 #define BOOST_HISTOGRAM_AXIS_CATEGORY_HPP
9
10 #include <algorithm>
11 #include <boost/core/nvp.hpp>
12 #include <boost/histogram/axis/iterator.hpp>
13 #include <boost/histogram/axis/metadata_base.hpp>
14 #include <boost/histogram/axis/option.hpp>
15 #include <boost/histogram/detail/detect.hpp>
16 #include <boost/histogram/detail/relaxed_equal.hpp>
17 #include <boost/histogram/fwd.hpp>
18 #include <boost/throw_exception.hpp>
19 #include <stdexcept>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 #include <vector>
24
25 namespace boost {
26 namespace histogram {
27 namespace axis {
28
29 /** Maps at a set of unique values to bin indices.
30
31 The axis maps a set of values to bins, following the order of arguments in the
32 constructor. The optional overflow bin for this axis counts input values that
33 are not part of the set. Binning has O(N) complexity, but with a very small
34 factor. For small N (the typical use case) it beats other kinds of lookup.
35
36 @tparam Value input value type, must be equal-comparable.
37 @tparam MetaData type to store meta data.
38 @tparam Options see boost::histogram::axis::option.
39 @tparam Allocator allocator to use for dynamic memory management.
40
41 The options `underflow` and `circular` are not allowed. The options `growth`
42 and `overflow` are mutually exclusive.
43 */
44 template <class Value, class MetaData, class Options, class Allocator>
45 class category : public iterator_mixin<category<Value, MetaData, Options, Allocator>>,
46 public metadata_base_t<MetaData> {
47 // these must be private, so that they are not automatically inherited
48 using value_type = Value;
49 using metadata_base = metadata_base_t<MetaData>;
50 using metadata_type = typename metadata_base::metadata_type;
51 using options_type = detail::replace_default<Options, option::overflow_t>;
52 using allocator_type = Allocator;
53 using vector_type = std::vector<value_type, allocator_type>;
54
55 static_assert(!options_type::test(option::underflow),
56 "category axis cannot have underflow");
57 static_assert(!options_type::test(option::circular),
58 "category axis cannot be circular");
59 static_assert(!(options_type::test(option::growth) &&
60 options_type::test(option::overflow)),
61 "growing category axis cannot have entries in overflow bin");
62
63 public:
64 constexpr category() = default;
65 explicit category(allocator_type alloc) : vec_(alloc) {}
66
67 /** Construct from iterator range of unique values.
68
69 @param begin begin of category range of unique values.
70 @param end end of category range of unique values.
71 @param meta description of the axis (optional).
72 @param options see boost::histogram::axis::option (optional).
73 @param alloc allocator instance to use (optional).
74 */
75 template <class It, class = detail::requires_iterator<It>>
76 category(It begin, It end, metadata_type meta = {}, options_type options = {},
77 allocator_type alloc = {})
78 : metadata_base(std::move(meta)), vec_(alloc) {
79 (void)options;
80 if (std::distance(begin, end) < 0)
81 BOOST_THROW_EXCEPTION(
82 std::invalid_argument("end must be reachable by incrementing begin"));
83 vec_.reserve(std::distance(begin, end));
84 while (begin != end) vec_.emplace_back(*begin++);
85 }
86
87 // kept for backward compatibility
88 template <class It, class = detail::requires_iterator<It>>
89 category(It begin, It end, metadata_type meta, allocator_type alloc)
90 : category(begin, end, std::move(meta), {}, std::move(alloc)) {}
91
92 /** Construct axis from iterable sequence of unique values.
93
94 @param iterable sequence of unique values.
95 @param meta description of the axis.
96 @param options see boost::histogram::axis::option (optional).
97 @param alloc allocator instance to use.
98 */
99 template <class C, class = detail::requires_iterable<C>>
100 category(const C& iterable, metadata_type meta = {}, options_type options = {},
101 allocator_type alloc = {})
102 : category(std::begin(iterable), std::end(iterable), std::move(meta), options,
103 std::move(alloc)) {}
104
105 // kept for backward compatibility
106 template <class C, class = detail::requires_iterable<C>>
107 category(const C& iterable, metadata_type meta, allocator_type alloc)
108 : category(std::begin(iterable), std::end(iterable), std::move(meta), {},
109 std::move(alloc)) {}
110
111 /** Construct axis from an initializer list of unique values.
112
113 @param list `std::initializer_list` of unique values.
114 @param meta description of the axis.
115 @param options see boost::histogram::axis::option (optional).
116 @param alloc allocator instance to use.
117 */
118 template <class U>
119 category(std::initializer_list<U> list, metadata_type meta = {},
120 options_type options = {}, allocator_type alloc = {})
121 : category(list.begin(), list.end(), std::move(meta), options, std::move(alloc)) {}
122
123 // kept for backward compatibility
124 template <class U>
125 category(std::initializer_list<U> list, metadata_type meta, allocator_type alloc)
126 : category(list.begin(), list.end(), std::move(meta), {}, std::move(alloc)) {}
127
128 /// Constructor used by algorithm::reduce to shrink and rebin (not for users).
129 category(const category& src, index_type begin, index_type end, unsigned merge)
130 // LCOV_EXCL_START: gcc-8 is missing the delegated ctor for no reason
131 : category(src.vec_.begin() + begin, src.vec_.begin() + end, src.metadata(), {},
132 src.get_allocator())
133 // LCOV_EXCL_STOP
134 {
135 if (merge > 1)
136 BOOST_THROW_EXCEPTION(std::invalid_argument("cannot merge bins for category axis"));
137 }
138
139 /// Return index for value argument.
140 index_type index(const value_type& x) const noexcept {
141 const auto beg = vec_.begin();
142 const auto end = vec_.end();
143 return static_cast<index_type>(std::distance(beg, std::find(beg, end, x)));
144 }
145
146 /// Returns index and shift (if axis has grown) for the passed argument.
147 std::pair<index_type, index_type> update(const value_type& x) {
148 const auto i = index(x);
149 if (i < size()) return {i, 0};
150 vec_.emplace_back(x);
151 return {i, -1};
152 }
153
154 /// Return value for index argument.
155 /// Throws `std::out_of_range` if the index is out of bounds.
156 auto value(index_type idx) const
157 -> std::conditional_t<std::is_scalar<value_type>::value, value_type,
158 const value_type&> {
159 if (idx < 0 || idx >= size())
160 BOOST_THROW_EXCEPTION(std::out_of_range("category index out of range"));
161 return vec_[idx];
162 }
163
164 /// Return value for index argument; alias for value(...).
165 decltype(auto) bin(index_type idx) const { return value(idx); }
166
167 /// Returns the number of bins, without over- or underflow.
168 index_type size() const noexcept { return static_cast<index_type>(vec_.size()); }
169
170 /// Returns the options.
171 static constexpr unsigned options() noexcept { return options_type::value; }
172
173 /// Whether the axis is inclusive (see axis::traits::is_inclusive).
174 static constexpr bool inclusive() noexcept {
175 return options() & (option::overflow | option::growth);
176 }
177
178 /// Indicate that the axis is not ordered.
179 static constexpr bool ordered() noexcept { return false; }
180
181 template <class V, class M, class O, class A>
182 bool operator==(const category<V, M, O, A>& o) const noexcept {
183 const auto& a = vec_;
184 const auto& b = o.vec_;
185 return std::equal(a.begin(), a.end(), b.begin(), b.end(), detail::relaxed_equal{}) &&
186 detail::relaxed_equal{}(this->metadata(), o.metadata());
187 }
188
189 template <class V, class M, class O, class A>
190 bool operator!=(const category<V, M, O, A>& o) const noexcept {
191 return !operator==(o);
192 }
193
194 allocator_type get_allocator() const { return vec_.get_allocator(); }
195
196 template <class Archive>
197 void serialize(Archive& ar, unsigned /* version */) {
198 ar& make_nvp("seq", vec_);
199 ar& make_nvp("meta", this->metadata());
200 }
201
202 private:
203 vector_type vec_;
204
205 template <class V, class M, class O, class A>
206 friend class category;
207 };
208
209 #if __cpp_deduction_guides >= 201606
210
211 template <class T>
212 category(std::initializer_list<T>)
213 -> category<detail::replace_cstring<std::decay_t<T>>, null_type>;
214
215 template <class T, class M>
216 category(std::initializer_list<T>, M)
217 -> category<detail::replace_cstring<std::decay_t<T>>,
218 detail::replace_cstring<std::decay_t<M>>>;
219
220 template <class T, class M, unsigned B>
221 category(std::initializer_list<T>, M, const option::bitset<B>&)
222 -> category<detail::replace_cstring<std::decay_t<T>>,
223 detail::replace_cstring<std::decay_t<M>>, option::bitset<B>>;
224
225 #endif
226
227 } // namespace axis
228 } // namespace histogram
229 } // namespace boost
230
231 #endif