1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // UNSUPPORTED: c++98, c++03, c++11, c++14 11 12 // <any> 13 14 // template <class T, class ...Args> emplace(Args&&...); 15 // template <class T, class U, class ...Args> 16 // void emplace(initializer_list<U>, Args&&...); 17 18 #include <any> 19 #include <cassert> 20 21 #include "any_helpers.h" 22 #include "count_new.hpp" 23 #include "test_macros.h" 24 25 using std::any; 26 using std::any_cast; 27 28 struct Tracked { 29 static int count; 30 Tracked() {++count;} 31 ~Tracked() { --count; } 32 }; 33 int Tracked::count = 0; 34 35 template <class Type> 36 void test_emplace_type() { 37 // constructing from a small type should perform no allocations. 38 DisableAllocationGuard g(isSmallType<Type>()); ((void)g); 39 assert(Type::count == 0); 40 Type::reset(); 41 { 42 any a(std::in_place_type<Tracked>); 43 assert(Tracked::count == 1); 44 45 a.emplace<Type>(); 46 47 assert(Tracked::count == 0); 48 assert(Type::count == 1); 49 assert(Type::copied == 0); 50 assert(Type::moved == 0); 51 assertContains<Type>(a, 0); 52 } 53 assert(Type::count == 0); 54 Type::reset(); 55 { 56 any a(std::in_place_type<Tracked>); 57 assert(Tracked::count == 1); 58 59 a.emplace<Type>(101); 60 61 assert(Tracked::count == 0); 62 assert(Type::count == 1); 63 assert(Type::copied == 0); 64 assert(Type::moved == 0); 65 assertContains<Type>(a, 101); 66 } 67 assert(Type::count == 0); 68 Type::reset(); 69 { 70 any a(std::in_place_type<Tracked>); 71 assert(Tracked::count == 1); 72 73 a.emplace<Type>(-1, 42, -1); 74 75 assert(Tracked::count == 0); 76 assert(Type::count == 1); 77 assert(Type::copied == 0); 78 assert(Type::moved == 0); 79 assertContains<Type>(a, 42); 80 } 81 assert(Type::count == 0); 82 Type::reset(); 83 } 84 85 template <class Type> 86 void test_emplace_type_tracked() { 87 // constructing from a small type should perform no allocations. 88 DisableAllocationGuard g(isSmallType<Type>()); ((void)g); 89 { 90 any a(std::in_place_type<Tracked>); 91 assert(Tracked::count == 1); 92 a.emplace<Type>(); 93 assert(Tracked::count == 0); 94 assertArgsMatch<Type>(a); 95 } 96 { 97 any a(std::in_place_type<Tracked>); 98 assert(Tracked::count == 1); 99 a.emplace<Type>(-1, 42, -1); 100 assert(Tracked::count == 0); 101 assertArgsMatch<Type, int, int, int>(a); 102 } 103 // initializer_list constructor tests 104 { 105 any a(std::in_place_type<Tracked>); 106 assert(Tracked::count == 1); 107 a.emplace<Type>({-1, 42, -1}); 108 assert(Tracked::count == 0); 109 assertArgsMatch<Type, std::initializer_list<int>>(a); 110 } 111 { 112 int x = 42; 113 any a(std::in_place_type<Tracked>); 114 assert(Tracked::count == 1); 115 a.emplace<Type>({-1, 42, -1}, x); 116 assert(Tracked::count == 0); 117 assertArgsMatch<Type, std::initializer_list<int>, int&>(a); 118 } 119 } 120 121 #ifndef TEST_HAS_NO_EXCEPTIONS 122 123 struct SmallThrows { 124 SmallThrows(int) { throw 42; } 125 SmallThrows(std::initializer_list<int>, int) { throw 42; } 126 }; 127 static_assert(IsSmallObject<SmallThrows>::value, ""); 128 129 struct LargeThrows { 130 LargeThrows(int) { throw 42; } 131 LargeThrows(std::initializer_list<int>, int) { throw 42; } 132 int data[sizeof(std::any)]; 133 }; 134 static_assert(!IsSmallObject<LargeThrows>::value, ""); 135 136 template <class Type> 137 void test_emplace_throws() 138 { 139 // any stores small type 140 { 141 std::any a(small{42}); 142 assert(small::count == 1); 143 try { 144 a.emplace<Type>(101); 145 assert(false); 146 } catch (int const&) { 147 } 148 assert(small::count == 0); 149 } 150 { 151 std::any a(small{42}); 152 assert(small::count == 1); 153 try { 154 a.emplace<Type>({1, 2, 3}, 101); 155 assert(false); 156 } catch (int const&) { 157 } 158 assert(small::count == 0); 159 } 160 // any stores large type 161 { 162 std::any a(large{42}); 163 assert(large::count == 1); 164 try { 165 a.emplace<Type>(101); 166 assert(false); 167 } catch (int const&) { 168 } 169 assert(large::count == 0); 170 } 171 { 172 std::any a(large{42}); 173 assert(large::count == 1); 174 try { 175 a.emplace<Type>({1, 2, 3}, 101); 176 assert(false); 177 } catch (int const&) { 178 } 179 assert(large::count == 0); 180 } 181 } 182 183 #endif 184 185 template <class T, class ...Args> 186 constexpr auto has_emplace(int) 187 -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; } 188 189 template <class ...Args> 190 constexpr bool has_emplace(long) { return false; } 191 192 template <class ...Args> 193 constexpr bool has_emplace() { return has_emplace<Args...>(0); } 194 195 196 template <class T, class IT, class ...Args> 197 constexpr auto has_emplace_init_list(int) 198 -> decltype(std::any{}.emplace<T>( 199 {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()}, 200 std::declval<Args>()...), true) { return true; } 201 202 template <class ...Args> 203 constexpr bool has_emplace_init_list(long) { return false; } 204 205 template <class ...Args> 206 constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); } 207 208 209 void test_emplace_sfinae_constraints() { 210 { 211 static_assert(has_emplace<int>(), ""); 212 static_assert(has_emplace<int, int>(), ""); 213 static_assert(!has_emplace<int, int, int>(), "not constructible"); 214 static_assert(!has_emplace_init_list<int, int>(), "not constructible from il"); 215 } 216 { 217 static_assert(has_emplace<small>(), ""); 218 static_assert(has_emplace<large>(), ""); 219 static_assert(!has_emplace<small, void*>(), ""); 220 static_assert(!has_emplace<large, void*>(), ""); 221 222 static_assert(has_emplace_init_list<small, int>(), ""); 223 static_assert(has_emplace_init_list<large, int>(), ""); 224 static_assert(!has_emplace_init_list<small, void*>(), ""); 225 static_assert(!has_emplace_init_list<large, void*>(), ""); 226 } 227 { 228 // Test that the emplace SFINAE's away when the 229 // argument is non-copyable 230 struct NoCopy { 231 NoCopy() = default; 232 NoCopy(NoCopy const&) = delete; 233 NoCopy(int) {} 234 NoCopy(std::initializer_list<int>, int, int) {} 235 }; 236 static_assert(!has_emplace<NoCopy>(), ""); 237 static_assert(!has_emplace<NoCopy, int>(), ""); 238 static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), ""); 239 static_assert(!has_emplace<NoCopy&>(), ""); 240 static_assert(!has_emplace<NoCopy&, int>(), ""); 241 static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), ""); 242 static_assert(!has_emplace<NoCopy&&>(), ""); 243 static_assert(!has_emplace<NoCopy&&, int>(), ""); 244 static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), ""); 245 246 } 247 } 248 249 int main() { 250 test_emplace_type<small>(); 251 test_emplace_type<large>(); 252 test_emplace_type<small_throws_on_copy>(); 253 test_emplace_type<large_throws_on_copy>(); 254 test_emplace_type<throws_on_move>(); 255 test_emplace_type_tracked<small_tracked_t>(); 256 test_emplace_type_tracked<large_tracked_t>(); 257 test_emplace_sfinae_constraints(); 258 #ifndef TEST_HAS_NO_EXCEPTIONS 259 test_emplace_throws<SmallThrows>(); 260 test_emplace_throws<LargeThrows>(); 261 #endif 262 } 263