285 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// <any>12 13// template <class T, class ...Args> T& emplace(Args&&...);14// template <class T, class U, class ...Args>15// T& emplace(initializer_list<U>, Args&&...);16 17#include <any>18#include <cassert>19 20#include "any_helpers.h"21#include "count_new.h"22#include "test_macros.h"23 24struct Tracked {25 static int count;26 Tracked() { ++count; }27 Tracked(Tracked const&) noexcept { ++count; }28 Tracked& operator=(Tracked const&) = default;29 ~Tracked() { --count; }30};31int Tracked::count = 0;32 33template <class Type>34void test_emplace_type() {35 // constructing from a small type should perform no allocations.36 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);37 assert(Type::count == 0);38 Type::reset();39 {40 std::any a(std::in_place_type<Tracked>);41 assert(Tracked::count == 1);42 43 auto &v = a.emplace<Type>();44 static_assert( std::is_same_v<Type&, decltype(v)>, "" );45 assert(&v == std::any_cast<Type>(&a));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 std::any a(std::in_place_type<Tracked>);57 assert(Tracked::count == 1);58 59 auto &v = a.emplace<Type>(101);60 static_assert( std::is_same_v<Type&, decltype(v)>, "" );61 assert(&v == std::any_cast<Type>(&a));62 63 assert(Tracked::count == 0);64 assert(Type::count == 1);65 assert(Type::copied == 0);66 assert(Type::moved == 0);67 assertContains<Type>(a, 101);68 }69 assert(Type::count == 0);70 Type::reset();71 {72 std::any a(std::in_place_type<Tracked>);73 assert(Tracked::count == 1);74 75 auto &v = a.emplace<Type>(-1, 42, -1);76 static_assert( std::is_same_v<Type&, decltype(v)>, "" );77 assert(&v == std::any_cast<Type>(&a));78 79 assert(Tracked::count == 0);80 assert(Type::count == 1);81 assert(Type::copied == 0);82 assert(Type::moved == 0);83 assertContains<Type>(a, 42);84 }85 assert(Type::count == 0);86 Type::reset();87}88 89template <class Type>90void test_emplace_type_tracked() {91 // constructing from a small type should perform no allocations.92 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);93 {94 std::any a(std::in_place_type<Tracked>);95 assert(Tracked::count == 1);96 auto &v = a.emplace<Type>();97 static_assert( std::is_same_v<Type&, decltype(v)>, "" );98 assert(&v == std::any_cast<Type>(&a));99 100 assert(Tracked::count == 0);101 assertArgsMatch<Type>(a);102 }103 {104 std::any a(std::in_place_type<Tracked>);105 assert(Tracked::count == 1);106 auto &v = a.emplace<Type>(-1, 42, -1);107 static_assert( std::is_same_v<Type&, decltype(v)>, "" );108 assert(&v == std::any_cast<Type>(&a));109 110 assert(Tracked::count == 0);111 assertArgsMatch<Type, int, int, int>(a);112 }113 // initializer_list constructor tests114 {115 std::any a(std::in_place_type<Tracked>);116 assert(Tracked::count == 1);117 auto &v = a.emplace<Type>({-1, 42, -1});118 static_assert( std::is_same_v<Type&, decltype(v)>, "" );119 assert(&v == std::any_cast<Type>(&a));120 121 assert(Tracked::count == 0);122 assertArgsMatch<Type, std::initializer_list<int>>(a);123 }124 {125 int x = 42;126 std::any a(std::in_place_type<Tracked>);127 assert(Tracked::count == 1);128 auto &v = a.emplace<Type>({-1, 42, -1}, x);129 static_assert( std::is_same_v<Type&, decltype(v)>, "" );130 assert(&v == std::any_cast<Type>(&a));131 132 assert(Tracked::count == 0);133 assertArgsMatch<Type, std::initializer_list<int>, int&>(a);134 }135}136 137#ifndef TEST_HAS_NO_EXCEPTIONS138 139struct SmallThrows {140 SmallThrows(int) { throw 42; }141 SmallThrows(std::initializer_list<int>, int) { throw 42; }142};143static_assert(IsSmallObject<SmallThrows>::value, "");144 145struct LargeThrows {146 LargeThrows(int) { throw 42; }147 LargeThrows(std::initializer_list<int>, int) { throw 42; }148 int data[sizeof(std::any)];149};150static_assert(!IsSmallObject<LargeThrows>::value, "");151 152template <class Type>153void test_emplace_throws()154{155 // any stores small type156 {157 std::any a(small{42});158 assert(small::count == 1);159 try {160 auto &v = a.emplace<Type>(101);161 static_assert( std::is_same_v<Type&, decltype(v)>, "" );162 assert(false);163 } catch (int const&) {164 }165 assert(small::count == 0);166 }167 {168 std::any a(small{42});169 assert(small::count == 1);170 try {171 auto &v = a.emplace<Type>({1, 2, 3}, 101);172 static_assert( std::is_same_v<Type&, decltype(v)>, "" );173 assert(false);174 } catch (int const&) {175 }176 assert(small::count == 0);177 }178 // any stores large type179 {180 std::any a(large{42});181 assert(large::count == 1);182 try {183 auto &v = a.emplace<Type>(101);184 static_assert( std::is_same_v<Type&, decltype(v)>, "" );185 assert(false);186 } catch (int const&) {187 }188 assert(large::count == 0);189 }190 {191 std::any a(large{42});192 assert(large::count == 1);193 try {194 auto &v = a.emplace<Type>({1, 2, 3}, 101);195 static_assert( std::is_same_v<Type&, decltype(v)>, "" );196 assert(false);197 } catch (int const&) {198 }199 assert(large::count == 0);200 }201}202 203#endif204 205template <class T, class ...Args>206constexpr auto has_emplace(int)207 -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; }208 209template <class ...Args>210constexpr bool has_emplace(long) { return false; }211 212template <class ...Args>213constexpr bool has_emplace() { return has_emplace<Args...>(0); }214 215 216template <class T, class IT, class ...Args>217constexpr auto has_emplace_init_list(int)218 -> decltype(std::any{}.emplace<T>(219 {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()},220 std::declval<Args>()...), true) { return true; }221 222template <class ...Args>223constexpr bool has_emplace_init_list(long) { return false; }224 225template <class ...Args>226constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); }227 228 229void test_emplace_sfinae_constraints() {230 {231 static_assert(has_emplace<int>(), "");232 static_assert(has_emplace<int, int>(), "");233 static_assert(!has_emplace<int, int, int>(), "not constructible");234 static_assert(!has_emplace_init_list<int, int>(), "not constructible from il");235 }236 {237 static_assert(has_emplace<small>(), "");238 static_assert(has_emplace<large>(), "");239 static_assert(!has_emplace<small, void*>(), "");240 static_assert(!has_emplace<large, void*>(), "");241 242 static_assert(has_emplace_init_list<small, int>(), "");243 static_assert(has_emplace_init_list<large, int>(), "");244 static_assert(!has_emplace_init_list<small, void*>(), "");245 static_assert(!has_emplace_init_list<large, void*>(), "");246 }247 {248 // Test that the emplace SFINAE's away when the249 // argument is non-copyable250 struct NoCopy {251 NoCopy() = default;252 NoCopy(NoCopy const&) = delete;253 NoCopy(int) {}254 NoCopy(std::initializer_list<int>, int, int) {}255 };256 static_assert(!has_emplace<NoCopy>(), "");257 static_assert(!has_emplace<NoCopy, int>(), "");258 static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), "");259 static_assert(!has_emplace<NoCopy&>(), "");260 static_assert(!has_emplace<NoCopy&, int>(), "");261 static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), "");262 static_assert(!has_emplace<NoCopy&&>(), "");263 static_assert(!has_emplace<NoCopy&&, int>(), "");264 static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), "");265 266 }267}268 269int main(int, char**) {270 test_emplace_type<small>();271 test_emplace_type<large>();272 test_emplace_type<small_throws_on_copy>();273 test_emplace_type<large_throws_on_copy>();274 test_emplace_type<throws_on_move>();275 test_emplace_type_tracked<small_tracked_t>();276 test_emplace_type_tracked<large_tracked_t>();277 test_emplace_sfinae_constraints();278#ifndef TEST_HAS_NO_EXCEPTIONS279 test_emplace_throws<SmallThrows>();280 test_emplace_throws<LargeThrows>();281#endif282 283 return 0;284}285