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 | |
9 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
10 | |
11 | // <memory> |
12 | |
13 | // template <class T, class ...Args> |
14 | // constexpr T* construct_at(T* location, Args&& ...args); |
15 | |
16 | #include <memory> |
17 | #include <cassert> |
18 | #include <utility> |
19 | |
20 | #include "test_iterators.h" |
21 | |
22 | struct Foo { |
23 | constexpr Foo() { } |
24 | constexpr Foo(int a, char b, double c) : a_(a), b_(b), c_(c) { } |
25 | constexpr Foo(int a, char b, double c, int* count) : Foo(a, b, c) { *count += 1; } |
26 | constexpr bool operator==(Foo const& other) const { |
27 | return a_ == other.a_ && b_ == other.b_ && c_ == other.c_; |
28 | } |
29 | |
30 | private: |
31 | int a_; |
32 | char b_; |
33 | double c_; |
34 | }; |
35 | |
36 | struct Counted { |
37 | int& count_; |
38 | constexpr Counted(int& count) : count_(count) { ++count; } |
39 | constexpr Counted(Counted const& that) : count_(that.count_) { ++count_; } |
40 | constexpr ~Counted() { --count_; } |
41 | }; |
42 | |
43 | constexpr bool test() |
44 | { |
45 | { |
46 | int i = 99; |
47 | int* res = std::construct_at(&i); |
48 | assert(res == &i); |
49 | assert(*res == 0); |
50 | } |
51 | |
52 | { |
53 | int i = 0; |
54 | int* res = std::construct_at(&i, 42); |
55 | assert(res == &i); |
56 | assert(*res == 42); |
57 | } |
58 | |
59 | { |
60 | Foo foo = {}; |
61 | int count = 0; |
62 | Foo* res = std::construct_at(&foo, 42, 'x', 123.89, &count); |
63 | assert(res == &foo); |
64 | assert(*res == Foo(42, 'x', 123.89)); |
65 | assert(count == 1); |
66 | } |
67 | |
68 | { |
69 | std::allocator<Counted> a; |
70 | Counted* p = a.allocate(n: 2); |
71 | int count = 0; |
72 | std::construct_at(p, count); |
73 | assert(count == 1); |
74 | std::construct_at(p+1, count); |
75 | assert(count == 2); |
76 | (p+1)->~Counted(); |
77 | assert(count == 1); |
78 | p->~Counted(); |
79 | assert(count == 0); |
80 | a.deallocate(p: p, t: 2); |
81 | } |
82 | |
83 | { |
84 | std::allocator<Counted const> a; |
85 | Counted const* p = a.allocate(2); |
86 | int count = 0; |
87 | std::construct_at(p, count); |
88 | assert(count == 1); |
89 | std::construct_at(p+1, count); |
90 | assert(count == 2); |
91 | (p+1)->~Counted(); |
92 | assert(count == 1); |
93 | p->~Counted(); |
94 | assert(count == 0); |
95 | a.deallocate(p, 2); |
96 | } |
97 | |
98 | return true; |
99 | } |
100 | |
101 | template <class ...Args, class = decltype(std::construct_at(std::declval<Args>()...))> |
102 | constexpr bool can_construct_at(Args&&...) { return true; } |
103 | |
104 | template <class ...Args> |
105 | constexpr bool can_construct_at(...) { return false; } |
106 | |
107 | // Check that SFINAE works. |
108 | static_assert( can_construct_at((int*)nullptr, 42)); |
109 | static_assert( can_construct_at((Foo*)nullptr, 1, '2', 3.0)); |
110 | static_assert(!can_construct_at((Foo*)nullptr, 1, '2')); |
111 | static_assert(!can_construct_at((Foo*)nullptr, 1, '2', 3.0, 4)); |
112 | static_assert(!can_construct_at(nullptr, 1, '2', 3.0)); |
113 | static_assert(!can_construct_at((int*)nullptr, 1, '2', 3.0)); |
114 | static_assert(!can_construct_at(contiguous_iterator<Foo*>(), 1, '2', 3.0)); |
115 | // Can't construct function pointers. |
116 | static_assert(!can_construct_at((int(*)())nullptr)); |
117 | static_assert(!can_construct_at((int(*)())nullptr, nullptr)); |
118 | |
119 | int main(int, char**) |
120 | { |
121 | test(); |
122 | static_assert(test()); |
123 | return 0; |
124 | } |
125 | |