29 #ifndef PIRANHA_TYPE_TRAITS_HPP 30 #define PIRANHA_TYPE_TRAITS_HPP 41 #include <initializer_list> 46 #include <type_traits> 49 #include <piranha/config.hpp> 58 template <
typename... Ts>
63 template <
typename... Ts>
64 using void_t =
typename make_void<Ts...>::type;
67 template <
class Default,
class AlwaysVoid,
template <
class...>
class Op,
class... Args>
69 using value_t = std::false_type;
73 template <
class Default,
template <
class...>
class Op,
class... Args>
74 struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
75 using value_t = std::true_type;
76 using type = Op<Args...>;
83 nonesuch(nonesuch
const &) =
delete;
84 void operator=(nonesuch
const &) =
delete;
87 template <
template <
class...>
class Op,
class... Args>
88 using is_detected =
typename detector<nonesuch, void, Op, Args...>::value_t;
90 template <
template <
class...>
class Op,
class... Args>
91 using detected_t =
typename detector<nonesuch, void, Op, Args...>::type;
95 struct conjunction : std::true_type {
99 struct conjunction<B1> : B1 {
102 template <
class B1,
class... Bn>
103 struct conjunction<B1, Bn...> : std::conditional<B1::value != false, conjunction<Bn...>, B1>::type {
108 struct disjunction : std::false_type {
112 struct disjunction<B1> : B1 {
115 template <
class B1,
class... Bn>
116 struct disjunction<B1, Bn...> : std::conditional<B1::value != false, B1, disjunction<Bn...>>::type {
121 struct negation : std::integral_constant<bool, !B::value> {
128 template <std::size_t CurIdx,
class...>
129 struct disjunction_idx_impl : std::integral_constant<std::size_t, 0u> {
132 template <std::
size_t CurIdx,
class B1>
133 struct disjunction_idx_impl<CurIdx, B1>
134 : std::integral_constant<std::size_t, (B1::value != false) ? CurIdx : CurIdx + 1u> {
137 template <std::size_t CurIdx,
class B1,
class... Bn>
138 struct disjunction_idx_impl<CurIdx, B1, Bn...>
139 : std::conditional<B1::value != false, std::integral_constant<std::size_t, CurIdx>,
140 disjunction_idx_impl<CurIdx + 1u, Bn...>>::type {
143 template <
class... Bs>
144 struct disjunction_idx : disjunction_idx_impl<0u, Bs...> {
150 template <std::size_t... Ints>
151 struct index_sequence {
152 using type = index_sequence;
153 using value_type = std::size_t;
154 static constexpr std::size_t size() noexcept
156 return sizeof...(Ints);
160 template <
class Sequence1,
class Sequence2>
161 struct merge_and_renumber;
163 template <std::size_t... I1, std::size_t... I2>
164 struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
165 : index_sequence<I1..., (sizeof...(I1) + I2)...> {
168 template <std::
size_t N>
169 struct make_index_sequence
170 : merge_and_renumber<typename make_index_sequence<N / 2>::type, typename make_index_sequence<N - N / 2>::type> {
174 struct make_index_sequence<0> : index_sequence<> {
178 struct make_index_sequence<1> : index_sequence<0> {
181 template <
typename T,
typename F, std::size_t... Is>
182 void apply_to_each_item(T &&t,
const F &f, index_sequence<Is...>)
184 (void)std::initializer_list<int>{0, (void(f(std::get<Is>(std::forward<T>(t)))), 0)...};
191 template <
class Tuple,
class F>
192 void tuple_for_each(Tuple &&t,
const F &f)
194 apply_to_each_item(std::forward<Tuple>(t), f,
195 make_index_sequence<std::tuple_size<
typename std::decay<Tuple>::type>::value>{});
199 template <
typename T>
200 using uncvref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
202 template <
typename T>
203 using decay_t =
typename std::decay<T>::type;
205 template <
typename T>
206 using unref_t =
typename std::remove_reference<T>::type;
208 template <
typename T>
209 using addlref_t =
typename std::add_lvalue_reference<T>::type;
211 template <
bool B,
typename T =
void>
212 using enable_if_t =
typename std::enable_if<B, T>::type;
214 template <
typename T>
215 using is_nonconst_rvalue_ref
216 = std::integral_constant<bool,
217 conjunction<std::is_rvalue_reference<T>, negation<std::is_const<unref_t<T>>>>::value>;
220 template <
typename T,
typename U>
221 using add_t = decltype(std::declval<const T &>() + std::declval<const U &>());
232 template <
typename T,
typename U = T>
235 static const bool implementation_defined = is_detected<add_t, T, U>::value;
239 static const bool value = implementation_defined;
242 template <
typename T,
typename U>
253 template <
typename T,
typename U = T>
256 template <
typename T1,
typename U1>
257 using ip_add_t = decltype(std::declval<T1 &>() += std::declval<const U1 &>());
258 static const bool implementation_defined = is_detected<ip_add_t, T, U>::value;
262 static const bool value = implementation_defined;
265 template <
typename T,
typename U>
276 template <
typename T,
typename U = T>
279 template <
typename T1,
typename U1>
280 using sub_t = decltype(std::declval<const T1 &>() - std::declval<const U1 &>());
281 static const bool implementation_defined = is_detected<sub_t, T, U>::value;
285 static const bool value = implementation_defined;
288 template <
typename T,
typename U>
299 template <
typename T,
typename U = T>
302 template <
typename T1,
typename U1>
303 using ip_sub_t = decltype(std::declval<T1 &>() -= std::declval<const U1 &>());
304 static const bool implementation_defined = is_detected<ip_sub_t, T, U>::value;
308 static const bool value = implementation_defined;
311 template <
typename T,
typename U>
314 inline namespace impl
318 template <
typename T,
typename U>
319 using mul_t = decltype(std::declval<const T &>() * std::declval<const U &>());
330 template <
typename T,
typename U = T>
333 static const bool implementation_defined = is_detected<mul_t, T, U>::value;
337 static const bool value = implementation_defined;
340 template <
typename T,
typename U>
351 template <
typename T,
typename U = T>
354 template <
typename T1,
typename U1>
355 using ip_mul_t = decltype(std::declval<T1 &>() *= std::declval<const U1 &>());
356 static const bool implementation_defined = is_detected<ip_mul_t, T, U>::value;
360 static const bool value = implementation_defined;
363 template <
typename T,
typename U>
374 template <
typename T,
typename U = T>
377 template <
typename T1,
typename U1>
378 using div_t = decltype(std::declval<const T1 &>() / std::declval<const U1 &>());
379 static const bool implementation_defined = is_detected<div_t, T, U>::value;
383 static const bool value = implementation_defined;
386 template <
typename T,
typename U>
397 template <
typename T,
typename U = T>
400 template <
typename T1,
typename U1>
401 using ip_div_t = decltype(std::declval<T1 &>() /= std::declval<const U1 &>());
402 static const bool implementation_defined = is_detected<ip_div_t, T, U>::value;
406 static const bool value = implementation_defined;
409 template <
typename T,
typename U>
420 template <
typename T,
typename U = T>
423 template <
typename T1,
typename U1>
424 using ls_t = decltype(std::declval<const T1 &>() << std::declval<const U1 &>());
425 static const bool implementation_defined = is_detected<ls_t, T, U>::value;
429 static const bool value = implementation_defined;
432 template <
typename T,
typename U>
443 template <
typename T,
typename U = T>
446 template <
typename T1,
typename U1>
447 using rs_t = decltype(std::declval<const T1 &>() >> std::declval<const U1 &>());
448 static const bool implementation_defined = is_detected<rs_t, T, U>::value;
452 static const bool value = implementation_defined;
455 template <
typename T,
typename U>
466 template <
typename T,
typename U = T>
469 template <
typename T1,
typename U1>
470 using ls_t = decltype(std::declval<T1 &>() <<= std::declval<const U1 &>());
471 static const bool implementation_defined = is_detected<ls_t, T, U>::value;
475 static const bool value = implementation_defined;
478 template <
typename T,
typename U>
489 template <
typename T,
typename U = T>
492 template <
typename T1,
typename U1>
493 using rs_t = decltype(std::declval<T1 &>() >>= std::declval<const U1 &>());
494 static const bool implementation_defined = is_detected<rs_t, T, U>::value;
498 static const bool value = implementation_defined;
501 template <
typename T,
typename U>
510 template <
typename T,
typename U = T>
513 template <
typename T1,
typename U1>
514 using eq_t = decltype(std::declval<const T1 &>() == std::declval<const U1 &>());
515 template <
typename T1,
typename U1>
516 using ineq_t = decltype(std::declval<const T1 &>() != std::declval<const U1 &>());
517 static const bool implementation_defined = conjunction<std::is_convertible<detected_t<eq_t, T, U>,
bool>,
518 std::is_convertible<detected_t<ineq_t, T, U>,
bool>>
::value;
522 static const bool value = implementation_defined;
526 template <
typename T,
typename U>
535 template <
typename T,
typename U = T>
538 template <
typename T1,
typename U1>
539 using lt_t = decltype(std::declval<const T1 &>() < std::declval<const U1 &>());
540 static const bool implementation_defined = std::is_convertible<detected_t<lt_t, T, U>,
bool>
::value;
544 static const bool value = implementation_defined;
548 template <
typename T,
typename U>
558 template <
typename T,
typename U = T>
561 template <
typename T1,
typename U1>
562 using gt_t = decltype(std::declval<const T1 &>() > std::declval<const U1 &>());
563 static const bool implementation_defined = std::is_convertible<detected_t<gt_t, T, U>,
bool>
::value;
567 static const bool value = implementation_defined;
571 template <
typename T,
typename U>
582 template <
typename T,
typename =
void>
589 template <
typename T,
typename Enable>
603 template <
typename T>
608 static const bool implementation_defined
609 = conjunction<std::is_default_constructible<T>, std::is_copy_constructible<T>,
610 disjunction<negation<enable_noexcept_checks<T>>,
611 conjunction<std::is_nothrow_destructible<T>,
612 #if defined(PIRANHA_COMPILER_IS_INTEL) 615 std::is_move_constructible<T>, std::is_move_assignable<T>
618 std::is_nothrow_move_constructible<T>, std::is_nothrow_move_assignable<T>
624 static const bool value = implementation_defined;
627 template <
typename T>
639 template <
typename T>
642 template <
typename T1>
643 using ostreamable_t = decltype(std::declval<std::ostream &>() << std::declval<const T1 &>());
644 static const bool implementation_defined = std::is_same<detected_t<ostreamable_t, T>, std::ostream &>
::value;
648 static const bool value = implementation_defined;
651 template <
typename T>
667 template <
typename T,
typename ReturnType,
typename... Args>
670 template <
typename T1,
typename... Args1>
671 using ret_t = decltype(std::declval<T1 &>()(std::declval<Args1>()...));
672 static const bool implementation_defined
673 = conjunction<std::is_class<T>, std::is_same<detected_t<ret_t, T, Args...>, ReturnType>>
::value;
677 static const bool value = implementation_defined;
680 template <
typename T,
typename ReturnType,
typename... Args>
689 template <
typename T,
typename U>
693 static const bool implementation_defined
698 static const bool value = implementation_defined;
701 template <
typename T,
typename U>
710 template <
typename T,
typename U>
713 static const bool implementation_defined
714 = conjunction<is_function_object<const T, bool, const addlref_t<U>,
const addlref_t<U>>,
719 static const bool value = implementation_defined;
722 template <
typename T,
typename U>
738 template <
typename T>
745 static const bool value = implementation_defined;
748 template <
typename T>
769 #define PIRANHA_DECLARE_HAS_TYPEDEF(type_name) \ 770 template <typename PIRANHA_DECLARE_HAS_TYPEDEF_ARGUMENT> \ 771 class has_typedef_##type_name \ 773 using Td_ = piranha::uncvref_t<PIRANHA_DECLARE_HAS_TYPEDEF_ARGUMENT>; \ 774 template <typename U> \ 775 using type_t = typename U::type_name; \ 778 static const bool value = piranha::is_detected<type_t, Td_>::value; \ 786 #define PIRANHA_TT_CHECK(tt, ...) \ 787 static_assert(tt<__VA_ARGS__>::value, "type trait check failure -> " #tt "<" #__VA_ARGS__ ">") 795 template <
typename T,
typename... Args>
796 struct min_int_impl {
797 using next =
typename min_int_impl<Args...>::type;
798 static_assert((std::is_unsigned<T>::value && std::is_unsigned<next>::value && std::is_integral<next>::value)
799 || (std::is_signed<T>::value && std::is_signed<next>::value && std::is_integral<next>::value),
800 "The type trait's arguments must all be (un)signed integers.");
801 using type =
typename std::conditional<(std::numeric_limits<T>::max() < std::numeric_limits<next>::max()
802 && (std::is_unsigned<T>::value
803 || std::numeric_limits<T>::min() > std::numeric_limits<next>::min())),
807 template <
typename T>
808 struct min_int_impl<T> {
809 static_assert(std::is_integral<T>::value,
"The type trait's arguments must all be (un)signed integers.");
813 template <
typename T,
typename... Args>
814 struct max_int_impl {
815 using next =
typename max_int_impl<Args...>::type;
816 static_assert((std::is_unsigned<T>::value && std::is_unsigned<next>::value && std::is_integral<next>::value)
817 || (std::is_signed<T>::value && std::is_signed<next>::value && std::is_integral<next>::value),
818 "The type trait's arguments must all be (un)signed integers.");
819 using type =
typename std::conditional<(std::numeric_limits<T>::max() > std::numeric_limits<next>::max()
820 && (std::is_unsigned<T>::value
821 || std::numeric_limits<T>::min() < std::numeric_limits<next>::min())),
825 template <
typename T>
826 struct max_int_impl<T> {
827 static_assert(std::is_integral<T>::value,
"The type trait's arguments must all be (un)signed integers.");
837 template <
typename T,
typename... Args>
838 using min_int =
typename detail::min_int_impl<T, Args...>::type;
845 template <
typename T,
typename... Args>
846 using max_int =
typename detail::max_int_impl<T, Args...>::type;
848 inline namespace impl
851 #if !defined(PIRANHA_DOXYGEN_INVOKED) 861 template <
typename It>
862 struct has_iterator_traits {
863 using it_tags = std::tuple<std::input_iterator_tag, std::output_iterator_tag, std::forward_iterator_tag,
864 std::bidirectional_iterator_tag, std::random_access_iterator_tag>;
870 using i_traits = std::iterator_traits<It>;
871 static const bool value
872 = conjunction<has_typedef_reference<i_traits>, has_typedef_value_type<i_traits>, has_typedef_pointer<i_traits>,
873 has_typedef_difference_type<i_traits>, has_typedef_iterator_category<i_traits>,
874 std::is_copy_constructible<It>, std::is_copy_assignable<It>, std::is_destructible<It>>::value;
878 template <
typename,
typename>
879 struct convertible_type_in_tuple {
882 template <
typename T,
typename... Args>
883 struct convertible_type_in_tuple<T,
std::tuple<Args...>> {
884 static const bool value = disjunction<std::is_convertible<T, Args>...>::value;
900 template <
typename T>
903 template <
typename U>
904 using deref_t = decltype(*std::declval<U &>());
905 template <
typename U>
906 using inc_t = decltype(++std::declval<U &>());
907 template <
typename U>
908 using it_cat =
typename std::iterator_traits<U>::iterator_category;
909 using uT = uncvref_t<T>;
910 static const bool implementation_defined = conjunction<
919 is_detected<deref_t, uT>, std::is_same<detected_t<inc_t, uT>, addlref_t<uT>>, has_iterator_traits<uT>,
923 convertible_type_in_tuple<detected_t<it_cat, uT>,
typename has_iterator_traits<uT>::it_tags>>
::value;
927 static const bool value = implementation_defined;
930 template <
typename T>
933 inline namespace impl
936 #if !defined(PIRANHA_DOXYGEN_INVOKED) 942 template <
typename U,
typename =
void>
943 struct arrow_operator_type {
947 template <
typename U>
948 struct arrow_operator_type<U *> {
953 template <
typename U>
954 using arrow_operator_t =
typename arrow_operator_type<U>::type;
957 template <
typename U>
958 using rec_arrow_op_t = arrow_operator_t<decltype(std::declval<U &>().operator->())>;
960 template <
typename U>
961 struct arrow_operator_type<U, enable_if_t<is_detected<rec_arrow_op_t, U>::value>> {
962 using type = rec_arrow_op_t<U>;
967 template <
typename T,
typename =
void>
968 struct is_input_iterator_impl : std::false_type {
971 template <
typename T>
972 struct is_input_iterator_impl<
974 enable_if_t<conjunction<
975 is_iterator<T>, is_equality_comparable<T>,
976 std::is_convertible<decltype(*std::declval<T &>()), typename std::iterator_traits<T>::value_type>,
977 std::is_same<decltype(++std::declval<T &>()), T &>,
978 std::is_same<decltype((void)std::declval<T &>()++), decltype((void)++std::declval<T &>())>,
979 std::is_convertible<decltype(*std::declval<T &>()++), typename std::iterator_traits<T>::value_type>,
984 std::is_same<unref_t<decltype(*std::declval<arrow_operator_t<T>>())>, unref_t<decltype(*std::declval<T &>())>>,
988 std::is_convertible<typename std::iterator_traits<T>::iterator_category, std::input_iterator_tag>>::value>>
1000 template <
typename T>
1003 static const bool implementation_defined = is_input_iterator_impl<uncvref_t<T>>
::value;
1007 static const bool value = implementation_defined;
1010 template <
typename T>
1013 inline namespace impl
1016 template <
typename T,
typename =
void>
1017 struct is_forward_iterator_impl : std::false_type {
1020 template <
typename T>
1021 struct is_forward_iterator_impl<
1022 T, enable_if_t<conjunction<
1023 is_input_iterator<T>,
std::is_default_constructible<T>,
1024 disjunction<std::is_same<typename std::iterator_traits<T>::value_type &,
1025 typename std::iterator_traits<T>::reference>,
1026 std::is_same<typename std::iterator_traits<T>::value_type const &,
1027 typename std::iterator_traits<T>::reference>>,
1028 std::is_convertible<decltype(std::declval<T &>()++), const T &>,
1029 std::is_same<decltype(*std::declval<T &>()++), typename std::iterator_traits<T>::reference>,
1030 std::is_convertible<typename std::iterator_traits<T>::iterator_category, std::forward_iterator_tag>>::value>>
1040 template <
typename T>
1043 static const bool implementation_defined = is_forward_iterator_impl<uncvref_t<T>>
::value;
1047 static const bool value = implementation_defined;
1050 template <
typename T>
1056 #if !defined(PIRANHA_DOXYGEN_INVOKED) 1057 template <
typename T>
1058 constexpr T safe_abs_sint_impl(T cur_p = T(1), T cur_n = T(-1))
1060 return (cur_p > std::numeric_limits<T>::max() / T(2) || cur_n < std::numeric_limits<T>::min() / T(2))
1062 : safe_abs_sint_impl(static_cast<T>(cur_p * 2), static_cast<T>(cur_n * 2));
1066 template <
typename T>
1067 struct safe_abs_sint {
1068 static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
"T must be a signed integral type.");
1069 static const T value = safe_abs_sint_impl<T>();
1072 template <
typename T>
1073 const T safe_abs_sint<T>::value;
1078 template <
typename T>
1080 static const bool value =
true;
1083 template <
typename T>
1084 const bool true_tt<T>::value;
1094 template <
typename T>
1097 template <
typename U>
1098 using begin_t = decltype(std::begin(std::declval<U &>()));
1099 template <
typename U>
1100 using end_t = decltype(std::end(std::declval<U &>()));
1101 static const bool implementation_defined
1103 std::is_same<detected_t<begin_t, T>, detected_t<end_t, T>>>
::value;
1107 static const bool value = implementation_defined;
1110 template <
typename T>
1118 template <
typename T>
1121 static const bool implementation_defined
1122 = disjunction<std::is_same<T, void>,
1123 conjunction<std::is_destructible<T>,
1124 disjunction<std::is_copy_constructible<T>, std::is_move_constructible<T>>>>
::value;
1128 static const bool value = implementation_defined;
1131 template <
typename T>
1146 template <
typename T,
typename =
void>
1156 template <
typename T,
typename Enable>
1159 inline namespace impl
1163 template <
typename T>
1164 using fp_zero_is_absorbing_enabler = enable_if_t<std::is_floating_point<uncvref_t<T>>::value
1165 && (std::numeric_limits<uncvref_t<T>>::has_quiet_NaN
1166 || std::numeric_limits<uncvref_t<T>>::has_signaling_NaN)>;
1178 template <
typename T>
1188 template <
typename T>
Greater-than-comparable type trait.
Function object type trait.
Equality-comparable type trait.
static const bool value
Value of the type trait.
In-place divisible type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
In-place addable type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
#define PIRANHA_DECLARE_HAS_TYPEDEF(type_name)
Macro to test if class has type definition.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
Forward iterator type trait.
static const bool value
Value of the type trait.
typename detail::min_int_impl< T, Args... >::type min_int
Detect narrowest integer type.
In-place subtractable type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
static const bool value
Default value of the type trait.
Detect if zero is a multiplicative absorber.
static const bool value
Value of the type trait.
Detect if type can be returned from a function.
In-place right-shift type trait.
static const bool value
Value of the type trait.
In-place left-shift type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
In-place multipliable type trait.
static const bool value
Value of the type trait.
Less-than-comparable type trait.
static const bool value
Value of the type trait.
typename detail::max_int_impl< T, Args... >::type max_int
Detect widest integer type.
static const bool value
Value of the type trait.
Type trait for classes that can be output-streamed.
Type trait to detect equality function objects.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
Type trait to detect hash function objects.
Type trait for well-behaved container elements.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.