detect.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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/function.hpp> // mp_and, mp_or
  10. #include <boost/mp11/integral.hpp> // mp_not
  11. #include <boost/mp11/list.hpp> // mp_first
  12. #include <iterator>
  13. #include <tuple>
  14. #include <type_traits>
  15. // forward declaration
  16. namespace boost {
  17. namespace variant2 {
  18. template <class...>
  19. class variant;
  20. } // namespace variant2
  21. } // namespace boost
  22. namespace boost {
  23. namespace histogram {
  24. namespace detail {
  25. template <class...>
  26. using void_t = void;
  27. struct detect_base {
  28. template <class T>
  29. static T&& val();
  30. template <class T>
  31. static T& ref();
  32. template <class T>
  33. static T const& cref();
  34. };
  35. #define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
  36. template <class U> \
  37. struct name##_impl : detect_base { \
  38. template <class T> \
  39. static mp11::mp_true test(T& t, decltype(cond, 0)); \
  40. template <class T> \
  41. static mp11::mp_false test(T&, float); \
  42. using type = decltype(test<U>(ref<U>(), 0)); \
  43. }; \
  44. template <class T> \
  45. using name = typename name##_impl<T>::type
  46. #define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
  47. template <class V, class W> \
  48. struct name##_impl : detect_base { \
  49. template <class T, class U> \
  50. static mp11::mp_true test(T& t, U& u, decltype(cond, 0)); \
  51. template <class T, class U> \
  52. static mp11::mp_false test(T&, U&, float); \
  53. using type = decltype(test<V, W>(ref<V>(), ref<W>(), 0)); \
  54. }; \
  55. template <class T, class U = T> \
  56. using name = typename name##_impl<T, U>::type
  57. // reset has overloads, trying to get pmf in this case always fails
  58. BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0));
  59. BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]);
  60. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(is_transform, (t.inverse(t.forward(u))));
  61. BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container,
  62. (t[0], t.size(), std::begin(t), std::end(t)));
  63. BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like,
  64. (t[0], t.size(), t.resize(0), std::begin(t), std::end(t)));
  65. BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value,
  66. std::begin(t), std::end(t)));
  67. BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, ((typename T::key_type*)nullptr,
  68. (typename T::mapped_type*)nullptr,
  69. std::begin(t), std::end(t)));
  70. // ok: is_axis is false for axis::variant, because T::index is templated
  71. BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index));
  72. BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t)));
  73. BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator,
  74. (typename std::iterator_traits<T>::iterator_category{}));
  75. BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t));
  76. BOOST_HISTOGRAM_DETAIL_DETECT(is_allocator, (&T::allocate, &T::deallocate));
  77. BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t);
  78. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (cref<T>() == u));
  79. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd, (t += u));
  80. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub, (t -= u));
  81. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul, (t *= u));
  82. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv, (t /= u));
  83. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_method_eq, (cref<T>().operator==(u)));
  84. BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
  85. // stronger form of std::is_convertible that works with explicit operator T and ctors
  86. BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(is_explicitly_convertible, static_cast<U>(t));
  87. BOOST_HISTOGRAM_DETAIL_DETECT(is_complete, sizeof(T));
  88. template <class T>
  89. using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
  90. has_threading_support<T>>;
  91. template <class T>
  92. using is_adaptible =
  93. mp11::mp_and<mp11::mp_not<is_storage<T>>,
  94. mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>;
  95. template <class T>
  96. struct is_tuple_impl : std::false_type {};
  97. template <class... Ts>
  98. struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
  99. template <class T>
  100. using is_tuple = typename is_tuple_impl<T>::type;
  101. template <class T>
  102. struct is_variant_impl : std::false_type {};
  103. template <class... Ts>
  104. struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {};
  105. template <class T>
  106. using is_variant = typename is_variant_impl<T>::type;
  107. template <class T>
  108. struct is_axis_variant_impl : std::false_type {};
  109. template <class... Ts>
  110. struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {};
  111. template <class T>
  112. using is_axis_variant = typename is_axis_variant_impl<T>::type;
  113. template <class T>
  114. using is_any_axis = mp11::mp_or<is_axis<T>, is_axis_variant<T>>;
  115. template <class T>
  116. using is_sequence_of_axis = mp11::mp_and<is_iterable<T>, is_axis<mp11::mp_first<T>>>;
  117. template <class T>
  118. using is_sequence_of_axis_variant =
  119. mp11::mp_and<is_iterable<T>, is_axis_variant<mp11::mp_first<T>>>;
  120. template <class T>
  121. using is_sequence_of_any_axis =
  122. mp11::mp_and<is_iterable<T>, is_any_axis<mp11::mp_first<T>>>;
  123. // Poor-mans concept checks.
  124. // These must be structs not aliases, so their names pop up in compiler errors.
  125. template <class T, class = std::enable_if_t<is_storage<std::decay_t<T>>::value>>
  126. struct requires_storage {};
  127. template <class T, class _ = std::decay_t<T>,
  128. class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
  129. struct requires_storage_or_adaptible {};
  130. template <class T, class = std::enable_if_t<is_iterator<std::decay_t<T>>::value>>
  131. struct requires_iterator {};
  132. template <class T, class = std::enable_if_t<
  133. is_iterable<std::remove_cv_t<std::remove_reference_t<T>>>::value>>
  134. struct requires_iterable {};
  135. template <class T, class = std::enable_if_t<is_axis<std::decay_t<T>>::value>>
  136. struct requires_axis {};
  137. template <class T, class = std::enable_if_t<is_any_axis<std::decay_t<T>>::value>>
  138. struct requires_any_axis {};
  139. template <class T, class = std::enable_if_t<is_sequence_of_axis<std::decay_t<T>>::value>>
  140. struct requires_sequence_of_axis {};
  141. template <class T,
  142. class = std::enable_if_t<is_sequence_of_axis_variant<std::decay_t<T>>::value>>
  143. struct requires_sequence_of_axis_variant {};
  144. template <class T,
  145. class = std::enable_if_t<is_sequence_of_any_axis<std::decay_t<T>>::value>>
  146. struct requires_sequence_of_any_axis {};
  147. template <class T,
  148. class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>>
  149. struct requires_axes {};
  150. template <class T, class U,
  151. class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>>
  152. struct requires_transform {};
  153. template <class T, class = std::enable_if_t<is_allocator<std::decay_t<T>>::value>>
  154. struct requires_allocator {};
  155. } // namespace detail
  156. } // namespace histogram
  157. } // namespace boost
  158. #endif