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