//===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14 // XFAIL: availability=macosx10.13 // XFAIL: availability=macosx10.12 // XFAIL: availability=macosx10.11 // XFAIL: availability=macosx10.10 // XFAIL: availability=macosx10.9 // XFAIL: availability=macosx10.8 // XFAIL: availability=macosx10.7 // <any> // template <class T, class ...Args> T& emplace(Args&&...); // template <class T, class U, class ...Args> // T& emplace(initializer_list<U>, Args&&...); #include <any> #include <cassert> #include "any_helpers.h" #include "count_new.hpp" #include "test_macros.h" using std::any; using std::any_cast; struct Tracked { static int count; Tracked() {++count;} ~Tracked() { --count; } }; int Tracked::count = 0; template <class Type> void test_emplace_type() { // constructing from a small type should perform no allocations. DisableAllocationGuard g(isSmallType<Type>()); ((void)g); assert(Type::count == 0); Type::reset(); { any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>(); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assert(Type::count == 1); assert(Type::copied == 0); assert(Type::moved == 0); assertContains<Type>(a, 0); } assert(Type::count == 0); Type::reset(); { any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>(101); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assert(Type::count == 1); assert(Type::copied == 0); assert(Type::moved == 0); assertContains<Type>(a, 101); } assert(Type::count == 0); Type::reset(); { any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>(-1, 42, -1); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assert(Type::count == 1); assert(Type::copied == 0); assert(Type::moved == 0); assertContains<Type>(a, 42); } assert(Type::count == 0); Type::reset(); } template <class Type> void test_emplace_type_tracked() { // constructing from a small type should perform no allocations. DisableAllocationGuard g(isSmallType<Type>()); ((void)g); { any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>(); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assertArgsMatch<Type>(a); } { any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>(-1, 42, -1); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assertArgsMatch<Type, int, int, int>(a); } // initializer_list constructor tests { any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>({-1, 42, -1}); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assertArgsMatch<Type, std::initializer_list<int>>(a); } { int x = 42; any a(std::in_place_type<Tracked>); assert(Tracked::count == 1); auto &v = a.emplace<Type>({-1, 42, -1}, x); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(&v == std::any_cast<Type>(&a)); assert(Tracked::count == 0); assertArgsMatch<Type, std::initializer_list<int>, int&>(a); } } #ifndef TEST_HAS_NO_EXCEPTIONS struct SmallThrows { SmallThrows(int) { throw 42; } SmallThrows(std::initializer_list<int>, int) { throw 42; } }; static_assert(IsSmallObject<SmallThrows>::value, ""); struct LargeThrows { LargeThrows(int) { throw 42; } LargeThrows(std::initializer_list<int>, int) { throw 42; } int data[sizeof(std::any)]; }; static_assert(!IsSmallObject<LargeThrows>::value, ""); template <class Type> void test_emplace_throws() { // any stores small type { std::any a(small{42}); assert(small::count == 1); try { auto &v = a.emplace<Type>(101); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(false); } catch (int const&) { } assert(small::count == 0); } { std::any a(small{42}); assert(small::count == 1); try { auto &v = a.emplace<Type>({1, 2, 3}, 101); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(false); } catch (int const&) { } assert(small::count == 0); } // any stores large type { std::any a(large{42}); assert(large::count == 1); try { auto &v = a.emplace<Type>(101); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(false); } catch (int const&) { } assert(large::count == 0); } { std::any a(large{42}); assert(large::count == 1); try { auto &v = a.emplace<Type>({1, 2, 3}, 101); static_assert( std::is_same_v<Type&, decltype(v)>, "" ); assert(false); } catch (int const&) { } assert(large::count == 0); } } #endif template <class T, class ...Args> constexpr auto has_emplace(int) -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; } template <class ...Args> constexpr bool has_emplace(long) { return false; } template <class ...Args> constexpr bool has_emplace() { return has_emplace<Args...>(0); } template <class T, class IT, class ...Args> constexpr auto has_emplace_init_list(int) -> decltype(std::any{}.emplace<T>( {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()}, std::declval<Args>()...), true) { return true; } template <class ...Args> constexpr bool has_emplace_init_list(long) { return false; } template <class ...Args> constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); } void test_emplace_sfinae_constraints() { { static_assert(has_emplace<int>(), ""); static_assert(has_emplace<int, int>(), ""); static_assert(!has_emplace<int, int, int>(), "not constructible"); static_assert(!has_emplace_init_list<int, int>(), "not constructible from il"); } { static_assert(has_emplace<small>(), ""); static_assert(has_emplace<large>(), ""); static_assert(!has_emplace<small, void*>(), ""); static_assert(!has_emplace<large, void*>(), ""); static_assert(has_emplace_init_list<small, int>(), ""); static_assert(has_emplace_init_list<large, int>(), ""); static_assert(!has_emplace_init_list<small, void*>(), ""); static_assert(!has_emplace_init_list<large, void*>(), ""); } { // Test that the emplace SFINAE's away when the // argument is non-copyable struct NoCopy { NoCopy() = default; NoCopy(NoCopy const&) = delete; NoCopy(int) {} NoCopy(std::initializer_list<int>, int, int) {} }; static_assert(!has_emplace<NoCopy>(), ""); static_assert(!has_emplace<NoCopy, int>(), ""); static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), ""); static_assert(!has_emplace<NoCopy&>(), ""); static_assert(!has_emplace<NoCopy&, int>(), ""); static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), ""); static_assert(!has_emplace<NoCopy&&>(), ""); static_assert(!has_emplace<NoCopy&&, int>(), ""); static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), ""); } } int main() { test_emplace_type<small>(); test_emplace_type<large>(); test_emplace_type<small_throws_on_copy>(); test_emplace_type<large_throws_on_copy>(); test_emplace_type<throws_on_move>(); test_emplace_type_tracked<small_tracked_t>(); test_emplace_type_tracked<large_tracked_t>(); test_emplace_sfinae_constraints(); #ifndef TEST_HAS_NO_EXCEPTIONS test_emplace_throws<SmallThrows>(); test_emplace_throws<LargeThrows>(); #endif }