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