1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
15 // template<class T, class A>
16 // shared_ptr<T> allocate_shared(const A& a); // T is U[N]
18 // template<class T, class A>
19 // shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u); // T is U[N]
23 #include <cstdint> // std::uintptr_t
27 #include "min_allocator.h"
28 #include "operator_hijacker.h"
31 template <class T
, class ...Args
>
32 concept CanAllocateShared
= requires(Args
&& ...args
) {
33 { std::allocate_shared
<T
>(std::forward
<Args
>(args
)...) } -> std::same_as
<std::shared_ptr
<T
>>;
36 int main(int, char**) {
37 // Make sure we initialize elements correctly
39 // Without passing an initial value
42 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
43 for (unsigned i
= 0; i
< 8; ++i
) {
48 using Array
= int[8][3];
49 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
50 for (unsigned i
= 0; i
< 8; ++i
) {
51 assert(ptr
[i
][0] == 0);
52 assert(ptr
[i
][1] == 0);
53 assert(ptr
[i
][2] == 0);
57 using Array
= int[8][3][2];
58 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
59 for (unsigned i
= 0; i
< 8; ++i
) {
60 assert(ptr
[i
][0][0] == 0);
61 assert(ptr
[i
][0][1] == 0);
62 assert(ptr
[i
][1][0] == 0);
63 assert(ptr
[i
][1][1] == 0);
64 assert(ptr
[i
][2][0] == 0);
65 assert(ptr
[i
][2][1] == 0);
69 // Passing an initial value
73 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
74 for (unsigned i
= 0; i
< 8; ++i
) {
75 assert(ptr
[i
] == init
);
79 using Array
= int[8][3];
80 int init
[3] = {42, 43, 44};
81 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
82 for (unsigned i
= 0; i
< 8; ++i
) {
83 assert(ptr
[i
][0] == 42);
84 assert(ptr
[i
][1] == 43);
85 assert(ptr
[i
][2] == 44);
89 using Array
= int[8][3][2];
90 int init
[3][2] = {{31, 32}, {41, 42}, {51, 52}};
91 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
92 for (unsigned i
= 0; i
< 8; ++i
) {
93 assert(ptr
[i
][0][0] == 31);
94 assert(ptr
[i
][0][1] == 32);
95 assert(ptr
[i
][1][0] == 41);
96 assert(ptr
[i
][1][1] == 42);
97 assert(ptr
[i
][2][0] == 51);
98 assert(ptr
[i
][2][1] == 52);
103 // Make sure array elements are destroyed in reverse order
105 // Without passing an initial value
107 using Array
= DestroyInReverseOrder
[8];
108 DestroyInReverseOrder::reset();
110 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
111 assert(DestroyInReverseOrder::alive() == 8);
113 assert(DestroyInReverseOrder::alive() == 0);
116 using Array
= DestroyInReverseOrder
[8][3];
117 DestroyInReverseOrder::reset();
119 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
120 assert(DestroyInReverseOrder::alive() == 8 * 3);
122 assert(DestroyInReverseOrder::alive() == 0);
125 using Array
= DestroyInReverseOrder
[8][3][2];
126 DestroyInReverseOrder::reset();
128 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
129 assert(DestroyInReverseOrder::alive() == 8 * 3 * 2);
131 assert(DestroyInReverseOrder::alive() == 0);
134 // Passing an initial value
136 using Array
= DestroyInReverseOrder
[8];
138 DestroyInReverseOrder
init(&count
);
141 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
142 assert(count
== 8 + init_count
);
144 assert(count
== init_count
);
147 using Array
= DestroyInReverseOrder
[8][3];
149 DestroyInReverseOrder init
[3] = {&count
, &count
, &count
};
152 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
153 assert(count
== 8 * 3 + init_count
);
155 assert(count
== init_count
);
158 using Array
= DestroyInReverseOrder
[8][3][2];
160 DestroyInReverseOrder init
[3][2] = {{&count
, &count
}, {&count
, &count
}, {&count
, &count
}};
161 int init_count
= 3 * 2;
163 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
164 assert(count
== 8 * 3 * 2 + init_count
);
166 assert(count
== init_count
);
170 // Count the number of copies being made
172 // Without passing an initial value
174 using Array
= CountCopies
[8];
175 CountCopies::reset();
176 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
177 assert(CountCopies::copies() == 0);
180 using Array
= CountCopies
[8][3];
181 CountCopies::reset();
182 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());;
183 assert(CountCopies::copies() == 0);
186 using Array
= CountCopies
[8][3][2];
187 CountCopies::reset();
188 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());;
189 assert(CountCopies::copies() == 0);
192 // Passing an initial value
194 using Array
= CountCopies
[8];
196 CountCopies
init(&copies
);
197 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
201 using Array
= CountCopies
[8][3];
203 CountCopies init
[3] = {&copies
, &copies
, &copies
};
204 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
205 assert(copies
== 8 * 3);
208 using Array
= CountCopies
[8][3][2];
210 CountCopies init
[3][2] = {{&copies
, &copies
}, {&copies
, &copies
}, {&copies
, &copies
}};
211 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
212 assert(copies
== 8 * 3 * 2);
216 // Make sure array elements are aligned properly when the array contains an overaligned type.
218 // Here, we don't need to test both the with-initial-value and without-initial-value code paths,
219 // since we're just checking the alignment and both are going to use the same code path unless
220 // the implementation is completely crazy.
222 auto check_alignment
= []<class T
> {
225 std::shared_ptr ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
226 for (int i
= 0; i
< 8; ++i
) {
227 T
* p
= std::addressof(ptr
[i
]);
228 assert(reinterpret_cast<std::uintptr_t>(p
) % alignof(T
) == 0);
232 using Array
= T
[8][3];
233 std::shared_ptr ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
234 for (int i
= 0; i
< 8; ++i
) {
235 for (int j
= 0; j
< 3; ++j
) {
236 T
* p
= std::addressof(ptr
[i
][j
]);
237 assert(reinterpret_cast<std::uintptr_t>(p
) % alignof(T
) == 0);
242 using Array
= T
[8][3][2];
243 std::shared_ptr ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
244 for (int i
= 0; i
< 8; ++i
) {
245 for (int j
= 0; j
< 3; ++j
) {
246 for (int k
= 0; k
< 2; ++k
) {
247 T
* p
= std::addressof(ptr
[i
][j
][k
]);
248 assert(reinterpret_cast<std::uintptr_t>(p
) % alignof(T
) == 0);
256 check_alignment
.operator()<Empty
>();
257 check_alignment
.operator()<OverAligned
>();
258 check_alignment
.operator()<MaxAligned
>();
260 // test non corner cases as well while we're at it
261 struct Foo
{ int i
; char c
; };
262 check_alignment
.operator()<int>();
263 check_alignment
.operator()<Foo
>();
266 // Make sure that we destroy all the elements constructed so far when an exception
267 // is thrown. Also make sure that we do it in reverse order of construction.
268 #ifndef TEST_HAS_NO_EXCEPTIONS
270 struct Sentinel
: ThrowOnConstruction
, DestroyInReverseOrder
{ };
272 // Without passing an initial value
274 using Array
= Sentinel
[8];
275 for (int i
= 0; i
< 8; ++i
) {
276 ThrowOnConstruction::throw_after(i
);
277 DestroyInReverseOrder::reset();
279 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
281 } catch (ThrowOnConstruction::exception
const&) {
282 assert(DestroyInReverseOrder::alive() == 0);
287 using Array
= Sentinel
[8][3];
288 for (int i
= 0; i
< 8 * 3; ++i
) {
289 ThrowOnConstruction::throw_after(i
);
290 DestroyInReverseOrder::reset();
292 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
294 } catch (ThrowOnConstruction::exception
const&) {
295 assert(DestroyInReverseOrder::alive() == 0);
300 using Array
= Sentinel
[8][3][2];
301 for (int i
= 0; i
< 8 * 3 * 2; ++i
) {
302 ThrowOnConstruction::throw_after(i
);
303 DestroyInReverseOrder::reset();
305 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
307 } catch (ThrowOnConstruction::exception
const&) {
308 assert(DestroyInReverseOrder::alive() == 0);
313 // Passing an initial value
315 using Array
= Sentinel
[8];
316 for (int i
= 0; i
< 8; ++i
) {
317 DestroyInReverseOrder::reset();
318 ThrowOnConstruction::reset();
320 ThrowOnConstruction::throw_after(i
);
322 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
324 } catch (ThrowOnConstruction::exception
const&) {
325 assert(DestroyInReverseOrder::alive() == 1);
330 using Array
= Sentinel
[8][3];
331 for (int i
= 0; i
< 8 * 3; ++i
) {
332 DestroyInReverseOrder::reset();
333 ThrowOnConstruction::reset();
334 Sentinel init
[3] = {};
335 ThrowOnConstruction::throw_after(i
);
337 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
339 } catch (ThrowOnConstruction::exception
const&) {
340 assert(DestroyInReverseOrder::alive() == 3);
345 using Array
= Sentinel
[8][3][2];
346 for (int i
= 0; i
< 8 * 3 * 2; ++i
) {
347 DestroyInReverseOrder::reset();
348 ThrowOnConstruction::reset();
349 Sentinel init
[3][2] = {};
350 ThrowOnConstruction::throw_after(i
);
352 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
354 } catch (ThrowOnConstruction::exception
const&) {
355 assert(DestroyInReverseOrder::alive() == 3 * 2);
360 #endif // TEST_HAS_NO_EXCEPTIONS
362 // Test with another allocator that's not std::allocator
364 // Without passing an initial value
366 using Array
= int[8][3];
367 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(min_allocator
<Array
>());
368 for (unsigned i
= 0; i
< 8; ++i
) {
369 assert(ptr
[i
][0] == 0);
370 assert(ptr
[i
][1] == 0);
371 assert(ptr
[i
][2] == 0);
375 // Passing an initial value
377 using Array
= int[8][3];
378 int init
[3] = {42, 43, 44};
379 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(min_allocator
<Array
>(), init
);
380 for (unsigned i
= 0; i
< 8; ++i
) {
381 assert(ptr
[i
][0] == 42);
382 assert(ptr
[i
][1] == 43);
383 assert(ptr
[i
][2] == 44);
388 // Make sure the version without an initialization argument works even for non-movable types
390 using Array
= NonMovable
[8][3];
391 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
395 // Make sure std::allocate_shared handles badly-behaved types properly
397 using Array
= operator_hijacker
[3];
398 std::shared_ptr
<Array
> p1
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
399 std::shared_ptr
<Array
> p2
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), operator_hijacker());
400 assert(p1
!= nullptr);
401 assert(p2
!= nullptr);
404 // Check that we SFINAE-away for invalid arguments
407 static_assert( CanAllocateShared
<T
[8], std::allocator
<T
[8]>>);
408 static_assert( CanAllocateShared
<T
[8], std::allocator
<T
[8]>, T
>);
409 static_assert(!CanAllocateShared
<T
[8], std::allocator
<T
[8]>, T
, int>); // too many arguments
410 static_assert(!CanAllocateShared
<T
[8], std::allocator
<T
[8]>, int>); // T is not constructible from int