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