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// <memory>
10
11// shared_ptr
12
13// template<class T, class A, class... Args>
14// shared_ptr<T> allocate_shared(const A& a, Args&&... args);
15
16// This test checks that allocator_traits::construct and allocator_traits::destroy
17// are used in allocate_shared as requested for the resolution of LWG2070. Note
18// that LWG2070 was resolved by P0674R1 (which is a C++20 paper), but we implement
19// LWG issue resolutions as DRs per our policy.
20
21#include <cassert>
22#include <cstddef>
23#include <cstdint>
24#include <memory>
25#include <new>
26#include <utility>
27
28#include "test_macros.h"
29
30static bool construct_called = false;
31static bool destroy_called = false;
32static unsigned allocator_id = 0;
33
34template <class T>
35struct MyAllocator {
36public:
37 typedef T value_type;
38 typedef T* pointer;
39
40 unsigned id = 0;
41
42 MyAllocator() = default;
43 MyAllocator(int i) : id(i) {}
44
45 template <class U>
46 MyAllocator(MyAllocator<U> const& other) : id(other.id) {}
47
48 pointer allocate(std::ptrdiff_t n) {
49 return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
50 }
51
52 void deallocate(pointer p, std::ptrdiff_t) { return ::operator delete(p); }
53
54 template <typename ...Args>
55 void construct(T* p, Args&& ...args) {
56 construct_called = true;
57 destroy_called = false;
58 allocator_id = id;
59 ::new (p) T(std::forward<Args>(args)...);
60 }
61
62 void destroy(T* p) {
63 construct_called = false;
64 destroy_called = true;
65 allocator_id = id;
66 p->~T();
67 }
68};
69
70struct Private;
71
72class Factory {
73public:
74 static std::shared_ptr<Private> allocate();
75};
76
77template <class T>
78struct FactoryAllocator;
79
80struct Private {
81 int id;
82
83private:
84 friend FactoryAllocator<Private>;
85 Private(int i) : id(i) {}
86 ~Private() {}
87};
88
89template <class T>
90struct FactoryAllocator : std::allocator<T> {
91 FactoryAllocator() = default;
92
93 template <class T1>
94 FactoryAllocator(FactoryAllocator<T1>) {}
95
96 template <class T1>
97 struct rebind {
98 typedef FactoryAllocator<T1> other;
99 };
100
101 void construct(void* p, int id) { ::new (p) Private(id); }
102 void destroy(Private* p) { p->~Private(); }
103};
104
105std::shared_ptr<Private> Factory::allocate() {
106 FactoryAllocator<Private> factory_alloc;
107 return std::allocate_shared<Private>(a: factory_alloc, args: 42);
108}
109
110struct mchar {
111 char c;
112};
113
114struct Foo {
115 int val;
116
117 Foo(int v) : val(v) {}
118
119 Foo(Foo a, Foo b) : val(a.val + b.val) {}
120};
121
122void test_aligned(void* p, std::size_t align) {
123 assert(reinterpret_cast<std::uintptr_t>(p) % align == 0);
124}
125
126int main(int, char**) {
127 {
128 std::shared_ptr<int> p = std::allocate_shared<int>(a: MyAllocator<int>());
129 assert(construct_called);
130 }
131 assert(destroy_called);
132 {
133 std::shared_ptr<Foo> p =
134 std::allocate_shared<Foo>(a: MyAllocator<Foo>(), args: Foo(42), args: 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>(a: 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>(a: MyAllocator<int>(), args: 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>(a: MyAllocator<mchar>(), args: 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#if TEST_STD_VER >= 11
171 {
172 struct Bar {
173 std::max_align_t y;
174 };
175
176 std::shared_ptr<Bar> p;
177 test_aligned(p.get(), alignof(Bar));
178 }
179#endif
180
181 return 0;
182}
183

source code of libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.lwg2070.pass.cpp