ConceptsTests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/UnitTest/TestTypes.h>
  9. #include <AzCore/std/concepts/concepts.h>
  10. #include <AzCore/std/ranges/ranges_functional.h>
  11. namespace UnitTest
  12. {
  13. class ConceptsTestFixture
  14. : public LeakDetectionFixture
  15. {};
  16. TEST_F(ConceptsTestFixture, GeneralConcepts)
  17. {
  18. // concept same_as
  19. static_assert(AZStd::same_as<ConceptsTestFixture, ConceptsTestFixture>);
  20. static_assert(!AZStd::same_as<ConceptsTestFixture, LeakDetectionFixture>);
  21. // concept derived_from
  22. static_assert(AZStd::derived_from<ConceptsTestFixture, LeakDetectionFixture>);
  23. static_assert(!AZStd::derived_from<LeakDetectionFixture, ConceptsTestFixture>);
  24. // concept convertible_to
  25. static_assert(AZStd::convertible_to<ConceptsTestFixture&, LeakDetectionFixture&>);
  26. static_assert(!AZStd::convertible_to<LeakDetectionFixture&, ConceptsTestFixture&>);
  27. // Test structs to validate common_reference_with and common_with concepts
  28. struct Base {};
  29. struct TestBase : Base {};
  30. struct TestDerived : TestBase {};
  31. struct TestDerived2 : TestBase {};
  32. struct NoMove
  33. {
  34. NoMove(NoMove&&) = delete;
  35. NoMove& operator=(NoMove&&) = delete;
  36. };
  37. struct NoDestructible
  38. {
  39. ~NoDestructible() = delete;
  40. };
  41. struct NoDefaultInitializable
  42. {
  43. NoDefaultInitializable(bool);
  44. };
  45. struct CopyOnly
  46. {
  47. CopyOnly(const CopyOnly&) = default;
  48. };
  49. struct MoveOnly
  50. {
  51. MoveOnly(MoveOnly&&) = default;
  52. };
  53. struct MoveableButNotCopyable
  54. {
  55. MoveableButNotCopyable(MoveableButNotCopyable&&) = default;
  56. MoveableButNotCopyable& operator=(MoveableButNotCopyable&&) = default;
  57. };
  58. // concept common_reference_with
  59. static_assert(AZStd::common_reference_with<TestBase&, Base&>);
  60. static_assert(AZStd::same_as<AZStd::common_reference_t<const TestBase&, Base&>, const Base&>);
  61. static_assert(!AZStd::common_reference_with<TestDerived2, TestDerived>);
  62. // concept common_with
  63. static_assert(AZStd::common_with<TestBase, Base>);
  64. static_assert(!AZStd::common_with<LeakDetectionFixture, AllocatorsBenchmarkFixture>);
  65. // arithmetic concepts
  66. // concept integral
  67. static_assert(AZStd::integral<int>);
  68. static_assert(!AZStd::integral<float>);
  69. // concept signed_integral
  70. static_assert(AZStd::signed_integral<int>);
  71. static_assert(!AZStd::signed_integral<unsigned int>);
  72. static_assert(!AZStd::signed_integral<float>);
  73. // concept signed_integral
  74. static_assert(AZStd::unsigned_integral<unsigned int>);
  75. static_assert(!AZStd::unsigned_integral<int>);
  76. static_assert(!AZStd::unsigned_integral<float>);
  77. // concept floating_point
  78. static_assert(AZStd::floating_point<float>);
  79. static_assert(!AZStd::floating_point<int>);
  80. // concept assignable_from
  81. static_assert(AZStd::assignable_from<Base&, TestBase>);
  82. static_assert(!AZStd::assignable_from<TestBase&, Base>);
  83. // concept swappable
  84. static_assert(AZStd::swappable<Base>);
  85. static_assert(!AZStd::swappable<NoMove>);
  86. static_assert(AZStd::swappable_with<Base, Base>);
  87. static_assert(!AZStd::swappable_with<NoMove, Base>);
  88. // concept destructible
  89. static_assert(AZStd::destructible<Base>);
  90. static_assert(!AZStd::destructible<NoDestructible>);
  91. // concept constructible_from
  92. static_assert(AZStd::constructible_from<NoDefaultInitializable, bool>);
  93. static_assert(!AZStd::constructible_from<NoDefaultInitializable>);
  94. // concept default_initializable
  95. static_assert(AZStd::default_initializable<Base>);
  96. static_assert(!AZStd::default_initializable<NoDefaultInitializable>);
  97. // concept move_constructible
  98. static_assert(AZStd::move_constructible<MoveOnly>);
  99. static_assert(!AZStd::move_constructible<NoMove>);
  100. // concept copy_constructible
  101. static_assert(AZStd::copy_constructible<CopyOnly>);
  102. static_assert(!AZStd::copy_constructible<MoveOnly>);
  103. // concept equality_comparable
  104. static_assert(AZStd::equality_comparable<AZStd::string_view>);
  105. static_assert(!AZStd::equality_comparable<Base>);
  106. static_assert(AZStd::equality_comparable_with<AZStd::string_view, const char*>);
  107. static_assert(!AZStd::equality_comparable_with<Base, TestBase>);
  108. static_assert(!AZStd::equality_comparable_with<Base, const char*>);
  109. // concept totally_ordered
  110. static_assert(AZStd::totally_ordered<AZStd::string_view>);
  111. static_assert(!AZStd::totally_ordered<Base>);
  112. static_assert(AZStd::totally_ordered_with<AZStd::string_view, const char*>);
  113. static_assert(!AZStd::totally_ordered_with<Base, TestBase>);
  114. static_assert(!AZStd::totally_ordered_with<Base, const char*>);
  115. // concept movable
  116. static_assert(AZStd::movable<MoveableButNotCopyable>);
  117. static_assert(!AZStd::movable<NoMove>);
  118. // concept copyable
  119. static_assert(AZStd::copyable<Base>);
  120. static_assert(!AZStd::copyable<MoveableButNotCopyable>);
  121. // concept semiregular
  122. static_assert(AZStd::semiregular<Base>);
  123. static_assert(!AZStd::semiregular<MoveableButNotCopyable>);
  124. // concept regular
  125. static_assert(AZStd::regular<AZStd::string_view>);
  126. static_assert(!AZStd::regular<Base>);
  127. // concept invocable
  128. static_assert(AZStd::invocable<decltype(AZStd::ranges::swap), int&, int&>);
  129. static_assert(!AZStd::invocable<decltype(AZStd::ranges::swap), int&, float&>);
  130. // concept predicate
  131. auto BooleanPredicate = [](double) -> int
  132. {
  133. return 0;
  134. };
  135. auto BasePredicate = [](int) -> Base
  136. {
  137. return Base{};
  138. };
  139. static_assert(AZStd::predicate<decltype(BooleanPredicate), double>);
  140. static_assert(!AZStd::predicate<decltype(BooleanPredicate), Base>);
  141. static_assert(!AZStd::predicate<decltype(BasePredicate), int>);
  142. // concept relation
  143. struct RelationPredicate
  144. {
  145. bool operator()(AZStd::string_view, Base) const;
  146. bool operator()(Base, AZStd::string_view) const;
  147. bool operator()(AZStd::string_view, AZStd::string_view) const;
  148. bool operator()(Base, Base) const;
  149. // non-complete relation
  150. bool operator()(Base, int) const;
  151. bool operator()(int, Base) const;
  152. };
  153. static_assert(AZStd::relation<RelationPredicate, AZStd::string_view, Base>);
  154. static_assert(AZStd::relation<RelationPredicate, Base, AZStd::string_view>);
  155. static_assert(!AZStd::relation<RelationPredicate, int, Base>);
  156. static_assert(!AZStd::relation<RelationPredicate, Base, int>);
  157. //concept equivalence_relation
  158. static_assert(AZStd::equivalence_relation<RelationPredicate, AZStd::string_view, Base>);
  159. static_assert(AZStd::equivalence_relation<RelationPredicate, Base, AZStd::string_view>);
  160. static_assert(!AZStd::equivalence_relation<RelationPredicate, int, Base>);
  161. static_assert(!AZStd::equivalence_relation<RelationPredicate, Base, int>);
  162. //concept strict_weak_order
  163. static_assert(AZStd::strict_weak_order<RelationPredicate, AZStd::string_view, Base>);
  164. static_assert(AZStd::strict_weak_order<RelationPredicate, Base, AZStd::string_view>);
  165. static_assert(!AZStd::strict_weak_order<RelationPredicate, int, Base>);
  166. static_assert(!AZStd::strict_weak_order<RelationPredicate, Base, int>);
  167. }
  168. TEST_F(ConceptsTestFixture, IteratorInvocableConcepts)
  169. {
  170. // concept indirectly unary invocable
  171. // i.e Is deferencing an iterator like type and invoking
  172. // a unary callable a well formed expression
  173. auto CharUnaryCallable = [](const char) -> int { return {}; };
  174. auto IntUnaryCallable = [](int) -> int { return {}; };
  175. auto IntRefUnaryCallable = [](int&) -> int { return {}; };
  176. static_assert(AZStd::indirectly_unary_invocable<decltype(CharUnaryCallable), AZStd::string_view::iterator>);
  177. static_assert(AZStd::indirectly_unary_invocable<decltype(IntUnaryCallable), AZStd::string_view::iterator>);
  178. static_assert(!AZStd::indirectly_unary_invocable<decltype(IntRefUnaryCallable), AZStd::string_view::iterator>);
  179. // concept indirectly regular unary invocable
  180. // i.e Is deferencing an iterator like type and invoking with a unary callable
  181. // which will not modify the input arguments(hence the term "regular") a well formed expression
  182. static_assert(AZStd::indirectly_regular_unary_invocable<decltype(CharUnaryCallable), AZStd::string_view::iterator>);
  183. static_assert(AZStd::indirectly_regular_unary_invocable<decltype(IntUnaryCallable), AZStd::string_view::iterator>);
  184. static_assert(!AZStd::indirectly_regular_unary_invocable<decltype(IntRefUnaryCallable), AZStd::string_view::iterator>);
  185. // concept indirect unary predicate
  186. // i.e Is deferencing an iterator like type and invoking with a unary predicate
  187. // i.e which is a callable that accepts one argument and returns value testable in a boolean context
  188. auto CharUnaryPredicate = [](const char) -> bool { return {}; };
  189. auto IntUnaryPredicate = [](int) -> int { return {}; };// Return value is an int which is convertible to bool
  190. auto IntRefUnaryPredicate = [](int&) -> int { return {}; }; // string_view iterator value type(char) can't bind to an int&
  191. auto CharUnaryNonPredicate = [](const char) -> AZStd::string_view { return {}; }; // string_view is not convertible to bool
  192. static_assert(AZStd::indirect_unary_predicate<decltype(CharUnaryPredicate), AZStd::string_view::iterator>);
  193. static_assert(AZStd::indirect_unary_predicate<decltype(IntUnaryPredicate), AZStd::string_view::iterator>);
  194. static_assert(!AZStd::indirect_unary_predicate<decltype(IntRefUnaryPredicate), AZStd::string_view::iterator>);
  195. static_assert(!AZStd::indirect_unary_predicate<decltype(CharUnaryNonPredicate), AZStd::string_view::iterator>);
  196. // concept indirect binary predicate
  197. // i.e Is deferencing two iterator like types and invoking a binary predicate with those values
  198. // well formed and returns value testable in a boolean context.
  199. auto CharIntBinaryPredicate = [](const char, int) -> bool { return{}; };
  200. auto CharCharRefBinaryPredicate = [](const char, const char&) -> uint32_t { return{}; };
  201. auto UIntRefCharBinaryPredicate = [](uint32_t&, char) -> bool { return{}; };
  202. auto CharCharBinaryNonPredicate = [](const char, const char) -> AZStd::string_view { return {}; };
  203. static_assert(AZStd::indirect_binary_predicate<decltype(CharIntBinaryPredicate),
  204. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  205. static_assert(AZStd::indirect_binary_predicate<decltype(CharCharRefBinaryPredicate),
  206. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  207. // string_view iterator value type(char) cannot bind to int&
  208. static_assert(!AZStd::indirect_binary_predicate<decltype(UIntRefCharBinaryPredicate),
  209. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  210. // string_view is not convertible to bool
  211. static_assert(!AZStd::indirect_binary_predicate<decltype(CharCharBinaryNonPredicate),
  212. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  213. // Ok - iter_reference_t<uint32_t*> = uint32_t&
  214. static_assert(AZStd::indirect_binary_predicate<decltype(UIntRefCharBinaryPredicate),
  215. uint32_t*, AZStd::string_view::iterator>);
  216. // concept indirect equivalence relation
  217. // i.e Is deferencing two iterator like types and invoking a binary predicate with those values
  218. // well formed and returns value testable in a boolean context.
  219. // The dereferenced iterator types should be model an equivalence relationship
  220. // (a == b) && (b == c) == (a ==c)
  221. static_assert(AZStd::indirect_equivalence_relation<decltype(CharIntBinaryPredicate),
  222. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  223. static_assert(AZStd::indirect_equivalence_relation<decltype(CharCharRefBinaryPredicate),
  224. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  225. static_assert(!AZStd::indirect_equivalence_relation<decltype(UIntRefCharBinaryPredicate),
  226. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  227. static_assert(!AZStd::indirect_equivalence_relation<decltype(CharCharBinaryNonPredicate),
  228. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  229. // The "relation" concept requires that both both arguments can be bind to
  230. // either of the two binary parameters
  231. static_assert(!AZStd::indirect_equivalence_relation<decltype(UIntRefCharBinaryPredicate),
  232. uint32_t*, AZStd::string_view::iterator>);
  233. // concept indirect strict weak order
  234. // i.e Is deferencing two iterator like types and invoking a binary predicate with those values
  235. // well formed and returns value testable in a boolean context.
  236. // The dereferenced iterator types should be model a strict weak order relation
  237. // (a < b) && (b < c) == (a < c)
  238. static_assert(AZStd::indirect_strict_weak_order<decltype(CharIntBinaryPredicate),
  239. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  240. static_assert(AZStd::indirect_strict_weak_order<decltype(CharCharRefBinaryPredicate),
  241. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  242. static_assert(!AZStd::indirect_strict_weak_order<decltype(UIntRefCharBinaryPredicate),
  243. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  244. static_assert(!AZStd::indirect_strict_weak_order<decltype(CharCharBinaryNonPredicate),
  245. AZStd::string_view::iterator, AZStd::string_view::iterator>);
  246. // The "relation" concept requires that both both arguments can be bind to
  247. // either of the two binary parameters
  248. static_assert(!AZStd::indirect_strict_weak_order<decltype(UIntRefCharBinaryPredicate),
  249. uint32_t*, AZStd::string_view::iterator>);
  250. // indirect_result_t type alias
  251. static_assert(AZStd::same_as<AZStd::indirect_result_t<decltype(CharCharRefBinaryPredicate),
  252. AZStd::string_view::iterator, const char*>, uint32_t>);
  253. // projected operator* returns indirect result of the projection function
  254. static_assert(AZStd::same_as<AZStd::iter_reference_t<AZStd::projected<int*, AZStd::identity>>, int&>);
  255. }
  256. TEST_F(ConceptsTestFixture, IteratorAlgorithmConcepts)
  257. {
  258. static_assert(AZStd::indirectly_swappable<int*, int*>);
  259. static_assert(!AZStd::indirectly_swappable<int*, const int*>);
  260. auto CharIntIndirectlyComparable = [](const char lhs, int rhs) -> bool { return lhs == rhs; };
  261. static_assert(AZStd::indirectly_comparable<const char*, int*, decltype(CharIntIndirectlyComparable)>);
  262. static_assert(!AZStd::indirectly_comparable<AZStd::string_view, int*, decltype(CharIntIndirectlyComparable)>);
  263. static_assert(AZStd::permutable<typename AZStd::vector<int>::iterator>);
  264. // const iterator isn't indirectlly swappable or indirectly movable
  265. static_assert(!AZStd::permutable<typename AZStd::vector<int>::const_iterator>);
  266. static_assert(AZStd::mergeable<AZStd::vector<int>::iterator, AZStd::string_view::iterator, AZStd::vector<int>::iterator>);
  267. static_assert(!AZStd::mergeable<AZStd::vector<int>::iterator, AZStd::string_view::iterator, AZStd::string_view::iterator>);
  268. static_assert(AZStd::sortable<int*>);
  269. // Not sortable becaue the iter_reference_t<const int*> = const int& which isn't swappable
  270. static_assert(!AZStd::sortable<const int*>);
  271. }
  272. }