• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright 2012-2019 Glen Joseph Fernandes
3 (glenjofe@gmail.com)
4 
5 Distributed 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 
24 namespace boost {
25 namespace detail {
26 
27 template<class T>
28 struct sp_array_element {
29     typedef typename boost::remove_cv<typename
30         boost::remove_extent<T>::type>::type type;
31 };
32 
33 template<class T>
34 struct sp_array_count {
35     enum {
36         value = 1
37     };
38 };
39 
40 template<class T, std::size_t N>
41 struct sp_array_count<T[N]> {
42     enum {
43         value = N * sp_array_count<T>::value
44     };
45 };
46 
47 template<std::size_t N, std::size_t M>
48 struct sp_max_size {
49     enum {
50         value = N < M ? M : N
51     };
52 };
53 
54 template<std::size_t N, std::size_t M>
55 struct sp_align_up {
56     enum {
57         value = (N + M - 1) & ~(M - 1)
58     };
59 };
60 
61 template<class T>
62 BOOST_CONSTEXPR inline std::size_t
sp_objects(std::size_t size)63 sp_objects(std::size_t size) BOOST_SP_NOEXCEPT
64 {
65     return (size + sizeof(T) - 1) / sizeof(T);
66 }
67 
68 template<class A>
69 class sp_array_state {
70 public:
71     typedef A type;
72 
73     template<class U>
sp_array_state(const U & _allocator,std::size_t _size)74     sp_array_state(const U& _allocator, std::size_t _size) BOOST_SP_NOEXCEPT
75         : allocator_(_allocator),
76           size_(_size) { }
77 
allocator()78     A& allocator() BOOST_SP_NOEXCEPT {
79         return allocator_;
80     }
81 
size() const82     std::size_t size() const BOOST_SP_NOEXCEPT {
83         return size_;
84     }
85 
86 private:
87     A allocator_;
88     std::size_t size_;
89 };
90 
91 template<class A, std::size_t N>
92 class sp_size_array_state {
93 public:
94     typedef A type;
95 
96     template<class U>
sp_size_array_state(const U & _allocator,std::size_t)97     sp_size_array_state(const U& _allocator, std::size_t) BOOST_SP_NOEXCEPT
98         : allocator_(_allocator) { }
99 
allocator()100     A& allocator() BOOST_SP_NOEXCEPT {
101         return allocator_;
102     }
103 
size() const104     BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT {
105         return N;
106     }
107 
108 private:
109     A allocator_;
110 };
111 
112 template<class T, class U>
113 struct 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 
120 template<class T, class U>
121 struct sp_array_offset {
122     enum {
123         value = sp_align_up<sizeof(T), sp_array_alignment<T, U>::value>::value
124     };
125 };
126 
127 template<class U, class T>
128 inline U*
sp_array_start(T * base)129 sp_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 
137 template<class A, class T>
138 class 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 
148 public:
149     template<class U>
sp_array_creator(const U & other,std::size_t size)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 
create()154     T* create() {
155         return reinterpret_cast<T*>(other_.allocate(size_));
156     }
157 
destroy(T * base)158     void destroy(T* base) {
159         other_.deallocate(reinterpret_cast<type*>(base), size_);
160     }
161 
162 private:
163     typename boost::allocator_rebind<A, type>::type other_;
164     std::size_t size_;
165 };
166 
167 template<class T>
168 class BOOST_SYMBOL_VISIBLE sp_array_base
169     : public sp_counted_base {
170     typedef typename T::type allocator;
171 
172 public:
173     typedef typename allocator::value_type type;
174 
175     template<class A>
sp_array_base(const A & other,type * start,std::size_t size)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>
sp_array_base(const A & other,type * start,std::size_t size,const U & list)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 
state()194     T& state() BOOST_SP_NOEXCEPT {
195         return state_;
196     }
197 
dispose()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 
destroy()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 
get_deleter(const sp_typeinfo_ &)211     void* get_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
212         return 0;
213     }
214 
get_local_deleter(const sp_typeinfo_ &)215     void* get_local_deleter(const sp_typeinfo_&)
216         BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
217         return 0;
218     }
219 
get_untyped_deleter()220     void* get_untyped_deleter() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
221         return 0;
222     }
223 
224 private:
225     T state_;
226 };
227 
228 template<class A, class T>
229 struct sp_array_result {
230 public:
231     template<class U>
sp_array_resultboost::detail::sp_array_result232     sp_array_result(const U& other, std::size_t size)
233         : creator_(other, size),
234           result_(creator_.create()) { }
235 
~sp_array_resultboost::detail::sp_array_result236     ~sp_array_result() {
237         if (result_) {
238             creator_.destroy(result_);
239         }
240     }
241 
getboost::detail::sp_array_result242     T* get() const BOOST_SP_NOEXCEPT {
243         return result_;
244     }
245 
releaseboost::detail::sp_array_result246     void release() BOOST_SP_NOEXCEPT {
247         result_ = 0;
248     }
249 
250 private:
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 
260 template<class T, class A>
261 inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
allocate_shared(const A & allocator,std::size_t count)262 allocate_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 
277 template<class T, class A>
278 inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
allocate_shared(const A & allocator)279 allocate_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 
297 template<class T, class A>
298 inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
allocate_shared(const A & allocator,std::size_t count,const typename remove_extent<T>::type & value)299 allocate_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 
315 template<class T, class A>
316 inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
allocate_shared(const A & allocator,const typename remove_extent<T>::type & value)317 allocate_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 
336 template<class T, class A>
337 inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
allocate_shared_noinit(const A & allocator,std::size_t count)338 allocate_shared_noinit(const A& allocator, std::size_t count)
339 {
340     return boost::allocate_shared<T>(boost::noinit_adapt(allocator), count);
341 }
342 
343 template<class T, class A>
344 inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
allocate_shared_noinit(const A & allocator)345 allocate_shared_noinit(const A& allocator)
346 {
347     return boost::allocate_shared<T>(boost::noinit_adapt(allocator));
348 }
349 
350 } /* boost */
351 
352 #endif
353