typetraits_ut.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #include "typetraits.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include <vector>
  4. #include <tuple>
  5. namespace {
  6. enum ETestEnum {
  7. };
  8. class TPodClass {
  9. };
  10. class TNonPodClass {
  11. TNonPodClass() {
  12. }
  13. };
  14. class TEmptyClass {
  15. void operator()() const {
  16. }
  17. };
  18. class TAnotherEmptyClass {
  19. };
  20. class TEmptyDerivedClass: public TEmptyClass {
  21. };
  22. class TEmptyMultiDerivedClass: public TEmptyDerivedClass, public TAnotherEmptyClass {
  23. /* Not empty under MSVC.
  24. * MSVC's EBCO implementation can handle only one empty base class. */
  25. };
  26. struct TNonEmptyClass {
  27. TEmptyClass member;
  28. };
  29. class TNonEmptyDerivedClass: public TNonEmptyClass {
  30. };
  31. class TStdLayoutClass1: public TEmptyClass {
  32. public:
  33. int Value1;
  34. int Value2;
  35. };
  36. class TStdLayoutClass2: public TNonEmptyClass {
  37. };
  38. class TNonStdLayoutClass1 {
  39. public:
  40. int Value1;
  41. protected:
  42. int Value2;
  43. };
  44. class TNonStdLayoutClass2 {
  45. public:
  46. virtual void Func() {
  47. }
  48. };
  49. class TNonStdLayoutClass3: public TNonStdLayoutClass2 {
  50. };
  51. class TNonStdLayoutClass4: public TEmptyClass {
  52. public:
  53. TEmptyClass Base;
  54. };
  55. }
  56. #define ASSERT_SAME_TYPE(x, y) \
  57. { \
  58. const bool x_ = std::is_same<x, y>::value; \
  59. UNIT_ASSERT_C(x_, #x " != " #y); \
  60. }
  61. Y_UNIT_TEST_SUITE(TTypeTraitsTest) {
  62. Y_UNIT_TEST(TestIsSame) {
  63. UNIT_ASSERT((std::is_same<int, int>::value));
  64. UNIT_ASSERT(!(std::is_same<signed int, unsigned int>::value));
  65. }
  66. Y_UNIT_TEST(TestRemoveReference) {
  67. ASSERT_SAME_TYPE(std::remove_reference_t<int>, int);
  68. ASSERT_SAME_TYPE(std::remove_reference_t<const int>, const int);
  69. ASSERT_SAME_TYPE(std::remove_reference_t<int&>, int);
  70. ASSERT_SAME_TYPE(std::remove_reference_t<const int&>, const int);
  71. ASSERT_SAME_TYPE(std::remove_reference_t<int&&>, int);
  72. ASSERT_SAME_TYPE(std::remove_reference_t<const int&&>, const int);
  73. class TIncompleteType;
  74. ASSERT_SAME_TYPE(std::remove_reference_t<TIncompleteType&>, TIncompleteType);
  75. }
  76. Y_UNIT_TEST(TestRemoveConst) {
  77. ASSERT_SAME_TYPE(std::remove_const_t<const int>, int);
  78. }
  79. Y_UNIT_TEST(TestRemoveVolatile) {
  80. ASSERT_SAME_TYPE(std::remove_volatile_t<volatile int>, int);
  81. }
  82. Y_UNIT_TEST(TestRemoveCV) {
  83. ASSERT_SAME_TYPE(std::remove_cv_t<const volatile int>, int);
  84. }
  85. Y_UNIT_TEST(TestAddCV) {
  86. ASSERT_SAME_TYPE(std::add_cv_t<int>, const volatile int);
  87. }
  88. Y_UNIT_TEST(TestClass) {
  89. UNIT_ASSERT(std::is_class<TString>::value);
  90. UNIT_ASSERT(!std::is_class<ETestEnum>::value);
  91. UNIT_ASSERT(!std::is_class<int>::value);
  92. UNIT_ASSERT(!std::is_class<void*>::value);
  93. }
  94. template <class T>
  95. inline void TestArithmeticType() {
  96. UNIT_ASSERT(std::is_arithmetic<T>::value);
  97. UNIT_ASSERT(std::is_arithmetic<const T>::value);
  98. UNIT_ASSERT(std::is_arithmetic<volatile T>::value);
  99. UNIT_ASSERT(std::is_arithmetic<const volatile T>::value);
  100. UNIT_ASSERT(!std::is_arithmetic<T&>::value);
  101. UNIT_ASSERT(!std::is_arithmetic<T&&>::value);
  102. UNIT_ASSERT(!std::is_arithmetic<T*>::value);
  103. bool a;
  104. a = std::is_same<typename TTypeTraits<T>::TFuncParam, T>::value;
  105. UNIT_ASSERT(a);
  106. a = std::is_same<typename TTypeTraits<const volatile T>::TFuncParam, const volatile T>::value;
  107. UNIT_ASSERT(a);
  108. }
  109. template <class T>
  110. inline void TestUnsignedIntType() {
  111. UNIT_ASSERT(std::is_unsigned<T>::value);
  112. UNIT_ASSERT(std::is_unsigned<const T>::value);
  113. UNIT_ASSERT(std::is_unsigned<volatile T>::value);
  114. UNIT_ASSERT(std::is_unsigned<const volatile T>::value);
  115. UNIT_ASSERT(!std::is_unsigned<T&>::value);
  116. UNIT_ASSERT(!std::is_unsigned<T&&>::value);
  117. UNIT_ASSERT(!std::is_unsigned<T*>::value);
  118. enum ETypedEnum: T {};
  119. UNIT_ASSERT(!std::is_unsigned<ETypedEnum>::value);
  120. }
  121. template <class T>
  122. inline void TestSignedIntType() {
  123. UNIT_ASSERT(std::is_signed<T>::value);
  124. UNIT_ASSERT(std::is_signed<const T>::value);
  125. UNIT_ASSERT(std::is_signed<volatile T>::value);
  126. UNIT_ASSERT(std::is_signed<const volatile T>::value);
  127. UNIT_ASSERT(!std::is_signed<T&>::value);
  128. UNIT_ASSERT(!std::is_signed<T&&>::value);
  129. UNIT_ASSERT(!std::is_signed<T*>::value);
  130. enum ETypedEnum: T {};
  131. UNIT_ASSERT(!std::is_signed<ETypedEnum>::value);
  132. }
  133. Y_UNIT_TEST(TestBool) {
  134. TestArithmeticType<bool>();
  135. TestUnsignedIntType<bool>();
  136. }
  137. Y_UNIT_TEST(TestUnsignedChar) {
  138. TestArithmeticType<unsigned char>();
  139. TestUnsignedIntType<unsigned char>();
  140. }
  141. Y_UNIT_TEST(TestSizeT) {
  142. TestArithmeticType<size_t>();
  143. TestUnsignedIntType<size_t>();
  144. }
  145. Y_UNIT_TEST(TestInt) {
  146. TestArithmeticType<int>();
  147. TestSignedIntType<int>();
  148. }
  149. Y_UNIT_TEST(TestDouble) {
  150. TestArithmeticType<double>();
  151. }
  152. Y_UNIT_TEST(TestLongDouble) {
  153. TestArithmeticType<long double>();
  154. }
  155. Y_UNIT_TEST(TestAddRValueReference) {
  156. ASSERT_SAME_TYPE(std::add_rvalue_reference_t<int>, int&&);
  157. ASSERT_SAME_TYPE(std::add_rvalue_reference_t<int const&>, int const&);
  158. ASSERT_SAME_TYPE(std::add_rvalue_reference_t<int*>, int*&&);
  159. ASSERT_SAME_TYPE(std::add_rvalue_reference_t<int*&>, int*&);
  160. ASSERT_SAME_TYPE(std::add_rvalue_reference_t<int&&>, int&&);
  161. ASSERT_SAME_TYPE(std::add_rvalue_reference_t<void>, void);
  162. }
  163. Y_UNIT_TEST(TestIsEmpty) {
  164. UNIT_ASSERT(std::is_empty<TEmptyClass>::value);
  165. UNIT_ASSERT(std::is_empty<TEmptyDerivedClass>::value);
  166. UNIT_ASSERT(std::is_empty<TAnotherEmptyClass>::value);
  167. #ifdef _MSC_VER
  168. UNIT_ASSERT(!std::is_empty<TEmptyMultiDerivedClass>::value);
  169. #else
  170. UNIT_ASSERT(std::is_empty<TEmptyMultiDerivedClass>::value);
  171. #endif
  172. UNIT_ASSERT(!std::is_empty<TNonEmptyClass>::value);
  173. UNIT_ASSERT(!std::is_empty<TNonEmptyDerivedClass>::value);
  174. }
  175. Y_UNIT_TEST(TestIsStandardLayout) {
  176. UNIT_ASSERT(std::is_standard_layout<TStdLayoutClass1>::value);
  177. UNIT_ASSERT(std::is_standard_layout<TStdLayoutClass2>::value);
  178. UNIT_ASSERT(!std::is_standard_layout<TNonStdLayoutClass1>::value);
  179. UNIT_ASSERT(!std::is_standard_layout<TNonStdLayoutClass2>::value);
  180. UNIT_ASSERT(!std::is_standard_layout<TNonStdLayoutClass3>::value);
  181. UNIT_ASSERT(!std::is_standard_layout<TNonStdLayoutClass4>::value);
  182. }
  183. template <class T>
  184. using TTrySum = decltype(std::declval<T>() + std::declval<T>());
  185. Y_UNIT_TEST(TestIsTriviallyCopyable) {
  186. struct TPod {
  187. int value;
  188. };
  189. struct TNontriviallyCopyAssignable {
  190. TNontriviallyCopyAssignable(const TNontriviallyCopyAssignable&) = default;
  191. TNontriviallyCopyAssignable& operator=(const TNontriviallyCopyAssignable&);
  192. };
  193. struct TNonTriviallyCopyConstructible {
  194. TNonTriviallyCopyConstructible(const TNonTriviallyCopyConstructible&);
  195. TNonTriviallyCopyConstructible& operator=(const TNonTriviallyCopyConstructible&) = default;
  196. };
  197. struct TNonTriviallyDestructible {
  198. TNonTriviallyDestructible(const TNonTriviallyDestructible&) = default;
  199. TNonTriviallyDestructible& operator=(const TNonTriviallyDestructible&) = default;
  200. ~TNonTriviallyDestructible();
  201. };
  202. UNIT_ASSERT(std::is_trivially_copyable<int>::value);
  203. UNIT_ASSERT(std::is_trivially_copyable<TPod>::value);
  204. UNIT_ASSERT(!std::is_trivially_copyable<TNontriviallyCopyAssignable>::value);
  205. UNIT_ASSERT(!std::is_trivially_copyable<TNonTriviallyCopyConstructible>::value);
  206. UNIT_ASSERT(!std::is_trivially_copyable<TNonTriviallyDestructible>::value);
  207. }
  208. }
  209. namespace {
  210. template <typename T>
  211. struct TTypeTraitsExpected;
  212. template <>
  213. struct TTypeTraitsExpected<void> {
  214. enum { IsIntegral = false };
  215. enum { IsArithmetic = false };
  216. enum { IsPod = true };
  217. enum { IsVolatile = false };
  218. enum { IsConstant = false };
  219. enum { IsPointer = false };
  220. enum { IsReference = false };
  221. enum { IsLvalueReference = false };
  222. enum { IsRvalueReference = false };
  223. enum { IsArray = false };
  224. enum { IsClassType = false };
  225. enum { IsVoid = true };
  226. enum { IsEnum = false };
  227. };
  228. template <>
  229. struct TTypeTraitsExpected<int>: public TTypeTraitsExpected<void> {
  230. enum { IsIntegral = true };
  231. enum { IsArithmetic = true };
  232. enum { IsVoid = false };
  233. };
  234. template <>
  235. struct TTypeTraitsExpected<size_t>: public TTypeTraitsExpected<int> {
  236. };
  237. template <>
  238. struct TTypeTraitsExpected<float>: public TTypeTraitsExpected<int> {
  239. enum { IsIntegral = false };
  240. };
  241. template <>
  242. struct TTypeTraitsExpected<long double>: public TTypeTraitsExpected<float> {
  243. };
  244. template <>
  245. struct TTypeTraitsExpected<const int>: public TTypeTraitsExpected<int> {
  246. enum { IsConstant = true };
  247. };
  248. template <>
  249. struct TTypeTraitsExpected<volatile int>: public TTypeTraitsExpected<int> {
  250. enum { IsVolatile = true };
  251. };
  252. template <>
  253. struct TTypeTraitsExpected<ETestEnum>: public TTypeTraitsExpected<int> {
  254. enum { IsIntegral = false };
  255. enum { IsArithmetic = false };
  256. enum { IsEnum = true };
  257. };
  258. template <>
  259. struct TTypeTraitsExpected<TPodClass>: public TTypeTraitsExpected<void> {
  260. enum { IsClassType = true };
  261. enum { IsVoid = false };
  262. };
  263. template <>
  264. struct TTypeTraitsExpected<TNonPodClass>: public TTypeTraitsExpected<TPodClass> {
  265. enum { IsPod = false };
  266. };
  267. template <>
  268. struct TTypeTraitsExpected<TNonPodClass&>: public TTypeTraitsExpected<TNonPodClass> {
  269. enum { IsClassType = false };
  270. enum { IsReference = true };
  271. enum { IsLvalueReference = true };
  272. };
  273. template <>
  274. struct TTypeTraitsExpected<TNonPodClass&&>: public TTypeTraitsExpected<TNonPodClass> {
  275. enum { IsClassType = false };
  276. enum { IsReference = true };
  277. enum { IsRvalueReference = true };
  278. };
  279. template <>
  280. struct TTypeTraitsExpected<const TNonPodClass&>: public TTypeTraitsExpected<TNonPodClass&> {
  281. };
  282. template <>
  283. struct TTypeTraitsExpected<float*>: public TTypeTraitsExpected<int> {
  284. enum { IsIntegral = false };
  285. enum { IsArithmetic = false };
  286. enum { IsPointer = true };
  287. };
  288. template <>
  289. struct TTypeTraitsExpected<float&>: public TTypeTraitsExpected<float*> {
  290. enum { IsPointer = false };
  291. enum { IsReference = true };
  292. enum { IsLvalueReference = true };
  293. };
  294. template <>
  295. struct TTypeTraitsExpected<float&&>: public TTypeTraitsExpected<float*> {
  296. enum { IsPointer = false };
  297. enum { IsReference = true };
  298. enum { IsRvalueReference = true };
  299. };
  300. template <>
  301. struct TTypeTraitsExpected<const float&>: public TTypeTraitsExpected<float&> {
  302. };
  303. template <>
  304. struct TTypeTraitsExpected<float[17]>: public TTypeTraitsExpected<int> {
  305. enum { IsIntegral = false };
  306. enum { IsArithmetic = false };
  307. enum { IsArray = true };
  308. };
  309. }
  310. #define UNIT_ASSERT_EQUAL_ENUM(expected, actual) UNIT_ASSERT_VALUES_EQUAL((bool)(expected), (bool)(actual))
  311. Y_UNIT_TEST_SUITE(TTypeTraitsTestNg) {
  312. template <typename T>
  313. void TestImpl() {
  314. //UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsPod, TTypeTraits<T>::IsPod);
  315. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsVoid, std::is_void<T>::value);
  316. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsEnum, std::is_enum<T>::value);
  317. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsIntegral, std::is_integral<T>::value);
  318. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsArithmetic, std::is_arithmetic<T>::value);
  319. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsVolatile, std::is_volatile<T>::value);
  320. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsConstant, std::is_const<T>::value);
  321. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsPointer, std::is_pointer<T>::value);
  322. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsReference, std::is_reference<T>::value);
  323. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsLvalueReference, std::is_lvalue_reference<T>::value);
  324. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsRvalueReference, std::is_rvalue_reference<T>::value);
  325. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsArray, std::is_array<T>::value);
  326. UNIT_ASSERT_EQUAL_ENUM(TTypeTraitsExpected<T>::IsClassType, std::is_class<T>::value);
  327. }
  328. #define TYPE_TEST(name, type) \
  329. Y_UNIT_TEST(name) { \
  330. TestImpl<type>(); \
  331. }
  332. TYPE_TEST(Void, void)
  333. TYPE_TEST(Int, int)
  334. TYPE_TEST(Float, float)
  335. TYPE_TEST(LongDouble, long double)
  336. TYPE_TEST(SizeT, size_t)
  337. TYPE_TEST(VolatileInt, volatile int)
  338. TYPE_TEST(ConstInt, const int)
  339. TYPE_TEST(Enum, ETestEnum)
  340. TYPE_TEST(FloatPointer, float*)
  341. TYPE_TEST(FloatReference, float&)
  342. TYPE_TEST(FloatConstReference, const float&)
  343. TYPE_TEST(FloatArray, float[17])
  344. TYPE_TEST(PodClass, TPodClass)
  345. TYPE_TEST(NonPodClass, TNonPodClass)
  346. TYPE_TEST(NonPodClassReference, TNonPodClass&)
  347. TYPE_TEST(NonPodClassConstReference, const TNonPodClass&)
  348. }
  349. enum E4 {
  350. X
  351. };
  352. enum class E64: ui64 {
  353. X
  354. };
  355. enum class E8: ui8 {
  356. X
  357. };
  358. // test for std::underlying_type_t
  359. static_assert(sizeof(std::underlying_type_t<E4>) == sizeof(int), "");
  360. static_assert(sizeof(std::underlying_type_t<E64>) == sizeof(ui64), "");
  361. static_assert(sizeof(std::underlying_type_t<E8>) == sizeof(ui8), "");
  362. // tests for TFixedWidthUnsignedInt
  363. static_assert(std::is_same<ui8, TFixedWidthUnsignedInt<i8>>::value, "");
  364. static_assert(std::is_same<ui16, TFixedWidthUnsignedInt<i16>>::value, "");
  365. static_assert(std::is_same<ui32, TFixedWidthUnsignedInt<i32>>::value, "");
  366. static_assert(std::is_same<ui64, TFixedWidthUnsignedInt<i64>>::value, "");
  367. // tests for TFixedWidthSignedInt
  368. static_assert(std::is_same<i8, TFixedWidthSignedInt<ui8>>::value, "");
  369. static_assert(std::is_same<i16, TFixedWidthSignedInt<ui16>>::value, "");
  370. static_assert(std::is_same<i32, TFixedWidthSignedInt<ui32>>::value, "");
  371. static_assert(std::is_same<i64, TFixedWidthSignedInt<ui64>>::value, "");
  372. // test for TIsSpecializationOf
  373. static_assert(TIsSpecializationOf<std::vector, std::vector<int>>::value, "");
  374. static_assert(TIsSpecializationOf<std::tuple, std::tuple<int, double, char>>::value, "");
  375. static_assert(!TIsSpecializationOf<std::vector, std::tuple<int, double, char>>::value, "");
  376. static_assert(!TIsSpecializationOf<std::pair, std::vector<int>>::value, "");
  377. // test for TIsTemplateBaseOf
  378. static_assert(TIsTemplateBaseOf<std::vector, std::vector<int>>::value);
  379. static_assert(TIsTemplateBaseOf<std::tuple, std::tuple<int, double, char>>::value);
  380. static_assert(TIsTemplateBaseOf<std::basic_string_view, std::wstring_view>::value);
  381. static_assert(TIsTemplateBaseOf<std::vector, TVector<int>>::value);
  382. static_assert(!TIsTemplateBaseOf<TVector, std::vector<int>>::value);
  383. static_assert(TIsTemplateBaseOf<TBasicStringBuf, TWtringBuf>::value);
  384. static_assert(TIsTemplateBaseOf<std::basic_string_view, TUtf32StringBuf>::value);
  385. static_assert(TIsTemplateBaseOf<std::basic_string_view, TWtringBuf>::value);
  386. // test for TIsIterable
  387. static_assert(TIsIterable<std::vector<int>>::value, "");
  388. static_assert(!TIsIterable<int>::value, "");
  389. static_assert(TIsIterable<int[42]>::value, "");
  390. // test for TDependentFalse
  391. static_assert(TDependentFalse<int> == false);
  392. static_assert(TDependentFalse<TNonPodClass> == false);
  393. static_assert(TValueDependentFalse<0x1000> == false);