Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:10

0001 // Copyright 2015-2019 Hans Dembinski
0002 //
0003 // Distributed under the Boost Software License, Version 1.0.
0004 // (See accompanying file LICENSE_1_0.txt
0005 // or copy at http://www.boost.org/LICENSE_1_0.txt)
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 /// Polymorphic axis type
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   // cannot import ctors with using directive, it breaks gcc and msvc
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   /// Return size of axis.
0086   index_type size() const {
0087     return visit([](const auto& a) -> index_type { return a.size(); }, *this);
0088   }
0089 
0090   /// Return options of axis or option::none_t if axis has no options.
0091   unsigned options() const {
0092     return visit([](const auto& a) { return traits::options(a); }, *this);
0093   }
0094 
0095   /// Returns true if the axis is inclusive or false.
0096   bool inclusive() const {
0097     return visit([](const auto& a) { return traits::inclusive(a); }, *this);
0098   }
0099 
0100   /// Returns true if the axis is ordered or false.
0101   bool ordered() const {
0102     return visit([](const auto& a) { return traits::ordered(a); }, *this);
0103   }
0104 
0105   /// Returns true if the axis is continuous or false.
0106   bool continuous() const {
0107     return visit([](const auto& a) { return traits::continuous(a); }, *this);
0108   }
0109 
0110   /// Return reference to const metadata or instance of null_type if axis has no
0111   /// metadata.
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   /// Return reference to metadata or instance of null_type if axis has no
0132   /// metadata.
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   /** Return index for value argument.
0153 
0154     Throws std::invalid_argument if axis has incompatible call signature.
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   /** Return value for index argument.
0162 
0163     Only works for axes with value method that returns something convertible
0164     to double and will throw a runtime_error otherwise, see
0165     axis::traits::value().
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   /** Return bin for index argument.
0173 
0174     Only works for axes with value method that returns something convertible
0175     to double and will throw a runtime_error otherwise, see
0176     axis::traits::value().
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) { // axis is discrete
0183                 const double x = traits::value_as<double>(a, idx);
0184                 return polymorphic_bin<double>(x, x);
0185               },
0186               [idx](const auto& a) { // axis is continuous
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 /* version */) {
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 // specialization for empty argument list, useful for meta-programming
0210 template <>
0211 class variant<> {};
0212 
0213 /// Apply visitor to variant (reference).
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 /// Apply visitor to variant (movable reference).
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 /// Apply visitor to variant (const reference).
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 /// Returns pointer to T in variant or null pointer if type does not match.
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 /// Returns pointer to const T in variant or null pointer if type does not match.
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 /// Return reference to T, throws std::runtime_error if type does not match.
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 /// Return movable reference to T, throws unspecified exception if type does not match.
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 /// Return const reference to T, throws unspecified exception if type does not match.
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 // pass-through version of visit for generic programming
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 // pass-through version of get for generic programming
0274 template <class T, class U>
0275 decltype(auto) get(U&& u) {
0276   return std::forward<U>(u);
0277 }
0278 
0279 // pass-through version of get_if for generic programming
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 // pass-through version of get_if for generic programming
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 /** Compare two variants.
0293 
0294   Return true if the variants point to the same concrete axis type and the types compare
0295   equal. Otherwise return false.
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 /** Compare variant with a concrete axis type.
0303 
0304   Return true if the variant point to the same concrete axis type and the types compare
0305   equal. Otherwise return false.
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 /// The negation of operator==.
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 /// The negation of operator==.
0333 template <class... Us, class T>
0334 bool operator!=(const variant<Us...>& u, const T& t) noexcept {
0335   return !(u == t);
0336 }
0337 
0338 /// The negation of operator==.
0339 template <class T, class... Us>
0340 bool operator!=(const T& t, const variant<Us...>& u) noexcept {
0341   return u != t;
0342 }
0343 
0344 } // namespace axis
0345 } // namespace histogram
0346 } // namespace boost
0347 
0348 #endif