experimental_any_helpers.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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 EXPERIMENTAL_ANY_HELPERS_H
  9. #define EXPERIMENTAL_ANY_HELPERS_H
  10. #include <experimental/any>
  11. #include <typeinfo>
  12. #include <type_traits>
  13. #include <cassert>
  14. #include "test_macros.h"
  15. #if !defined(TEST_HAS_NO_RTTI)
  16. #define RTTI_ASSERT(X) assert(X)
  17. #else
  18. #define RTTI_ASSERT(X)
  19. #endif
  20. template <class T>
  21. struct IsSmallObject
  22. : public std::integral_constant<bool
  23. , sizeof(T) <= (sizeof(void*)*3)
  24. && std::alignment_of<void*>::value
  25. % std::alignment_of<T>::value == 0
  26. && std::is_nothrow_move_constructible<T>::value
  27. >
  28. {};
  29. // Return 'true' if 'Type' will be considered a small type by 'any'
  30. template <class Type>
  31. bool isSmallType() {
  32. #if defined(_LIBCPP_VERSION)
  33. return std::experimental::__any_imp::_IsSmallObject<Type>::value;
  34. #else
  35. return IsSmallObject<Type>::value;
  36. #endif
  37. }
  38. // Assert that an object is empty. If the object used to contain an object
  39. // of type 'LastType' check that it can no longer be accessed.
  40. template <class LastType = int>
  41. void assertEmpty(std::experimental::any const& a) {
  42. assert(a.empty());
  43. RTTI_ASSERT(a.type() == typeid(void));
  44. assert(std::experimental::any_cast<LastType const>(&a) == nullptr);
  45. }
  46. // Assert that an 'any' object stores the specified 'Type' and 'value'.
  47. template <class Type>
  48. _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
  49. void assertContains(std::experimental::any const& a, int value = 1) {
  50. assert(!a.empty());
  51. RTTI_ASSERT(a.type() == typeid(Type));
  52. assert(std::experimental::any_cast<Type const &>(a).value == value);
  53. }
  54. // Modify the value of a "test type" stored within an any to the specified
  55. // 'value'.
  56. template <class Type>
  57. _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
  58. void modifyValue(std::experimental::any& a, int value) {
  59. assert(!a.empty());
  60. RTTI_ASSERT(a.type() == typeid(Type));
  61. std::experimental::any_cast<Type&>(a).value = value;
  62. }
  63. // A test type that will trigger the small object optimization within 'any'.
  64. template <int Dummy = 0>
  65. struct small_type
  66. {
  67. static int count;
  68. static int copied;
  69. static int moved;
  70. static int const_copied;
  71. static int non_const_copied;
  72. static void reset() {
  73. small_type::copied = 0;
  74. small_type::moved = 0;
  75. small_type::const_copied = 0;
  76. small_type::non_const_copied = 0;
  77. }
  78. int value;
  79. explicit small_type(int val) : value(val) {
  80. ++count;
  81. }
  82. small_type(small_type const & other) throw() {
  83. value = other.value;
  84. ++count;
  85. ++copied;
  86. ++const_copied;
  87. }
  88. small_type(small_type& other) throw() {
  89. value = other.value;
  90. ++count;
  91. ++copied;
  92. ++non_const_copied;
  93. }
  94. small_type(small_type && other) throw() {
  95. value = other.value;
  96. other.value = 0;
  97. ++count;
  98. ++moved;
  99. }
  100. ~small_type() {
  101. value = -1;
  102. --count;
  103. }
  104. private:
  105. small_type& operator=(small_type const&) = delete;
  106. small_type& operator=(small_type&&) = delete;
  107. };
  108. template <int Dummy>
  109. int small_type<Dummy>::count = 0;
  110. template <int Dummy>
  111. int small_type<Dummy>::copied = 0;
  112. template <int Dummy>
  113. int small_type<Dummy>::moved = 0;
  114. template <int Dummy>
  115. int small_type<Dummy>::const_copied = 0;
  116. template <int Dummy>
  117. int small_type<Dummy>::non_const_copied = 0;
  118. typedef small_type<> small;
  119. typedef small_type<1> small1;
  120. typedef small_type<2> small2;
  121. // A test type that will NOT trigger the small object optimization in any.
  122. template <int Dummy = 0>
  123. struct large_type
  124. {
  125. static int count;
  126. static int copied;
  127. static int moved;
  128. static int const_copied;
  129. static int non_const_copied;
  130. static void reset() {
  131. large_type::copied = 0;
  132. large_type::moved = 0;
  133. large_type::const_copied = 0;
  134. large_type::non_const_copied = 0;
  135. }
  136. int value;
  137. large_type(int val) : value(val) {
  138. ++count;
  139. data[0] = 0;
  140. }
  141. large_type(large_type const & other) {
  142. value = other.value;
  143. ++count;
  144. ++copied;
  145. ++const_copied;
  146. }
  147. large_type(large_type & other) {
  148. value = other.value;
  149. ++count;
  150. ++copied;
  151. ++non_const_copied;
  152. }
  153. large_type(large_type && other) {
  154. value = other.value;
  155. other.value = 0;
  156. ++count;
  157. ++moved;
  158. }
  159. ~large_type() {
  160. value = 0;
  161. --count;
  162. }
  163. private:
  164. large_type& operator=(large_type const&) = delete;
  165. large_type& operator=(large_type &&) = delete;
  166. int data[10];
  167. };
  168. template <int Dummy>
  169. int large_type<Dummy>::count = 0;
  170. template <int Dummy>
  171. int large_type<Dummy>::copied = 0;
  172. template <int Dummy>
  173. int large_type<Dummy>::moved = 0;
  174. template <int Dummy>
  175. int large_type<Dummy>::const_copied = 0;
  176. template <int Dummy>
  177. int large_type<Dummy>::non_const_copied = 0;
  178. typedef large_type<> large;
  179. typedef large_type<1> large1;
  180. typedef large_type<2> large2;
  181. // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
  182. // and 'throws_on_move'.
  183. struct my_any_exception {};
  184. void throwMyAnyExpression() {
  185. #if !defined(TEST_HAS_NO_EXCEPTIONS)
  186. throw my_any_exception();
  187. #else
  188. assert(false && "Exceptions are disabled");
  189. #endif
  190. }
  191. // A test type that will trigger the small object optimization within 'any'.
  192. // this type throws if it is copied.
  193. struct small_throws_on_copy
  194. {
  195. static int count;
  196. int value;
  197. explicit small_throws_on_copy(int val = 0) : value(val) {
  198. ++count;
  199. }
  200. small_throws_on_copy(small_throws_on_copy const &) {
  201. throwMyAnyExpression();
  202. }
  203. small_throws_on_copy(small_throws_on_copy && other) throw() {
  204. value = other.value;
  205. ++count;
  206. }
  207. ~small_throws_on_copy() {
  208. --count;
  209. }
  210. private:
  211. small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
  212. small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
  213. };
  214. int small_throws_on_copy::count = 0;
  215. // A test type that will NOT trigger the small object optimization within 'any'.
  216. // this type throws if it is copied.
  217. struct large_throws_on_copy
  218. {
  219. static int count;
  220. int value = 0;
  221. explicit large_throws_on_copy(int val = 0) : value(val) {
  222. data[0] = 0;
  223. ++count;
  224. }
  225. large_throws_on_copy(large_throws_on_copy const &) {
  226. throwMyAnyExpression();
  227. }
  228. large_throws_on_copy(large_throws_on_copy && other) throw() {
  229. value = other.value;
  230. ++count;
  231. }
  232. ~large_throws_on_copy() {
  233. --count;
  234. }
  235. private:
  236. large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
  237. large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
  238. int data[10];
  239. };
  240. int large_throws_on_copy::count = 0;
  241. // A test type that throws when it is moved. This object will NOT trigger
  242. // the small object optimization in 'any'.
  243. struct throws_on_move
  244. {
  245. static int count;
  246. int value;
  247. explicit throws_on_move(int val = 0) : value(val) { ++count; }
  248. throws_on_move(throws_on_move const & other) {
  249. value = other.value;
  250. ++count;
  251. }
  252. throws_on_move(throws_on_move &&) {
  253. throwMyAnyExpression();
  254. }
  255. ~throws_on_move() {
  256. --count;
  257. }
  258. private:
  259. throws_on_move& operator=(throws_on_move const&) = delete;
  260. throws_on_move& operator=(throws_on_move &&) = delete;
  261. };
  262. int throws_on_move::count = 0;
  263. #endif