update boost
This commit is contained in:
@@ -7,15 +7,21 @@
|
||||
#ifndef BOOST_HISTOGRAM_AXIS_INTEGER_HPP
|
||||
#define BOOST_HISTOGRAM_AXIS_INTEGER_HPP
|
||||
|
||||
#include <boost/core/nvp.hpp>
|
||||
#include <boost/histogram/axis/iterator.hpp>
|
||||
#include <boost/histogram/axis/metadata_base.hpp>
|
||||
#include <boost/histogram/axis/option.hpp>
|
||||
#include <boost/histogram/detail/compressed_pair.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/detail/convert_integer.hpp>
|
||||
#include <boost/histogram/detail/limits.hpp>
|
||||
#include <boost/histogram/detail/relaxed_equal.hpp>
|
||||
#include <boost/histogram/detail/replace_type.hpp>
|
||||
#include <boost/histogram/detail/static_if.hpp>
|
||||
#include <boost/histogram/fwd.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@@ -23,45 +29,68 @@ namespace boost {
|
||||
namespace histogram {
|
||||
namespace axis {
|
||||
|
||||
/**
|
||||
Axis for an interval of integer values with unit steps.
|
||||
/** Axis for an interval of integer values with unit steps.
|
||||
|
||||
Binning is a O(1) operation. This axis bins faster than a regular axis.
|
||||
Binning is a O(1) operation. This axis bins even faster than a regular axis.
|
||||
|
||||
@tparam Value input value type. Must be integer or floating point.
|
||||
@tparam MetaData type to store meta data.
|
||||
@tparam Options see boost::histogram::axis::option (all values allowed).
|
||||
The options `growth` and `circular` are mutually exclusive. If the axis uses
|
||||
integers and either `growth` or `circular` are set, the axis cannot have
|
||||
the options `underflow` or `overflow` set.
|
||||
|
||||
@tparam Value input value type. Must be integer or floating point.
|
||||
@tparam MetaData type to store meta data.
|
||||
@tparam Options see boost::histogram::axis::option.
|
||||
*/
|
||||
template <class Value, class MetaData, class Options>
|
||||
class integer : public iterator_mixin<integer<Value, MetaData, Options>> {
|
||||
static_assert(std::is_integral<Value>::value || std::is_floating_point<Value>::value,
|
||||
"integer axis requires type floating point or integral type");
|
||||
|
||||
class integer : public iterator_mixin<integer<Value, MetaData, Options>>,
|
||||
public metadata_base_t<MetaData> {
|
||||
// these must be private, so that they are not automatically inherited
|
||||
using value_type = Value;
|
||||
using local_index_type = std::conditional_t<std::is_integral<value_type>::value,
|
||||
index_type, real_index_type>;
|
||||
|
||||
using metadata_type = detail::replace_default<MetaData, std::string>;
|
||||
using metadata_base = metadata_base_t<MetaData>;
|
||||
using metadata_type = typename metadata_base::metadata_type;
|
||||
using options_type =
|
||||
detail::replace_default<Options, decltype(option::underflow | option::overflow)>;
|
||||
|
||||
static_assert(!options_type::test(option::circular) ||
|
||||
std::is_floating_point<value_type>::value ||
|
||||
!options_type::test(option::overflow),
|
||||
"integer axis with integral type cannot have overflow");
|
||||
using local_index_type = std::conditional_t<std::is_integral<value_type>::value,
|
||||
index_type, real_index_type>;
|
||||
|
||||
public:
|
||||
constexpr integer() = default;
|
||||
|
||||
/** Construct over semi-open integer interval [start, stop).
|
||||
*
|
||||
* \param start first integer of covered range.
|
||||
* \param stop one past last integer of covered range.
|
||||
* \param meta description of the axis.
|
||||
|
||||
@param start first integer of covered range.
|
||||
@param stop one past last integer of covered range.
|
||||
@param meta description of the axis (optional).
|
||||
@param options see boost::histogram::axis::option (optional).
|
||||
|
||||
The constructor throws `std::invalid_argument` if start is not less than stop.
|
||||
|
||||
The arguments meta and alloc are passed by value. If you move either of them into the
|
||||
axis and the constructor throws, their values are lost. Do not move if you cannot
|
||||
guarantee that the bin description is not valid.
|
||||
*/
|
||||
integer(value_type start, value_type stop, metadata_type meta = {})
|
||||
: size_meta_(static_cast<index_type>(stop - start), std::move(meta)), min_(start) {
|
||||
if (stop <= start) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required"));
|
||||
integer(value_type start, value_type stop, metadata_type meta = {},
|
||||
options_type options = {})
|
||||
: metadata_base(std::move(meta))
|
||||
, size_(static_cast<index_type>(stop - start))
|
||||
, min_(start) {
|
||||
static_assert(
|
||||
std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
|
||||
"integer axis requires floating point or integral type");
|
||||
|
||||
static_assert(!(options.test(option::circular) && options.test(option::growth)),
|
||||
"circular and growth options are mutually exclusive");
|
||||
|
||||
static_assert(
|
||||
std::is_floating_point<value_type>::value ||
|
||||
!((options.test(option::growth) || options.test(option::circular)) &&
|
||||
(options.test(option::overflow) || options.test(option::underflow))),
|
||||
"circular or growing integer axis with integral type "
|
||||
"cannot have entries in underflow or overflow bins");
|
||||
|
||||
if (!(stop >= start)) // double negation so it works with NaN
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("stop >= start required"));
|
||||
}
|
||||
|
||||
/// Constructor used by algorithm::reduce to shrink and rebin.
|
||||
@@ -75,66 +104,76 @@ public:
|
||||
|
||||
/// Return index for value argument.
|
||||
index_type index(value_type x) const noexcept {
|
||||
return index_impl(std::is_floating_point<value_type>(), x);
|
||||
return index_impl(options_type::test(axis::option::circular),
|
||||
std::is_floating_point<value_type>{},
|
||||
static_cast<double>(x - min_));
|
||||
}
|
||||
|
||||
/// Returns index and shift (if axis has grown) for the passed argument.
|
||||
auto update(value_type x) noexcept {
|
||||
auto impl = [this](long x) {
|
||||
auto impl = [this](long x) -> std::pair<index_type, index_type> {
|
||||
const auto i = x - min_;
|
||||
if (i >= 0) {
|
||||
const auto k = static_cast<axis::index_type>(i);
|
||||
if (k < size()) return std::make_pair(k, 0);
|
||||
if (k < size()) return {k, 0};
|
||||
const auto n = k - size() + 1;
|
||||
size_meta_.first() += n;
|
||||
return std::make_pair(k, -n);
|
||||
size_ += n;
|
||||
return {k, -n};
|
||||
}
|
||||
const auto k = static_cast<axis::index_type>(
|
||||
detail::static_if<std::is_floating_point<value_type>>(
|
||||
[](auto x) { return std::floor(x); }, [](auto x) { return x; }, i));
|
||||
min_ += k;
|
||||
size_meta_.first() -= k;
|
||||
return std::make_pair(0, -k);
|
||||
size_ -= k;
|
||||
return {0, -k};
|
||||
};
|
||||
|
||||
return detail::static_if<std::is_floating_point<value_type>>(
|
||||
[this, impl](auto x) {
|
||||
[this, impl](auto x) -> std::pair<index_type, index_type> {
|
||||
if (std::isfinite(x)) return impl(static_cast<long>(std::floor(x)));
|
||||
// this->size() is workaround for gcc-5 bug
|
||||
return std::make_pair(x < 0 ? -1 : this->size(), 0);
|
||||
return {x < 0 ? -1 : this->size(), 0};
|
||||
},
|
||||
impl, x);
|
||||
}
|
||||
|
||||
/// Return value for index argument.
|
||||
value_type value(local_index_type i) const noexcept {
|
||||
if (!options_type::test(option::circular)) {
|
||||
if (!options_type::test(option::circular) &&
|
||||
std::is_floating_point<value_type>::value) {
|
||||
if (i < 0) return detail::lowest<value_type>();
|
||||
if (i > size()) { return detail::highest<value_type>(); }
|
||||
if (i > size()) return detail::highest<value_type>();
|
||||
}
|
||||
return min_ + i;
|
||||
}
|
||||
|
||||
/// Return bin for index argument.
|
||||
decltype(auto) bin(index_type idx) const noexcept {
|
||||
return detail::static_if<std::is_floating_point<local_index_type>>(
|
||||
return detail::static_if<std::is_floating_point<value_type>>(
|
||||
[this](auto idx) { return interval_view<integer>(*this, idx); },
|
||||
[this](auto idx) { return this->value(idx); }, idx);
|
||||
}
|
||||
|
||||
/// Returns the number of bins, without over- or underflow.
|
||||
index_type size() const noexcept { return size_meta_.first(); }
|
||||
index_type size() const noexcept { return size_; }
|
||||
|
||||
/// Returns the options.
|
||||
static constexpr unsigned options() noexcept { return options_type::value; }
|
||||
/// Returns reference to metadata.
|
||||
metadata_type& metadata() noexcept { return size_meta_.second(); }
|
||||
/// Returns reference to const metadata.
|
||||
const metadata_type& metadata() const noexcept { return size_meta_.second(); }
|
||||
|
||||
/// Whether the axis is inclusive (see axis::traits::is_inclusive).
|
||||
static constexpr bool inclusive() noexcept {
|
||||
// If axis has underflow and overflow, it is inclusive.
|
||||
// If axis is growing or circular:
|
||||
// - it is inclusive if value_type is an integer.
|
||||
// - it is not inclusive if value_type is floating point, because of nan and inf.
|
||||
constexpr bool full_flow = options_type().test(option::underflow | option::overflow);
|
||||
return full_flow || (std::is_integral<value_type>::value &&
|
||||
(options() & (option::growth | option::circular)));
|
||||
}
|
||||
|
||||
template <class V, class M, class O>
|
||||
bool operator==(const integer<V, M, O>& o) const noexcept {
|
||||
return size() == o.size() && detail::relaxed_equal(metadata(), o.metadata()) &&
|
||||
min_ == o.min_;
|
||||
return size() == o.size() && min_ == o.min_ &&
|
||||
detail::relaxed_equal{}(this->metadata(), o.metadata());
|
||||
}
|
||||
|
||||
template <class V, class M, class O>
|
||||
@@ -143,31 +182,32 @@ public:
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive&, unsigned);
|
||||
void serialize(Archive& ar, unsigned /* version */) {
|
||||
ar& make_nvp("size", size_);
|
||||
ar& make_nvp("meta", this->metadata());
|
||||
ar& make_nvp("min", min_);
|
||||
}
|
||||
|
||||
private:
|
||||
index_type index_impl(std::false_type, int x) const noexcept {
|
||||
const auto z = x - min_;
|
||||
if (options_type::test(option::circular))
|
||||
return static_cast<index_type>(z - std::floor(float(z) / size()) * size());
|
||||
if (z < size()) return z >= 0 ? z : -1;
|
||||
// axis not circular
|
||||
template <class B>
|
||||
index_type index_impl(std::false_type, B, double z) const noexcept {
|
||||
if (z < size()) return z >= 0 ? static_cast<index_type>(z) : -1;
|
||||
return size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
index_type index_impl(std::true_type, T x) const noexcept {
|
||||
// need to handle NaN, cannot simply cast to int and call int-implementation
|
||||
const auto z = x - min_;
|
||||
if (options_type::test(option::circular)) {
|
||||
if (std::isfinite(z))
|
||||
return static_cast<index_type>(std::floor(z) - std::floor(z / size()) * size());
|
||||
} else if (z < size()) {
|
||||
return z >= 0 ? static_cast<index_type>(z) : -1;
|
||||
}
|
||||
return size();
|
||||
// value_type is integer, axis circular
|
||||
index_type index_impl(std::true_type, std::false_type, double z) const noexcept {
|
||||
return static_cast<index_type>(z - std::floor(z / size()) * size());
|
||||
}
|
||||
|
||||
detail::compressed_pair<index_type, metadata_type> size_meta_{0};
|
||||
// value_type is floating point, must handle +/-infinite or nan, axis circular
|
||||
index_type index_impl(std::true_type, std::true_type, double z) const noexcept {
|
||||
if (std::isfinite(z)) return index_impl(std::true_type{}, std::false_type{}, z);
|
||||
return z < size() ? -1 : size();
|
||||
}
|
||||
|
||||
index_type size_{0};
|
||||
value_type min_{0};
|
||||
|
||||
template <class V, class M, class O>
|
||||
@@ -177,13 +217,18 @@ private:
|
||||
#if __cpp_deduction_guides >= 201606
|
||||
|
||||
template <class T>
|
||||
integer(T, T)->integer<detail::convert_integer<T, index_type>>;
|
||||
|
||||
template <class T>
|
||||
integer(T, T, const char*)->integer<detail::convert_integer<T, index_type>>;
|
||||
integer(T, T) -> integer<detail::convert_integer<T, index_type>, null_type>;
|
||||
|
||||
template <class T, class M>
|
||||
integer(T, T, M)->integer<detail::convert_integer<T, index_type>, M>;
|
||||
integer(T, T, M)
|
||||
-> integer<detail::convert_integer<T, index_type>,
|
||||
detail::replace_type<std::decay_t<M>, const char*, std::string>>;
|
||||
|
||||
template <class T, class M, unsigned B>
|
||||
integer(T, T, M, const option::bitset<B>&)
|
||||
-> integer<detail::convert_integer<T, index_type>,
|
||||
detail::replace_type<std::decay_t<M>, const char*, std::string>,
|
||||
option::bitset<B>>;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user