typetraits.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #pragma once
  2. #include "va_args.h"
  3. #include <util/system/defaults.h>
  4. #include <iterator>
  5. #include <type_traits>
  6. #include <stlfwd>
  7. #if _LIBCPP_STD_VER >= 17
  8. template <bool B>
  9. using TBoolConstant = std::bool_constant<B>;
  10. #else
  11. template <bool B>
  12. struct TBoolConstant: std::integral_constant<bool, B> {};
  13. #endif
  14. #if _LIBCPP_STD_VER >= 17
  15. template <class B>
  16. using TNegation = std::negation<B>;
  17. #else
  18. template <class B>
  19. struct TNegation: ::TBoolConstant<!bool(B::value)> {};
  20. #endif
  21. namespace NPrivate {
  22. template <class... Bs>
  23. constexpr bool ConjunctionImpl() {
  24. bool bs[] = {(bool)Bs::value...};
  25. for (auto b : bs) {
  26. if (!b) {
  27. return false;
  28. }
  29. }
  30. return true;
  31. }
  32. template <class... Bs>
  33. constexpr bool DisjunctionImpl() {
  34. bool bs[] = {(bool)Bs::value...};
  35. for (auto b : bs) {
  36. if (b) {
  37. return true;
  38. }
  39. }
  40. return false;
  41. }
  42. }
  43. #if _LIBCPP_STD_VER >= 17 && !defined(_MSC_VER)
  44. // Disable std::conjunction for MSVC by analogy with std::disjunction.
  45. template <class... Bs>
  46. using TConjunction = std::conjunction<Bs...>;
  47. #else
  48. template <class... Bs>
  49. struct TConjunction: ::TBoolConstant<::NPrivate::ConjunctionImpl<Bs...>()> {};
  50. #endif
  51. #if _LIBCPP_STD_VER >= 17 && !defined(_MSC_VER)
  52. // Disable std::disjunction for MSVC.
  53. // It reduces build time (500 -> 20 seconds) and memory consumption (20 GB -> less than 1 GB)
  54. // for some files (notably search/dssm_boosting/dssm_boosting_calcer.cpp).
  55. template <class... Bs>
  56. using TDisjunction = std::disjunction<Bs...>;
  57. #else
  58. template <class... Bs>
  59. struct TDisjunction: ::TBoolConstant<::NPrivate::DisjunctionImpl<Bs...>()> {};
  60. #endif
  61. #if _LIBCPP_STD_VER >= 17
  62. template <class... Bs>
  63. using TVoidT = std::void_t<Bs...>;
  64. #else
  65. template <class...>
  66. using TVoidT = void;
  67. #endif
  68. template <class T>
  69. struct TPodTraits {
  70. enum {
  71. IsPod = false
  72. };
  73. };
  74. template <class T>
  75. class TTypeTraitsBase {
  76. public:
  77. static constexpr bool IsPod = (TPodTraits<std::remove_cv_t<T>>::IsPod || std::is_scalar<std::remove_all_extents_t<T>>::value ||
  78. TPodTraits<std::remove_cv_t<std::remove_all_extents_t<T>>>::IsPod);
  79. };
  80. namespace NPrivate {
  81. template <class T>
  82. struct TIsSmall: std::integral_constant<bool, (sizeof(T) <= sizeof(void*))> {};
  83. }
  84. template <class T>
  85. class TTypeTraits: public TTypeTraitsBase<T> {
  86. using TBase = TTypeTraitsBase<T>;
  87. /*
  88. * can be effectively passed to function as value
  89. */
  90. static constexpr bool IsValueType = std::is_scalar<T>::value ||
  91. std::is_array<T>::value ||
  92. std::is_reference<T>::value ||
  93. (TBase::IsPod &&
  94. std::conditional_t<
  95. std::is_function<T>::value,
  96. std::false_type,
  97. ::NPrivate::TIsSmall<T>>::value);
  98. public:
  99. /*
  100. * can be used in function templates for effective parameters passing
  101. */
  102. using TFuncParam = std::conditional_t<IsValueType, T, const std::remove_reference_t<T>&>;
  103. };
  104. template <>
  105. class TTypeTraits<void>: public TTypeTraitsBase<void> {};
  106. #define Y_DECLARE_PODTYPE(type) \
  107. template <> \
  108. struct TPodTraits<type> { \
  109. enum { IsPod = true }; \
  110. }
  111. #define Y_HAS_MEMBER_IMPL_2(method, name) \
  112. template <class T> \
  113. struct TClassHas##name { \
  114. struct TBase { \
  115. void method(); \
  116. }; \
  117. class THelper: public T, public TBase { \
  118. public: \
  119. template <class T1> \
  120. inline THelper(const T1& = T1()) { \
  121. } \
  122. }; \
  123. template <class T1, T1 val> \
  124. class TChecker {}; \
  125. struct TNo { \
  126. char ch; \
  127. }; \
  128. struct TYes { \
  129. char arr[2]; \
  130. }; \
  131. template <class T1> \
  132. static TNo CheckMember(T1*, TChecker<void (TBase::*)(), &T1::method>* = nullptr); \
  133. static TYes CheckMember(...); \
  134. static constexpr bool value = \
  135. (sizeof(TYes) == sizeof(CheckMember((THelper*)nullptr))); \
  136. }; \
  137. template <class T, bool isClassType> \
  138. struct TBaseHas##name: std::false_type {}; \
  139. template <class T> \
  140. struct TBaseHas##name<T, true> \
  141. : std::integral_constant<bool, TClassHas##name<T>::value> {}; \
  142. template <class T> \
  143. struct THas##name \
  144. : TBaseHas##name<T, std::is_class<T>::value || std::is_union<T>::value> {}
  145. #define Y_HAS_MEMBER_IMPL_1(name) Y_HAS_MEMBER_IMPL_2(name, name)
  146. /* @def Y_HAS_MEMBER
  147. *
  148. * This macro should be used to define compile-time introspection helper classes for template
  149. * metaprogramming.
  150. *
  151. * Macro accept one or two parameters, when used with two parameters e.g. `Y_HAS_MEMBER(xyz, ABC)`
  152. * will define class `THasABC` with static member `value` of type bool. Usage with one parameter
  153. * e.g. `Y_HAS_MEMBER(xyz)` will produce the same result as `Y_HAS_MEMBER(xyz, xyz)`.
  154. *
  155. * @code
  156. * #include <type_traits>
  157. *
  158. * Y_HAS_MEMBER(push_front, PushFront);
  159. *
  160. * template <typename T, typename U>
  161. * std::enable_if_t<THasPushFront<T>::value, void>
  162. * PushFront(T& container, const U value) {
  163. * container.push_front(x);
  164. * }
  165. *
  166. * template <typename T, typename U>
  167. * std::enable_if_t<!THasPushFront<T>::value, void>
  168. * PushFront(T& container, const U value) {
  169. * container.insert(container.begin(), x);
  170. * }
  171. * @endcode
  172. */
  173. #define Y_HAS_MEMBER(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, Y_HAS_MEMBER_IMPL_2, Y_HAS_MEMBER_IMPL_1)(__VA_ARGS__))
  174. #define Y_HAS_SUBTYPE_IMPL_2(subtype, name) \
  175. template <class T, class = void> \
  176. struct THas##name: std::false_type {}; \
  177. template <class T> \
  178. struct THas##name<T, ::TVoidT<typename T::subtype>>: std::true_type {}
  179. #define Y_HAS_SUBTYPE_IMPL_1(name) Y_HAS_SUBTYPE_IMPL_2(name, name)
  180. /* @def Y_HAS_SUBTYPE
  181. *
  182. * This macro should be used to define compile-time introspection helper classes for template
  183. * metaprogramming.
  184. *
  185. * Macro accept one or two parameters, when used with two parameters e.g. `Y_HAS_SUBTYPE(xyz, ABC)`
  186. * will define class `THasABC` with static member `value` of type bool. Usage with one parameter
  187. * e.g. `Y_HAS_SUBTYPE(xyz)` will produce the same result as `Y_HAS_SUBTYPE(xyz, xyz)`.
  188. *
  189. * @code
  190. * Y_HAS_MEMBER(find, FindMethod);
  191. * Y_HAS_SUBTYPE(const_iterator, ConstIterator);
  192. * Y_HAS_SUBTYPE(key_type, KeyType);
  193. *
  194. * template <typename T>
  195. * using TIsAssocCont = std::conditional_t<
  196. * THasFindMethod<T>::value && THasConstIterator<T>::value && THasKeyType<T>::value,
  197. * std::true_type,
  198. * std::false_type,
  199. * >;
  200. *
  201. * static_assert(TIsAssocCont<TVector<int>>::value == false, "");
  202. * static_assert(TIsAssocCont<THashMap<int>>::value == true, "");
  203. * @endcode
  204. */
  205. #define Y_HAS_SUBTYPE(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, Y_HAS_SUBTYPE_IMPL_2, Y_HAS_SUBTYPE_IMPL_1)(__VA_ARGS__))
  206. template <class T1, class T2>
  207. struct TPodTraits<std::pair<T1, T2>> {
  208. enum {
  209. IsPod = TTypeTraits<T1>::IsPod && TTypeTraits<T2>::IsPod
  210. };
  211. };
  212. template <class T>
  213. struct TIsPointerToConstMemberFunction: std::false_type {
  214. };
  215. template <class R, class T, class... Args>
  216. struct TIsPointerToConstMemberFunction<R (T::*)(Args...) const>: std::true_type {
  217. };
  218. template <class R, class T, class... Args>
  219. struct TIsPointerToConstMemberFunction<R (T::*)(Args...) const&>: std::true_type {
  220. };
  221. template <class R, class T, class... Args>
  222. struct TIsPointerToConstMemberFunction<R (T::*)(Args...) const&&>: std::true_type {
  223. };
  224. template <class R, class T, class... Args>
  225. struct TIsPointerToConstMemberFunction<R (T::*)(Args..., ...) const>: std::true_type {
  226. };
  227. template <class R, class T, class... Args>
  228. struct TIsPointerToConstMemberFunction<R (T::*)(Args..., ...) const&>: std::true_type {
  229. };
  230. template <class R, class T, class... Args>
  231. struct TIsPointerToConstMemberFunction<R (T::*)(Args..., ...) const&&>: std::true_type {
  232. };
  233. namespace NPrivate {
  234. template <template <typename...> class TBase, class TDerived>
  235. struct TIsBaseOfTemplateHelper {
  236. template <typename... Ts>
  237. static constexpr std::true_type Check(const TBase<Ts...>*);
  238. static constexpr std::false_type Check(...);
  239. using TType = decltype(Check(std::declval<TDerived*>()));
  240. };
  241. }
  242. template <template <class...> class T, class U>
  243. struct TIsSpecializationOf: std::false_type {};
  244. template <template <class...> class T, class... Ts>
  245. struct TIsSpecializationOf<T, T<Ts...>>: std::true_type {};
  246. template <template <typename...> class TBase, class TDerived>
  247. using TIsTemplateBaseOf = typename ::NPrivate::TIsBaseOfTemplateHelper<TBase, TDerived>::TType;
  248. /*
  249. * TDependentFalse is a constant dependent on a template parameter.
  250. * Use it in static_assert in a false branch of if constexpr to produce a compile error.
  251. * See an example with dependent_false at https://en.cppreference.com/w/cpp/language/if
  252. *
  253. * if constexpr (std::is_same<T, someType1>) {
  254. * } else if constexpr (std::is_same<T, someType2>) {
  255. * } else {
  256. * static_assert(TDependentFalse<T>, "unknown type");
  257. * }
  258. */
  259. template <typename... T>
  260. constexpr bool TDependentFalse = false;
  261. // FIXME: neither nvcc10 nor nvcc11 support using auto in this context
  262. #if defined(__NVCC__)
  263. template <size_t Value>
  264. constexpr bool TValueDependentFalse = false;
  265. #else
  266. template <auto... Values>
  267. constexpr bool TValueDependentFalse = false;
  268. #endif
  269. /*
  270. * shortcut for std::enable_if_t<...> which checks that T is std::tuple or std::pair
  271. */
  272. template <class T, class R = void>
  273. using TEnableIfTuple = std::enable_if_t<::TDisjunction<::TIsSpecializationOf<std::tuple, std::decay_t<T>>,
  274. ::TIsSpecializationOf<std::pair, std::decay_t<T>>>::value,
  275. R>;
  276. namespace NPrivate {
  277. // To allow ADL with custom begin/end
  278. using std::begin;
  279. using std::end;
  280. template <typename T>
  281. auto IsIterableImpl(int) -> decltype(
  282. begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
  283. ++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
  284. *begin(std::declval<T&>()), // operator*
  285. std::true_type{});
  286. template <typename T>
  287. std::false_type IsIterableImpl(...);
  288. }
  289. template <typename T>
  290. using TIsIterable = decltype(NPrivate::IsIterableImpl<T>(0));