any_helpers.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef ANY_HELPERS_H
  9. #define ANY_HELPERS_H
  10. #include <typeinfo>
  11. #include <type_traits>
  12. #include <cassert>
  13. namespace std { namespace experimental {} }
  14. #include "test_macros.h"
  15. #include "type_id.h"
  16. #if !defined(TEST_HAS_NO_RTTI)
  17. #define RTTI_ASSERT(X) assert(X)
  18. #else
  19. #define RTTI_ASSERT(X)
  20. #endif
  21. template <class T>
  22. struct IsSmallObject
  23. : public std::integral_constant<bool
  24. , sizeof(T) <= sizeof(std::any) - sizeof(void*)
  25. && std::alignment_of<void*>::value
  26. % std::alignment_of<T>::value == 0
  27. && std::is_nothrow_move_constructible<T>::value
  28. >
  29. {};
  30. template <class T>
  31. bool containsType(std::any const& a) {
  32. #if !defined(TEST_HAS_NO_RTTI)
  33. return a.type() == typeid(T);
  34. #else
  35. return a.has_value() && std::any_cast<T>(&a) != nullptr;
  36. #endif
  37. }
  38. // Return 'true' if 'Type' will be considered a small type by 'any'
  39. template <class Type>
  40. bool isSmallType() {
  41. return IsSmallObject<Type>::value;
  42. }
  43. // Assert that an object is empty. If the object used to contain an object
  44. // of type 'LastType' check that it can no longer be accessed.
  45. template <class LastType = int>
  46. void assertEmpty(std::any const& a) {
  47. using namespace std;
  48. assert(!a.has_value());
  49. RTTI_ASSERT(a.type() == typeid(void));
  50. assert(any_cast<LastType const>(&a) == nullptr);
  51. }
  52. template <class Type>
  53. constexpr auto has_value_member(int) -> decltype(std::declval<Type&>().value, true)
  54. { return true; }
  55. template <class> constexpr bool has_value_member(long) { return false; }
  56. // Assert that an 'any' object stores the specified 'Type' and 'value'.
  57. template <class Type>
  58. std::enable_if_t<has_value_member<Type>(0)>
  59. _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
  60. assertContains(std::any const& a, int value) {
  61. assert(a.has_value());
  62. assert(containsType<Type>(a));
  63. assert(std::any_cast<Type const &>(a).value == value);
  64. }
  65. template <class Type, class Value>
  66. std::enable_if_t<!has_value_member<Type>(0)>
  67. _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
  68. assertContains(std::any const& a, Value value) {
  69. assert(a.has_value());
  70. assert(containsType<Type>(a));
  71. assert(std::any_cast<Type const &>(a) == value);
  72. }
  73. // Modify the value of a "test type" stored within an any to the specified
  74. // 'value'.
  75. template <class Type>
  76. _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
  77. void modifyValue(std::any& a, int value) {
  78. using namespace std;
  79. using namespace std::experimental;
  80. assert(a.has_value());
  81. assert(containsType<Type>(a));
  82. any_cast<Type&>(a).value = value;
  83. }
  84. // A test type that will trigger the small object optimization within 'any'.
  85. template <int Dummy = 0>
  86. struct small_type
  87. {
  88. static int count;
  89. static int copied;
  90. static int moved;
  91. static int const_copied;
  92. static int non_const_copied;
  93. static void reset() {
  94. small_type::copied = 0;
  95. small_type::moved = 0;
  96. small_type::const_copied = 0;
  97. small_type::non_const_copied = 0;
  98. }
  99. int value;
  100. explicit small_type(int val = 0) : value(val) {
  101. ++count;
  102. }
  103. explicit small_type(int, int val, int) : value(val) {
  104. ++count;
  105. }
  106. small_type(std::initializer_list<int> il) : value(*il.begin()) {
  107. ++count;
  108. }
  109. small_type(small_type const & other) noexcept {
  110. value = other.value;
  111. ++count;
  112. ++copied;
  113. ++const_copied;
  114. }
  115. small_type(small_type& other) noexcept {
  116. value = other.value;
  117. ++count;
  118. ++copied;
  119. ++non_const_copied;
  120. }
  121. small_type(small_type && other) noexcept {
  122. value = other.value;
  123. other.value = 0;
  124. ++count;
  125. ++moved;
  126. }
  127. ~small_type() {
  128. value = -1;
  129. --count;
  130. }
  131. private:
  132. small_type& operator=(small_type const&) = delete;
  133. small_type& operator=(small_type&&) = delete;
  134. };
  135. template <int Dummy>
  136. int small_type<Dummy>::count = 0;
  137. template <int Dummy>
  138. int small_type<Dummy>::copied = 0;
  139. template <int Dummy>
  140. int small_type<Dummy>::moved = 0;
  141. template <int Dummy>
  142. int small_type<Dummy>::const_copied = 0;
  143. template <int Dummy>
  144. int small_type<Dummy>::non_const_copied = 0;
  145. typedef small_type<> small;
  146. typedef small_type<1> small1;
  147. typedef small_type<2> small2;
  148. // A test type that will NOT trigger the small object optimization in any.
  149. template <int Dummy = 0>
  150. struct large_type
  151. {
  152. static int count;
  153. static int copied;
  154. static int moved;
  155. static int const_copied;
  156. static int non_const_copied;
  157. static void reset() {
  158. large_type::copied = 0;
  159. large_type::moved = 0;
  160. large_type::const_copied = 0;
  161. large_type::non_const_copied = 0;
  162. }
  163. int value;
  164. large_type(int val = 0) : value(val) {
  165. ++count;
  166. data[0] = 0;
  167. }
  168. large_type(int, int val, int) : value(val) {
  169. ++count;
  170. data[0] = 0;
  171. }
  172. large_type(std::initializer_list<int> il) : value(*il.begin()) {
  173. ++count;
  174. }
  175. large_type(large_type const & other) {
  176. value = other.value;
  177. ++count;
  178. ++copied;
  179. ++const_copied;
  180. }
  181. large_type(large_type & other) {
  182. value = other.value;
  183. ++count;
  184. ++copied;
  185. ++non_const_copied;
  186. }
  187. large_type(large_type && other) {
  188. value = other.value;
  189. other.value = 0;
  190. ++count;
  191. ++moved;
  192. }
  193. ~large_type() {
  194. value = 0;
  195. --count;
  196. }
  197. private:
  198. large_type& operator=(large_type const&) = delete;
  199. large_type& operator=(large_type &&) = delete;
  200. int data[10];
  201. };
  202. template <int Dummy>
  203. int large_type<Dummy>::count = 0;
  204. template <int Dummy>
  205. int large_type<Dummy>::copied = 0;
  206. template <int Dummy>
  207. int large_type<Dummy>::moved = 0;
  208. template <int Dummy>
  209. int large_type<Dummy>::const_copied = 0;
  210. template <int Dummy>
  211. int large_type<Dummy>::non_const_copied = 0;
  212. typedef large_type<> large;
  213. typedef large_type<1> large1;
  214. typedef large_type<2> large2;
  215. // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
  216. // and 'throws_on_move'.
  217. struct my_any_exception {};
  218. void throwMyAnyExpression() {
  219. #if !defined(TEST_HAS_NO_EXCEPTIONS)
  220. throw my_any_exception();
  221. #else
  222. assert(false && "Exceptions are disabled");
  223. #endif
  224. }
  225. // A test type that will trigger the small object optimization within 'any'.
  226. // this type throws if it is copied.
  227. struct small_throws_on_copy
  228. {
  229. static int count;
  230. static int copied;
  231. static int moved;
  232. static void reset() { count = copied = moved = 0; }
  233. int value;
  234. explicit small_throws_on_copy(int val = 0) : value(val) {
  235. ++count;
  236. }
  237. explicit small_throws_on_copy(int, int val, int) : value(val) {
  238. ++count;
  239. }
  240. small_throws_on_copy(small_throws_on_copy const &) {
  241. throwMyAnyExpression();
  242. }
  243. small_throws_on_copy(small_throws_on_copy && other) throw() {
  244. value = other.value;
  245. ++count; ++moved;
  246. }
  247. ~small_throws_on_copy() {
  248. --count;
  249. }
  250. private:
  251. small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
  252. small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
  253. };
  254. int small_throws_on_copy::count = 0;
  255. int small_throws_on_copy::copied = 0;
  256. int small_throws_on_copy::moved = 0;
  257. // A test type that will NOT trigger the small object optimization within 'any'.
  258. // this type throws if it is copied.
  259. struct large_throws_on_copy
  260. {
  261. static int count;
  262. static int copied;
  263. static int moved;
  264. static void reset() { count = copied = moved = 0; }
  265. int value = 0;
  266. explicit large_throws_on_copy(int val = 0) : value(val) {
  267. data[0] = 0;
  268. ++count;
  269. }
  270. explicit large_throws_on_copy(int, int val, int) : value(val) {
  271. data[0] = 0;
  272. ++count;
  273. }
  274. large_throws_on_copy(large_throws_on_copy const &) {
  275. throwMyAnyExpression();
  276. }
  277. large_throws_on_copy(large_throws_on_copy && other) throw() {
  278. value = other.value;
  279. ++count; ++moved;
  280. }
  281. ~large_throws_on_copy() {
  282. --count;
  283. }
  284. private:
  285. large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
  286. large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
  287. int data[10];
  288. };
  289. int large_throws_on_copy::count = 0;
  290. int large_throws_on_copy::copied = 0;
  291. int large_throws_on_copy::moved = 0;
  292. // A test type that throws when it is moved. This object will NOT trigger
  293. // the small object optimization in 'any'.
  294. struct throws_on_move
  295. {
  296. static int count;
  297. static int copied;
  298. static int moved;
  299. static void reset() { count = copied = moved = 0; }
  300. int value;
  301. explicit throws_on_move(int val = 0) : value(val) { ++count; }
  302. explicit throws_on_move(int, int val, int) : value(val) { ++count; }
  303. throws_on_move(throws_on_move const & other) {
  304. value = other.value;
  305. ++count; ++copied;
  306. }
  307. throws_on_move(throws_on_move &&) {
  308. throwMyAnyExpression();
  309. }
  310. ~throws_on_move() {
  311. --count;
  312. }
  313. private:
  314. throws_on_move& operator=(throws_on_move const&) = delete;
  315. throws_on_move& operator=(throws_on_move &&) = delete;
  316. };
  317. int throws_on_move::count = 0;
  318. int throws_on_move::copied = 0;
  319. int throws_on_move::moved = 0;
  320. struct small_tracked_t {
  321. small_tracked_t()
  322. : arg_types(&makeArgumentID<>()) {}
  323. small_tracked_t(small_tracked_t const&) noexcept
  324. : arg_types(&makeArgumentID<small_tracked_t const&>()) {}
  325. small_tracked_t(small_tracked_t &&) noexcept
  326. : arg_types(&makeArgumentID<small_tracked_t &&>()) {}
  327. template <class ...Args>
  328. explicit small_tracked_t(Args&&...)
  329. : arg_types(&makeArgumentID<Args...>()) {}
  330. template <class ...Args>
  331. explicit small_tracked_t(std::initializer_list<int>, Args&&...)
  332. : arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {}
  333. TypeID const* arg_types;
  334. };
  335. static_assert(IsSmallObject<small_tracked_t>::value, "must be small");
  336. struct large_tracked_t {
  337. large_tracked_t()
  338. : arg_types(&makeArgumentID<>()) { dummy[0] = 42; }
  339. large_tracked_t(large_tracked_t const&) noexcept
  340. : arg_types(&makeArgumentID<large_tracked_t const&>()) {}
  341. large_tracked_t(large_tracked_t &&) noexcept
  342. : arg_types(&makeArgumentID<large_tracked_t &&>()) {}
  343. template <class ...Args>
  344. explicit large_tracked_t(Args&&...)
  345. : arg_types(&makeArgumentID<Args...>()) {}
  346. template <class ...Args>
  347. explicit large_tracked_t(std::initializer_list<int>, Args&&...)
  348. : arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {}
  349. TypeID const* arg_types;
  350. int dummy[sizeof(std::any) / sizeof(int) + 1];
  351. };
  352. static_assert(!IsSmallObject<large_tracked_t>::value, "must not be small");
  353. template <class Type, class ...Args>
  354. void assertArgsMatch(std::any const& a) {
  355. using namespace std;
  356. using namespace std::experimental;
  357. assert(a.has_value());
  358. assert(containsType<Type>(a));
  359. assert(any_cast<Type const &>(a).arg_types == &makeArgumentID<Args...>());
  360. };
  361. #endif