/usr/include/boost/histogram/axis
Edit: /usr/include/boost/histogram/axis/variant.hpp (11572B)
// Copyright 2015-2019 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_HISTOGRAM_AXIS_VARIANT_HPP
#define BOOST_HISTOGRAM_AXIS_VARIANT_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include // mp_contains
#include // mp_first
#include
#include
#include
#include
#include
namespace boost {
namespace histogram {
namespace axis {
/// Polymorphic axis type
template
class variant : public iterator_mixin> {
using impl_type = boost::variant2::variant;
template
using is_bounded_type = mp11::mp_contains>;
template
using requires_bounded_type = std::enable_if_t::value>;
using metadata_type = std::remove_const_t>>()))>>;
public:
// cannot import ctors with using directive, it breaks gcc and msvc
variant() = default;
variant(const variant&) = default;
variant& operator=(const variant&) = default;
variant(variant&&) = default;
variant& operator=(variant&&) = default;
template >
variant(T&& t) : impl(std::forward(t)) {}
template >
variant& operator=(T&& t) {
impl = std::forward(t);
return *this;
}
template
variant(const variant& u) {
this->operator=(u);
}
template
variant& operator=(const variant& u) {
visit(
[this](const auto& u) {
using U = std::decay_t;
detail::static_if>(
[this](const auto& u) { this->operator=(u); },
[](const auto&) {
BOOST_THROW_EXCEPTION(std::runtime_error(
detail::type_name() + " is not convertible to a bounded type of " +
detail::type_name()));
},
u);
},
u);
return *this;
}
/// Return size of axis.
index_type size() const {
return visit([](const auto& a) -> index_type { return a.size(); }, *this);
}
/// Return options of axis or option::none_t if axis has no options.
unsigned options() const {
return visit([](const auto& a) { return traits::options(a); }, *this);
}
/// Returns true if the axis is inclusive or false.
bool inclusive() const {
return visit([](const auto& a) { return traits::inclusive(a); }, *this);
}
/// Returns true if the axis is ordered or false.
bool ordered() const {
return visit([](const auto& a) { return traits::ordered(a); }, *this);
}
/// Returns true if the axis is continuous or false.
bool continuous() const {
return visit([](const auto& a) { return traits::continuous(a); }, *this);
}
/// Return reference to const metadata or instance of null_type if axis has no
/// metadata.
metadata_type& metadata() const {
return visit(
[](const auto& a) -> metadata_type& {
using M = decltype(traits::metadata(a));
return detail::static_if>(
[](const auto& a) -> metadata_type& { return traits::metadata(a); },
[](const auto&) -> metadata_type& {
BOOST_THROW_EXCEPTION(std::runtime_error(
"cannot return metadata of type " + detail::type_name() +
" through axis::variant interface which uses type " +
detail::type_name() +
"; use boost::histogram::axis::get to obtain a reference "
"of this axis type"));
},
a);
},
*this);
}
/// Return reference to metadata or instance of null_type if axis has no
/// metadata.
metadata_type& metadata() {
return visit(
[](auto& a) -> metadata_type& {
using M = decltype(traits::metadata(a));
return detail::static_if>(
[](auto& a) -> metadata_type& { return traits::metadata(a); },
[](auto&) -> metadata_type& {
BOOST_THROW_EXCEPTION(std::runtime_error(
"cannot return metadata of type " + detail::type_name() +
" through axis::variant interface which uses type " +
detail::type_name() +
"; use boost::histogram::axis::get to obtain a reference "
"of this axis type"));
},
a);
},
*this);
}
/** Return index for value argument.
Throws std::invalid_argument if axis has incompatible call signature.
*/
template
index_type index(const U& u) const {
return visit([&u](const auto& a) { return traits::index(a, u); }, *this);
}
/** Return value for index argument.
Only works for axes with value method that returns something convertible
to double and will throw a runtime_error otherwise, see
axis::traits::value().
*/
double value(real_index_type idx) const {
return visit([idx](const auto& a) { return traits::value_as(a, idx); },
*this);
}
/** Return bin for index argument.
Only works for axes with value method that returns something convertible
to double and will throw a runtime_error otherwise, see
axis::traits::value().
*/
auto bin(index_type idx) const {
return visit(
[idx](const auto& a) {
return detail::value_method_switch(
[idx](const auto& a) { // axis is discrete
const double x = traits::value_as(a, idx);
return polymorphic_bin(x, x);
},
[idx](const auto& a) { // axis is continuous
const double x1 = traits::value_as(a, idx);
const double x2 = traits::value_as(a, idx + 1);
return polymorphic_bin(x1, x2);
},
a, detail::priority<1>{});
},
*this);
}
template
void serialize(Archive& ar, unsigned /* version */) {
detail::variant_proxy p{*this};
ar& make_nvp("variant", p);
}
private:
impl_type impl;
friend struct detail::variant_access;
friend struct boost::histogram::unsafe_access;
};
// specialization for empty argument list, useful for meta-programming
template <>
class variant<> {};
/// Apply visitor to variant (reference).
template
decltype(auto) visit(Visitor&& vis, variant& var) {
return detail::variant_access::visit(vis, var);
}
/// Apply visitor to variant (movable reference).
template
decltype(auto) visit(Visitor&& vis, variant&& var) {
return detail::variant_access::visit(vis, std::move(var));
}
/// Apply visitor to variant (const reference).
template
decltype(auto) visit(Visitor&& vis, const variant& var) {
return detail::variant_access::visit(vis, var);
}
/// Returns pointer to T in variant or null pointer if type does not match.
template
auto get_if(variant* v) {
return detail::variant_access::template get_if(v);
}
/// Returns pointer to const T in variant or null pointer if type does not match.
template
auto get_if(const variant* v) {
return detail::variant_access::template get_if(v);
}
/// Return reference to T, throws std::runtime_error if type does not match.
template
decltype(auto) get(variant& v) {
auto tp = get_if(&v);
if (!tp) BOOST_THROW_EXCEPTION(std::runtime_error("T is not the held type"));
return *tp;
}
/// Return movable reference to T, throws unspecified exception if type does not match.
template
decltype(auto) get(variant&& v) {
auto tp = get_if(&v);
if (!tp) BOOST_THROW_EXCEPTION(std::runtime_error("T is not the held type"));
return std::move(*tp);
}
/// Return const reference to T, throws unspecified exception if type does not match.
template
decltype(auto) get(const variant& v) {
auto tp = get_if(&v);
if (!tp) BOOST_THROW_EXCEPTION(std::runtime_error("T is not the held type"));
return *tp;
}
// pass-through version of visit for generic programming
template
decltype(auto) visit(Visitor&& vis, T&& var) {
return std::forward(vis)(std::forward(var));
}
// pass-through version of get for generic programming
template
decltype(auto) get(U&& u) {
return std::forward(u);
}
// pass-through version of get_if for generic programming
template
auto get_if(U* u) {
return reinterpret_cast(std::is_same>::value ? u : nullptr);
}
// pass-through version of get_if for generic programming
template
auto get_if(const U* u) {
return reinterpret_cast(std::is_same>::value ? u
: nullptr);
}
/** Compare two variants.
Return true if the variants point to the same concrete axis type and the types compare
equal. Otherwise return false.
*/
template
bool operator==(const variant& u, const variant& v) noexcept {
return visit([&](const auto& vi) { return u == vi; }, v);
}
/** Compare variant with a concrete axis type.
Return true if the variant point to the same concrete axis type and the types compare
equal. Otherwise return false.
*/
template
bool operator==(const variant& u, const T& t) noexcept {
using V = variant;
return detail::static_if_c<(mp11::mp_contains::value ||
mp11::mp_contains::value ||
mp11::mp_contains::value)>(
[&](const auto& t) {
using U = std::decay_t;
const U* tp = detail::variant_access::template get_if(&u);
return tp && detail::relaxed_equal{}(*tp, t);
},
[&](const auto&) { return false; }, t);
}
template
bool operator==(const T& t, const variant& u) noexcept {
return u == t;
}
/// The negation of operator==.
template
bool operator!=(const variant& u, const variant& t) noexcept {
return !(u == t);
}
/// The negation of operator==.
template
bool operator!=(const variant& u, const T& t) noexcept {
return !(u == t);
}
/// The negation of operator==.
template
bool operator!=(const T& t, const variant& u) noexcept {
return u != t;
}
} // namespace axis
} // namespace histogram
} // namespace boost
#endif