detect.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright 2015-2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_DETAIL_DETECT_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_DETECT_HPP
  8. #include <boost/histogram/fwd.hpp>
  9. #include <boost/mp11/algorithm.hpp>
  10. #include <boost/mp11/function.hpp>
  11. #include <boost/mp11/utility.hpp>
  12. #include <boost/variant2/variant.hpp>
  13. #include <iterator>
  14. #include <tuple>
  15. #include <type_traits>
  16. namespace boost {
  17. namespace histogram {
  18. namespace detail {
  19. #define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
  20. template <class T> \
  21. using name##_impl = decltype(cond); \
  22. template <class T> \
  23. using name = typename boost::mp11::mp_valid<name##_impl, T>::type
  24. #define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
  25. template <class T, class U> \
  26. using name##_impl = decltype(cond); \
  27. template <class T, class U = T> \
  28. using name = typename boost::mp11::mp_valid<name##_impl, T, U>::type
  29. // metadata has overloads, trying to get pmf in this case always fails
  30. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_metadata, (std::declval<T&>().metadata()));
  31. // resize has overloads, trying to get pmf in this case always fails
  32. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_resize, (std::declval<T&>().resize(0)));
  33. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_size, &T::size);
  34. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_clear, &T::clear);
  35. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_lower, &T::lower);
  36. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_value, &T::value);
  37. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_update, &T::update);
  38. // reset has overloads, trying to get pmf in this case always fails
  39. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, (std::declval<T>().reset(0)));
  40. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_options, &T::options);
  41. BOOST_HISTOGRAM_DETAIL_DETECT(has_allocator, &T::get_allocator);
  42. BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, (std::declval<T&>()[0]));
  43. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
  44. is_transform,
  45. (std::declval<T&>().inverse(std::declval<T&>().forward(std::declval<U>()))));
  46. BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container, (std::declval<T>()[0], &T::size,
  47. std::begin(std::declval<T>()),
  48. std::end(std::declval<T>())));
  49. BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like,
  50. (std::declval<T>()[0], &T::size,
  51. std::declval<T>().resize(0), std::begin(std::declval<T>()),
  52. std::end(std::declval<T>())));
  53. BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like,
  54. (std::declval<T>()[0], &T::size, std::tuple_size<T>::value,
  55. std::begin(std::declval<T>()),
  56. std::end(std::declval<T>())));
  57. BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, (std::declval<typename T::key_type>(),
  58. std::declval<typename T::mapped_type>(),
  59. std::begin(std::declval<T>()),
  60. std::end(std::declval<T>())));
  61. // ok: is_axis is false for axis::variant, because T::index is templated
  62. BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (&T::size, &T::index));
  63. BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(std::declval<T&>()),
  64. std::end(std::declval<T&>())));
  65. BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator,
  66. (typename std::iterator_traits<T>::iterator_category()));
  67. BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable,
  68. (std::declval<std::ostream&>() << std::declval<T&>()));
  69. BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, (++std::declval<T&>()));
  70. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() ==
  71. std::declval<const U>()));
  72. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd,
  73. (std::declval<T&>() += std::declval<U>()));
  74. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub,
  75. (std::declval<T&>() -= std::declval<U>()));
  76. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul,
  77. (std::declval<T&>() *= std::declval<U>()));
  78. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv,
  79. (std::declval<T&>() /= std::declval<U>()));
  80. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
  81. has_method_eq, (std::declval<const T>().operator==(std::declval<const U>())));
  82. BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
  83. template <class T>
  84. using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
  85. has_threading_support<T>>;
  86. template <class T>
  87. using is_adaptible =
  88. mp11::mp_and<mp11::mp_not<is_storage<T>>,
  89. mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>;
  90. template <class T>
  91. struct is_tuple_impl : mp11::mp_false {};
  92. template <class... Ts>
  93. struct is_tuple_impl<std::tuple<Ts...>> : mp11::mp_true {};
  94. template <class T>
  95. using is_tuple = typename is_tuple_impl<T>::type;
  96. template <class T>
  97. struct is_variant_impl : mp11::mp_false {};
  98. template <class... Ts>
  99. struct is_variant_impl<boost::variant2::variant<Ts...>> : mp11::mp_true {};
  100. template <class T>
  101. using is_variant = typename is_variant_impl<T>::type;
  102. template <class T>
  103. struct is_axis_variant_impl : mp11::mp_false {};
  104. template <class... Ts>
  105. struct is_axis_variant_impl<axis::variant<Ts...>> : mp11::mp_true {};
  106. template <class T>
  107. using is_axis_variant = typename is_axis_variant_impl<T>::type;
  108. template <class T>
  109. using is_any_axis = mp11::mp_or<is_axis<T>, is_axis_variant<T>>;
  110. template <class T>
  111. using is_sequence_of_axis = mp11::mp_and<is_iterable<T>, is_axis<mp11::mp_first<T>>>;
  112. template <class T>
  113. using is_sequence_of_axis_variant =
  114. mp11::mp_and<is_iterable<T>, is_axis_variant<mp11::mp_first<T>>>;
  115. template <class T>
  116. using is_sequence_of_any_axis =
  117. mp11::mp_and<is_iterable<T>, is_any_axis<mp11::mp_first<T>>>;
  118. // poor-mans concept checks
  119. template <class T, class = std::enable_if_t<is_storage<std::decay_t<T>>::value>>
  120. struct requires_storage {};
  121. template <class T, class _ = std::decay_t<T>,
  122. class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
  123. struct requires_storage_or_adaptible {};
  124. template <class T, class = std::enable_if_t<is_iterator<std::decay_t<T>>::value>>
  125. struct requires_iterator {};
  126. template <class T, class = std::enable_if_t<
  127. is_iterable<std::remove_cv_t<std::remove_reference_t<T>>>::value>>
  128. struct requires_iterable {};
  129. template <class T, class = std::enable_if_t<is_axis<std::decay_t<T>>::value>>
  130. struct requires_axis {};
  131. template <class T, class = std::enable_if_t<is_any_axis<std::decay_t<T>>::value>>
  132. struct requires_any_axis {};
  133. template <class T, class = std::enable_if_t<is_sequence_of_axis<std::decay_t<T>>::value>>
  134. struct requires_sequence_of_axis {};
  135. template <class T,
  136. class = std::enable_if_t<is_sequence_of_axis_variant<std::decay_t<T>>::value>>
  137. struct requires_sequence_of_axis_variant {};
  138. template <class T,
  139. class = std::enable_if_t<is_sequence_of_any_axis<std::decay_t<T>>::value>>
  140. struct requires_sequence_of_any_axis {};
  141. template <class T,
  142. class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>>
  143. struct requires_axes {};
  144. template <class T, class U, class = std::enable_if_t<std::is_convertible<T, U>::value>>
  145. struct requires_convertible {};
  146. template <class T, class U,
  147. class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>>
  148. struct requires_transform {};
  149. } // namespace detail
  150. } // namespace histogram
  151. } // namespace boost
  152. #endif