File indexing completed on 2025-01-18 09:38:10
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_HISTOGRAM_AXIS_VARIANT_HPP
0008 #define BOOST_HISTOGRAM_AXIS_VARIANT_HPP
0009
0010 #include <boost/core/nvp.hpp>
0011 #include <boost/histogram/axis/iterator.hpp>
0012 #include <boost/histogram/axis/polymorphic_bin.hpp>
0013 #include <boost/histogram/axis/traits.hpp>
0014 #include <boost/histogram/detail/relaxed_equal.hpp>
0015 #include <boost/histogram/detail/static_if.hpp>
0016 #include <boost/histogram/detail/type_name.hpp>
0017 #include <boost/histogram/detail/variant_proxy.hpp>
0018 #include <boost/mp11/algorithm.hpp> // mp_contains
0019 #include <boost/mp11/list.hpp> // mp_first
0020 #include <boost/throw_exception.hpp>
0021 #include <boost/variant2/variant.hpp>
0022 #include <stdexcept>
0023 #include <type_traits>
0024 #include <utility>
0025
0026 namespace boost {
0027 namespace histogram {
0028 namespace axis {
0029
0030
0031 template <class... Ts>
0032 class variant : public iterator_mixin<variant<Ts...>> {
0033 using impl_type = boost::variant2::variant<Ts...>;
0034
0035 template <class T>
0036 using is_bounded_type = mp11::mp_contains<variant, std::decay_t<T>>;
0037
0038 template <class T>
0039 using requires_bounded_type = std::enable_if_t<is_bounded_type<T>::value>;
0040
0041 using metadata_type =
0042 std::remove_const_t<std::remove_reference_t<decltype(traits::metadata(
0043 std::declval<std::remove_pointer_t<mp11::mp_first<variant>>>()))>>;
0044
0045 public:
0046
0047 variant() = default;
0048 variant(const variant&) = default;
0049 variant& operator=(const variant&) = default;
0050 variant(variant&&) = default;
0051 variant& operator=(variant&&) = default;
0052
0053 template <class T, class = requires_bounded_type<T>>
0054 variant(T&& t) : impl(std::forward<T>(t)) {}
0055
0056 template <class T, class = requires_bounded_type<T>>
0057 variant& operator=(T&& t) {
0058 impl = std::forward<T>(t);
0059 return *this;
0060 }
0061
0062 template <class... Us>
0063 variant(const variant<Us...>& u) {
0064 this->operator=(u);
0065 }
0066
0067 template <class... Us>
0068 variant& operator=(const variant<Us...>& u) {
0069 visit(
0070 [this](const auto& u) {
0071 using U = std::decay_t<decltype(u)>;
0072 detail::static_if<is_bounded_type<U>>(
0073 [this](const auto& u) { this->operator=(u); },
0074 [](const auto&) {
0075 BOOST_THROW_EXCEPTION(std::runtime_error(
0076 detail::type_name<U>() + " is not convertible to a bounded type of " +
0077 detail::type_name<variant>()));
0078 },
0079 u);
0080 },
0081 u);
0082 return *this;
0083 }
0084
0085
0086 index_type size() const {
0087 return visit([](const auto& a) -> index_type { return a.size(); }, *this);
0088 }
0089
0090
0091 unsigned options() const {
0092 return visit([](const auto& a) { return traits::options(a); }, *this);
0093 }
0094
0095
0096 bool inclusive() const {
0097 return visit([](const auto& a) { return traits::inclusive(a); }, *this);
0098 }
0099
0100
0101 bool ordered() const {
0102 return visit([](const auto& a) { return traits::ordered(a); }, *this);
0103 }
0104
0105
0106 bool continuous() const {
0107 return visit([](const auto& a) { return traits::continuous(a); }, *this);
0108 }
0109
0110
0111
0112 metadata_type& metadata() const {
0113 return visit(
0114 [](const auto& a) -> metadata_type& {
0115 using M = decltype(traits::metadata(a));
0116 return detail::static_if<std::is_same<M, metadata_type&>>(
0117 [](const auto& a) -> metadata_type& { return traits::metadata(a); },
0118 [](const auto&) -> metadata_type& {
0119 BOOST_THROW_EXCEPTION(std::runtime_error(
0120 "cannot return metadata of type " + detail::type_name<M>() +
0121 " through axis::variant interface which uses type " +
0122 detail::type_name<metadata_type>() +
0123 "; use boost::histogram::axis::get to obtain a reference "
0124 "of this axis type"));
0125 },
0126 a);
0127 },
0128 *this);
0129 }
0130
0131
0132
0133 metadata_type& metadata() {
0134 return visit(
0135 [](auto& a) -> metadata_type& {
0136 using M = decltype(traits::metadata(a));
0137 return detail::static_if<std::is_same<M, metadata_type&>>(
0138 [](auto& a) -> metadata_type& { return traits::metadata(a); },
0139 [](auto&) -> metadata_type& {
0140 BOOST_THROW_EXCEPTION(std::runtime_error(
0141 "cannot return metadata of type " + detail::type_name<M>() +
0142 " through axis::variant interface which uses type " +
0143 detail::type_name<metadata_type>() +
0144 "; use boost::histogram::axis::get to obtain a reference "
0145 "of this axis type"));
0146 },
0147 a);
0148 },
0149 *this);
0150 }
0151
0152
0153
0154
0155
0156 template <class U>
0157 index_type index(const U& u) const {
0158 return visit([&u](const auto& a) { return traits::index(a, u); }, *this);
0159 }
0160
0161
0162
0163
0164
0165
0166
0167 double value(real_index_type idx) const {
0168 return visit([idx](const auto& a) { return traits::value_as<double>(a, idx); },
0169 *this);
0170 }
0171
0172
0173
0174
0175
0176
0177
0178 auto bin(index_type idx) const {
0179 return visit(
0180 [idx](const auto& a) {
0181 return detail::value_method_switch(
0182 [idx](const auto& a) {
0183 const double x = traits::value_as<double>(a, idx);
0184 return polymorphic_bin<double>(x, x);
0185 },
0186 [idx](const auto& a) {
0187 const double x1 = traits::value_as<double>(a, idx);
0188 const double x2 = traits::value_as<double>(a, idx + 1);
0189 return polymorphic_bin<double>(x1, x2);
0190 },
0191 a, detail::priority<1>{});
0192 },
0193 *this);
0194 }
0195
0196 template <class Archive>
0197 void serialize(Archive& ar, unsigned ) {
0198 detail::variant_proxy<variant> p{*this};
0199 ar& make_nvp("variant", p);
0200 }
0201
0202 private:
0203 impl_type impl;
0204
0205 friend struct detail::variant_access;
0206 friend struct boost::histogram::unsafe_access;
0207 };
0208
0209
0210 template <>
0211 class variant<> {};
0212
0213
0214 template <class Visitor, class... Us>
0215 decltype(auto) visit(Visitor&& vis, variant<Us...>& var) {
0216 return detail::variant_access::visit(vis, var);
0217 }
0218
0219
0220 template <class Visitor, class... Us>
0221 decltype(auto) visit(Visitor&& vis, variant<Us...>&& var) {
0222 return detail::variant_access::visit(vis, std::move(var));
0223 }
0224
0225
0226 template <class Visitor, class... Us>
0227 decltype(auto) visit(Visitor&& vis, const variant<Us...>& var) {
0228 return detail::variant_access::visit(vis, var);
0229 }
0230
0231
0232 template <class T, class... Us>
0233 auto get_if(variant<Us...>* v) {
0234 return detail::variant_access::template get_if<T>(v);
0235 }
0236
0237
0238 template <class T, class... Us>
0239 auto get_if(const variant<Us...>* v) {
0240 return detail::variant_access::template get_if<T>(v);
0241 }
0242
0243
0244 template <class T, class... Us>
0245 decltype(auto) get(variant<Us...>& v) {
0246 auto tp = get_if<T>(&v);
0247 if (!tp) BOOST_THROW_EXCEPTION(std::runtime_error("T is not the held type"));
0248 return *tp;
0249 }
0250
0251
0252 template <class T, class... Us>
0253 decltype(auto) get(variant<Us...>&& v) {
0254 auto tp = get_if<T>(&v);
0255 if (!tp) BOOST_THROW_EXCEPTION(std::runtime_error("T is not the held type"));
0256 return std::move(*tp);
0257 }
0258
0259
0260 template <class T, class... Us>
0261 decltype(auto) get(const variant<Us...>& v) {
0262 auto tp = get_if<T>(&v);
0263 if (!tp) BOOST_THROW_EXCEPTION(std::runtime_error("T is not the held type"));
0264 return *tp;
0265 }
0266
0267
0268 template <class Visitor, class T>
0269 decltype(auto) visit(Visitor&& vis, T&& var) {
0270 return std::forward<Visitor>(vis)(std::forward<T>(var));
0271 }
0272
0273
0274 template <class T, class U>
0275 decltype(auto) get(U&& u) {
0276 return std::forward<U>(u);
0277 }
0278
0279
0280 template <class T, class U>
0281 auto get_if(U* u) {
0282 return reinterpret_cast<T*>(std::is_same<T, std::decay_t<U>>::value ? u : nullptr);
0283 }
0284
0285
0286 template <class T, class U>
0287 auto get_if(const U* u) {
0288 return reinterpret_cast<const T*>(std::is_same<T, std::decay_t<U>>::value ? u
0289 : nullptr);
0290 }
0291
0292
0293
0294
0295
0296
0297 template <class... Us, class... Vs>
0298 bool operator==(const variant<Us...>& u, const variant<Vs...>& v) noexcept {
0299 return visit([&](const auto& vi) { return u == vi; }, v);
0300 }
0301
0302
0303
0304
0305
0306
0307 template <class... Us, class T>
0308 bool operator==(const variant<Us...>& u, const T& t) noexcept {
0309 using V = variant<Us...>;
0310 return detail::static_if_c<(mp11::mp_contains<V, T>::value ||
0311 mp11::mp_contains<V, T*>::value ||
0312 mp11::mp_contains<V, const T*>::value)>(
0313 [&](const auto& t) {
0314 using U = std::decay_t<decltype(t)>;
0315 const U* tp = detail::variant_access::template get_if<U>(&u);
0316 return tp && detail::relaxed_equal{}(*tp, t);
0317 },
0318 [&](const auto&) { return false; }, t);
0319 }
0320
0321 template <class T, class... Us>
0322 bool operator==(const T& t, const variant<Us...>& u) noexcept {
0323 return u == t;
0324 }
0325
0326
0327 template <class... Us, class... Ts>
0328 bool operator!=(const variant<Us...>& u, const variant<Ts...>& t) noexcept {
0329 return !(u == t);
0330 }
0331
0332
0333 template <class... Us, class T>
0334 bool operator!=(const variant<Us...>& u, const T& t) noexcept {
0335 return !(u == t);
0336 }
0337
0338
0339 template <class T, class... Us>
0340 bool operator!=(const T& t, const variant<Us...>& u) noexcept {
0341 return u != t;
0342 }
0343
0344 }
0345 }
0346 }
0347
0348 #endif