update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -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