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 // shared_ptr
14
15 // template<class T, class A, class... Args>
16 // shared_ptr<T> allocate_shared(const A& a, Args&&... args);
17
18 // This test checks that allocator_traits::construct is used in allocate_shared
19 // as requested in C++20 (via P0674R1).
20
21 #include "test_macros.h"
22
23 #include <memory>
24 #include <cassert>
25
26 static bool construct_called = false;
27 static bool destroy_called = false;
28 static unsigned allocator_id = 0;
29
30 template <class T>
31 struct MyAllocator {
32 public:
33 typedef T value_type;
34 typedef T* pointer;
35
36 unsigned id = 0;
37
38 MyAllocator() = default;
MyAllocatorMyAllocator39 MyAllocator(int i) : id(i) {}
40
41 template <class U>
MyAllocatorMyAllocator42 MyAllocator(MyAllocator<U> const& other) : id(other.id){};
43
allocateMyAllocator44 pointer allocate(std::ptrdiff_t n) {
45 return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
46 }
47
deallocateMyAllocator48 void deallocate(pointer p, std::ptrdiff_t) { return ::operator delete(p); }
49
50 template <typename ...Args>
constructMyAllocator51 void construct(T* p, Args&& ...args) {
52 construct_called = true;
53 destroy_called = false;
54 allocator_id = id;
55 ::new (p) T(std::forward<Args>(args)...);
56 }
57
destroyMyAllocator58 void destroy(T* p) {
59 construct_called = false;
60 destroy_called = true;
61 allocator_id = id;
62 p->~T();
63 }
64 };
65
66 struct Private;
67
68 class Factory {
69 public:
70 static std::shared_ptr<Private> allocate();
71 };
72
73 template <class T>
74 struct FactoryAllocator;
75
76 struct Private {
77 int id;
78
79 private:
80 friend FactoryAllocator<Private>;
PrivatePrivate81 Private(int i) : id(i) {}
~PrivatePrivate82 ~Private() {}
83 };
84
85 template <class T>
86 struct FactoryAllocator : std::allocator<T> {
87 FactoryAllocator() = default;
88
89 template <class T1>
FactoryAllocatorFactoryAllocator90 FactoryAllocator(FactoryAllocator<T1>) {}
91
92 template <class T1>
93 struct rebind {
94 typedef FactoryAllocator<T1> other;
95 };
96
constructFactoryAllocator97 void construct(void* p, int id) { ::new (p) Private(id); }
destroyFactoryAllocator98 void destroy(Private* p) { p->~Private(); }
99 };
100
allocate()101 std::shared_ptr<Private> Factory::allocate() {
102 FactoryAllocator<Private> factory_alloc;
103 return std::allocate_shared<Private>(factory_alloc, 42);
104 }
105
106 struct mchar {
107 char c;
108 };
109
110 struct Foo {
111 int val;
112
FooFoo113 Foo(int v) : val(v) {}
114
FooFoo115 Foo(Foo a, Foo b) : val(a.val + b.val) {}
116 };
117
118 struct Bar {
119 std::max_align_t y;
120 };
121
test_aligned(void * p,size_t align)122 void test_aligned(void* p, size_t align) {
123 assert(reinterpret_cast<uintptr_t>(p) % align == 0);
124 }
125
main(int,char **)126 int main(int, char**) {
127 {
128 std::shared_ptr<int> p = std::allocate_shared<int>(MyAllocator<int>());
129 assert(construct_called);
130 }
131 assert(destroy_called);
132 {
133 std::shared_ptr<Foo> p =
134 std::allocate_shared<Foo>(MyAllocator<Foo>(), Foo(42), Foo(100));
135 assert(construct_called);
136 assert(p->val == 142);
137 }
138 assert(destroy_called);
139 { // Make sure allocator is copied.
140 std::shared_ptr<int> p = std::allocate_shared<int>(MyAllocator<int>(3));
141 assert(allocator_id == 3);
142
143 allocator_id = 0;
144 }
145 assert(allocator_id == 3);
146
147 {
148 std::shared_ptr<int> p = std::allocate_shared<int>(MyAllocator<int>(), 42);
149 assert(construct_called);
150 assert(*p == 42);
151 }
152 assert(destroy_called);
153
154 { // Make sure allocator is properly re-bound.
155 std::shared_ptr<int> p =
156 std::allocate_shared<int>(MyAllocator<mchar>(), 42);
157 assert(construct_called);
158 assert(*p == 42);
159 }
160 assert(destroy_called);
161
162 {
163 // Make sure that we call the correct allocator::construct. Private has a private constructor
164 // so the construct method must be called on its friend Factory's allocator
165 // (Factory::Allocator).
166 std::shared_ptr<Private> p = Factory().allocate();
167 assert(p->id == 42);
168 }
169
170 {
171 std::shared_ptr<Bar> p;
172 test_aligned(p.get(), alignof(Bar));
173 }
174
175 return 0;
176 }
177