]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/histogram/axis/integer.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / histogram / axis / integer.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_INTEGER_HPP
8#define BOOST_HISTOGRAM_AXIS_INTEGER_HPP
9
10#include <boost/core/nvp.hpp>
11#include <boost/histogram/axis/iterator.hpp>
12#include <boost/histogram/axis/metadata_base.hpp>
13#include <boost/histogram/axis/option.hpp>
14#include <boost/histogram/detail/convert_integer.hpp>
15#include <boost/histogram/detail/limits.hpp>
20effc67 16#include <boost/histogram/detail/relaxed_equal.hpp>
92f5a8d4
TL
17#include <boost/histogram/detail/replace_type.hpp>
18#include <boost/histogram/detail/static_if.hpp>
19#include <boost/histogram/fwd.hpp>
20#include <boost/throw_exception.hpp>
21#include <cmath>
22#include <limits>
23#include <stdexcept>
24#include <string>
25#include <type_traits>
26#include <utility>
27
28namespace boost {
29namespace histogram {
30namespace axis {
31
1e59de90 32/** Axis for an interval of integer values with unit steps.
92f5a8d4 33
1e59de90 34 Binning is a O(1) operation. This axis bins faster than a regular axis.
92f5a8d4 35
1e59de90
TL
36 @tparam Value input value type. Must be integer or floating point.
37 @tparam MetaData type to store meta data.
38 @tparam Options see boost::histogram::axis::option.
92f5a8d4
TL
39 */
40template <class Value, class MetaData, class Options>
41class integer : public iterator_mixin<integer<Value, MetaData, Options>>,
20effc67 42 public metadata_base_t<MetaData> {
f67539c2 43 // these must be private, so that they are not automatically inherited
92f5a8d4 44 using value_type = Value;
20effc67
TL
45 using metadata_base = metadata_base_t<MetaData>;
46 using metadata_type = typename metadata_base::metadata_type;
92f5a8d4
TL
47 using options_type =
48 detail::replace_default<Options, decltype(option::underflow | option::overflow)>;
49
f67539c2
TL
50 static_assert(std::is_integral<value_type>::value ||
51 std::is_floating_point<value_type>::value,
52 "integer axis requires floating point or integral type");
53
92f5a8d4
TL
54 static_assert(!options_type::test(option::circular | option::growth) ||
55 (options_type::test(option::circular) ^
56 options_type::test(option::growth)),
57 "circular and growth options are mutually exclusive");
58
59 static_assert(std::is_floating_point<value_type>::value ||
60 (!options_type::test(option::circular) &&
61 !options_type::test(option::growth)) ||
62 (!options_type::test(option::overflow) &&
63 !options_type::test(option::underflow)),
64 "circular or growing integer axis with integral type "
65 "cannot have entries in underflow or overflow bins");
66
f67539c2
TL
67 using local_index_type = std::conditional_t<std::is_integral<value_type>::value,
68 index_type, real_index_type>;
69
92f5a8d4
TL
70public:
71 constexpr integer() = default;
72
73 /** Construct over semi-open integer interval [start, stop).
1e59de90
TL
74
75 @param start first integer of covered range.
76 @param stop one past last integer of covered range.
77 @param meta description of the axis (optional).
78 @param options see boost::histogram::axis::option (optional).
92f5a8d4 79 */
1e59de90
TL
80 integer(value_type start, value_type stop, metadata_type meta = {},
81 options_type options = {})
20effc67 82 : metadata_base(std::move(meta))
92f5a8d4
TL
83 , size_(static_cast<index_type>(stop - start))
84 , min_(start) {
1e59de90 85 (void)options;
92f5a8d4
TL
86 if (!(stop >= start))
87 BOOST_THROW_EXCEPTION(std::invalid_argument("stop >= start required"));
88 }
89
90 /// Constructor used by algorithm::reduce to shrink and rebin.
91 integer(const integer& src, index_type begin, index_type end, unsigned merge)
92 : integer(src.value(begin), src.value(end), src.metadata()) {
93 if (merge > 1)
94 BOOST_THROW_EXCEPTION(std::invalid_argument("cannot merge bins for integer axis"));
95 if (options_type::test(option::circular) && !(begin == 0 && end == src.size()))
96 BOOST_THROW_EXCEPTION(std::invalid_argument("cannot shrink circular axis"));
97 }
98
99 /// Return index for value argument.
100 index_type index(value_type x) const noexcept {
20effc67
TL
101 return index_impl(options_type::test(axis::option::circular),
102 std::is_floating_point<value_type>{},
103 static_cast<double>(x - min_));
92f5a8d4
TL
104 }
105
106 /// Returns index and shift (if axis has grown) for the passed argument.
107 auto update(value_type x) noexcept {
f67539c2 108 auto impl = [this](long x) -> std::pair<index_type, index_type> {
92f5a8d4
TL
109 const auto i = x - min_;
110 if (i >= 0) {
111 const auto k = static_cast<axis::index_type>(i);
f67539c2 112 if (k < size()) return {k, 0};
92f5a8d4
TL
113 const auto n = k - size() + 1;
114 size_ += n;
f67539c2 115 return {k, -n};
92f5a8d4
TL
116 }
117 const auto k = static_cast<axis::index_type>(
118 detail::static_if<std::is_floating_point<value_type>>(
119 [](auto x) { return std::floor(x); }, [](auto x) { return x; }, i));
120 min_ += k;
121 size_ -= k;
f67539c2 122 return {0, -k};
92f5a8d4
TL
123 };
124
125 return detail::static_if<std::is_floating_point<value_type>>(
f67539c2 126 [this, impl](auto x) -> std::pair<index_type, index_type> {
92f5a8d4 127 if (std::isfinite(x)) return impl(static_cast<long>(std::floor(x)));
f67539c2 128 return {x < 0 ? -1 : this->size(), 0};
92f5a8d4
TL
129 },
130 impl, x);
131 }
132
133 /// Return value for index argument.
134 value_type value(local_index_type i) const noexcept {
135 if (!options_type::test(option::circular) &&
136 std::is_floating_point<value_type>::value) {
137 if (i < 0) return detail::lowest<value_type>();
138 if (i > size()) return detail::highest<value_type>();
139 }
140 return min_ + i;
141 }
142
143 /// Return bin for index argument.
144 decltype(auto) bin(index_type idx) const noexcept {
145 return detail::static_if<std::is_floating_point<value_type>>(
146 [this](auto idx) { return interval_view<integer>(*this, idx); },
147 [this](auto idx) { return this->value(idx); }, idx);
148 }
149
150 /// Returns the number of bins, without over- or underflow.
151 index_type size() const noexcept { return size_; }
152
153 /// Returns the options.
154 static constexpr unsigned options() noexcept { return options_type::value; }
155
156 /// Whether the axis is inclusive (see axis::traits::is_inclusive).
157 static constexpr bool inclusive() noexcept {
1e59de90
TL
158 // If axis has underflow and overflow, it is inclusive.
159 // If axis is growing or circular:
160 // - it is inclusive if value_type is int.
161 // - it is not inclusive if value_type is float, because of nan and inf.
162 constexpr bool full_flow =
163 options() & option::underflow && options() & option::overflow;
164 return full_flow || (std::is_integral<value_type>::value &&
165 (options() & (option::growth | option::circular)));
92f5a8d4
TL
166 }
167
168 template <class V, class M, class O>
169 bool operator==(const integer<V, M, O>& o) const noexcept {
20effc67
TL
170 return size() == o.size() && min_ == o.min_ &&
171 detail::relaxed_equal{}(this->metadata(), o.metadata());
92f5a8d4
TL
172 }
173
174 template <class V, class M, class O>
175 bool operator!=(const integer<V, M, O>& o) const noexcept {
176 return !operator==(o);
177 }
178
179 template <class Archive>
180 void serialize(Archive& ar, unsigned /* version */) {
181 ar& make_nvp("size", size_);
182 ar& make_nvp("meta", this->metadata());
183 ar& make_nvp("min", min_);
184 }
185
186private:
20effc67
TL
187 // axis not circular
188 template <class B>
189 index_type index_impl(std::false_type, B, double z) const noexcept {
190 if (z < size()) return z >= 0 ? static_cast<index_type>(z) : -1;
191 return size();
192 }
193
194 // value_type is integer, axis circular
195 index_type index_impl(std::true_type, std::false_type, double z) const noexcept {
196 return static_cast<index_type>(z - std::floor(z / size()) * size());
197 }
198
199 // value_type is floating point, must handle +/-infinite or nan, axis circular
200 index_type index_impl(std::true_type, std::true_type, double z) const noexcept {
201 if (std::isfinite(z)) return index_impl(std::true_type{}, std::false_type{}, z);
202 return z < size() ? -1 : size();
203 }
204
92f5a8d4
TL
205 index_type size_{0};
206 value_type min_{0};
207
208 template <class V, class M, class O>
209 friend class integer;
210};
211
212#if __cpp_deduction_guides >= 201606
213
214template <class T>
1e59de90 215integer(T, T) -> integer<detail::convert_integer<T, index_type>, null_type>;
92f5a8d4
TL
216
217template <class T, class M>
218integer(T, T, M)
1e59de90
TL
219 -> integer<detail::convert_integer<T, index_type>,
220 detail::replace_type<std::decay_t<M>, const char*, std::string>>;
221
222template <class T, class M, unsigned B>
223integer(T, T, M, const option::bitset<B>&)
224 -> integer<detail::convert_integer<T, index_type>,
225 detail::replace_type<std::decay_t<M>, const char*, std::string>,
226 option::bitset<B>>;
92f5a8d4
TL
227
228#endif
229
230} // namespace axis
231} // namespace histogram
232} // namespace boost
233
234#endif