1/*
2Copyright 2012-2019 Glen Joseph Fernandes
3(glenjofe@gmail.com)
4
5Distributed under the Boost Software License, Version 1.0.
6(http://www.boost.org/LICENSE_1_0.txt)
7*/
8#ifndef BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
9#define BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
10
11#include <boost/core/allocator_access.hpp>
12#include <boost/core/alloc_construct.hpp>
13#include <boost/core/first_scalar.hpp>
14#include <boost/smart_ptr/shared_ptr.hpp>
15#include <boost/type_traits/alignment_of.hpp>
16#include <boost/type_traits/enable_if.hpp>
17#include <boost/type_traits/extent.hpp>
18#include <boost/type_traits/is_bounded_array.hpp>
19#include <boost/type_traits/is_unbounded_array.hpp>
20#include <boost/type_traits/remove_cv.hpp>
21#include <boost/type_traits/remove_extent.hpp>
22#include <boost/type_traits/type_with_alignment.hpp>
23
24namespace boost {
25namespace detail {
26
27template<class T>
28struct sp_array_element {
29 typedef typename boost::remove_cv<typename
30 boost::remove_extent<T>::type>::type type;
31};
32
33template<class T>
34struct sp_array_count {
35 enum {
36 value = 1
37 };
38};
39
40template<class T, std::size_t N>
41struct sp_array_count<T[N]> {
42 enum {
43 value = N * sp_array_count<T>::value
44 };
45};
46
47template<std::size_t N, std::size_t M>
48struct sp_max_size {
49 enum {
50 value = N < M ? M : N
51 };
52};
53
54template<std::size_t N, std::size_t M>
55struct sp_align_up {
56 enum {
57 value = (N + M - 1) & ~(M - 1)
58 };
59};
60
61template<class T>
62BOOST_CONSTEXPR inline std::size_t
63sp_objects(std::size_t size) BOOST_SP_NOEXCEPT
64{
65 return (size + sizeof(T) - 1) / sizeof(T);
66}
67
68template<class A>
69class sp_array_state {
70public:
71 typedef A type;
72
73 template<class U>
74 sp_array_state(const U& _allocator, std::size_t _size) BOOST_SP_NOEXCEPT
75 : allocator_(_allocator),
76 size_(_size) { }
77
78 A& allocator() BOOST_SP_NOEXCEPT {
79 return allocator_;
80 }
81
82 std::size_t size() const BOOST_SP_NOEXCEPT {
83 return size_;
84 }
85
86private:
87 A allocator_;
88 std::size_t size_;
89};
90
91template<class A, std::size_t N>
92class sp_size_array_state {
93public:
94 typedef A type;
95
96 template<class U>
97 sp_size_array_state(const U& _allocator, std::size_t) BOOST_SP_NOEXCEPT
98 : allocator_(_allocator) { }
99
100 A& allocator() BOOST_SP_NOEXCEPT {
101 return allocator_;
102 }
103
104 BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT {
105 return N;
106 }
107
108private:
109 A allocator_;
110};
111
112template<class T, class U>
113struct sp_array_alignment {
114 enum {
115 value = sp_max_size<boost::alignment_of<T>::value,
116 boost::alignment_of<U>::value>::value
117 };
118};
119
120template<class T, class U>
121struct sp_array_offset {
122 enum {
123 value = sp_align_up<sizeof(T), sp_array_alignment<T, U>::value>::value
124 };
125};
126
127template<class U, class T>
128inline U*
129sp_array_start(T* base) BOOST_SP_NOEXCEPT
130{
131 enum {
132 size = sp_array_offset<T, U>::value
133 };
134 return reinterpret_cast<U*>(reinterpret_cast<char*>(base) + size);
135}
136
137template<class A, class T>
138class sp_array_creator {
139 typedef typename A::value_type element;
140
141 enum {
142 offset = sp_array_offset<T, element>::value
143 };
144
145 typedef typename boost::type_with_alignment<sp_array_alignment<T,
146 element>::value>::type type;
147
148public:
149 template<class U>
150 sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
151 : other_(other),
152 size_(sp_objects<type>(offset + sizeof(element) * size)) { }
153
154 T* create() {
155 return reinterpret_cast<T*>(other_.allocate(size_));
156 }
157
158 void destroy(T* base) {
159 other_.deallocate(reinterpret_cast<type*>(base), size_);
160 }
161
162private:
163 typename boost::allocator_rebind<A, type>::type other_;
164 std::size_t size_;
165};
166
167template<class T>
168class BOOST_SYMBOL_VISIBLE sp_array_base
169 : public sp_counted_base {
170 typedef typename T::type allocator;
171
172public:
173 typedef typename allocator::value_type type;
174
175 template<class A>
176 sp_array_base(const A& other, type* start, std::size_t size)
177 : state_(other, size) {
178 boost::alloc_construct_n(state_.allocator(),
179 boost::first_scalar(start),
180 state_.size() * sp_array_count<type>::value);
181 }
182
183 template<class A, class U>
184 sp_array_base(const A& other, type* start, std::size_t size, const U& list)
185 : state_(other, size) {
186 enum {
187 count = sp_array_count<type>::value
188 };
189 boost::alloc_construct_n(state_.allocator(),
190 boost::first_scalar(start), state_.size() * count,
191 boost::first_scalar(&list), count);
192 }
193
194 T& state() BOOST_SP_NOEXCEPT {
195 return state_;
196 }
197
198 void dispose() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
199 boost::alloc_destroy_n(state_.allocator(),
200 boost::first_scalar(sp_array_start<type>(this)),
201 state_.size() * sp_array_count<type>::value);
202 }
203
204 void destroy() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
205 sp_array_creator<allocator, sp_array_base> other(state_.allocator(),
206 state_.size());
207 this->~sp_array_base();
208 other.destroy(this);
209 }
210
211 void* get_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
212 return 0;
213 }
214
215 void* get_local_deleter(const sp_typeinfo_&)
216 BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
217 return 0;
218 }
219
220 void* get_untyped_deleter() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
221 return 0;
222 }
223
224private:
225 T state_;
226};
227
228template<class A, class T>
229struct sp_array_result {
230public:
231 template<class U>
232 sp_array_result(const U& other, std::size_t size)
233 : creator_(other, size),
234 result_(creator_.create()) { }
235
236 ~sp_array_result() {
237 if (result_) {
238 creator_.destroy(result_);
239 }
240 }
241
242 T* get() const BOOST_SP_NOEXCEPT {
243 return result_;
244 }
245
246 void release() BOOST_SP_NOEXCEPT {
247 result_ = 0;
248 }
249
250private:
251 sp_array_result(const sp_array_result&);
252 sp_array_result& operator=(const sp_array_result&);
253
254 sp_array_creator<A, T> creator_;
255 T* result_;
256};
257
258} /* detail */
259
260template<class T, class A>
261inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
262allocate_shared(const A& allocator, std::size_t count)
263{
264 typedef typename detail::sp_array_element<T>::type element;
265 typedef typename allocator_rebind<A, element>::type other;
266 typedef detail::sp_array_state<other> state;
267 typedef detail::sp_array_base<state> base;
268 detail::sp_array_result<other, base> result(allocator, count);
269 base* node = result.get();
270 element* start = detail::sp_array_start<element>(node);
271 ::new(static_cast<void*>(node)) base(allocator, start, count);
272 result.release();
273 return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
274 detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
275}
276
277template<class T, class A>
278inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
279allocate_shared(const A& allocator)
280{
281 enum {
282 count = extent<T>::value
283 };
284 typedef typename detail::sp_array_element<T>::type element;
285 typedef typename allocator_rebind<A, element>::type other;
286 typedef detail::sp_size_array_state<other, extent<T>::value> state;
287 typedef detail::sp_array_base<state> base;
288 detail::sp_array_result<other, base> result(allocator, count);
289 base* node = result.get();
290 element* start = detail::sp_array_start<element>(node);
291 ::new(static_cast<void*>(node)) base(allocator, start, count);
292 result.release();
293 return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
294 detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
295}
296
297template<class T, class A>
298inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
299allocate_shared(const A& allocator, std::size_t count,
300 const typename remove_extent<T>::type& value)
301{
302 typedef typename detail::sp_array_element<T>::type element;
303 typedef typename allocator_rebind<A, element>::type other;
304 typedef detail::sp_array_state<other> state;
305 typedef detail::sp_array_base<state> base;
306 detail::sp_array_result<other, base> result(allocator, count);
307 base* node = result.get();
308 element* start = detail::sp_array_start<element>(node);
309 ::new(static_cast<void*>(node)) base(allocator, start, count, value);
310 result.release();
311 return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
312 detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
313}
314
315template<class T, class A>
316inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
317allocate_shared(const A& allocator,
318 const typename remove_extent<T>::type& value)
319{
320 enum {
321 count = extent<T>::value
322 };
323 typedef typename detail::sp_array_element<T>::type element;
324 typedef typename allocator_rebind<A, element>::type other;
325 typedef detail::sp_size_array_state<other, extent<T>::value> state;
326 typedef detail::sp_array_base<state> base;
327 detail::sp_array_result<other, base> result(allocator, count);
328 base* node = result.get();
329 element* start = detail::sp_array_start<element>(node);
330 ::new(static_cast<void*>(node)) base(allocator, start, count, value);
331 result.release();
332 return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
333 detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
334}
335
336template<class T, class A>
337inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
338allocate_shared_noinit(const A& allocator, std::size_t count)
339{
340 return boost::allocate_shared<T>(boost::noinit_adapt(allocator), count);
341}
342
343template<class T, class A>
344inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
345allocate_shared_noinit(const A& allocator)
346{
347 return boost::allocate_shared<T>(boost::noinit_adapt(allocator));
348}
349
350} /* boost */
351
352#endif
353

source code of include/boost/smart_ptr/allocate_shared_array.hpp