1 /*
2 Copyright 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_UNIQUE_HPP
9 #define BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP
10
11 #include <boost/smart_ptr/detail/sp_noexcept.hpp>
12 #include <boost/smart_ptr/detail/sp_nullptr_t.hpp>
13 #include <boost/core/allocator_access.hpp>
14 #include <boost/core/alloc_construct.hpp>
15 #include <boost/core/empty_value.hpp>
16 #include <boost/core/first_scalar.hpp>
17 #include <boost/core/noinit_adaptor.hpp>
18 #include <boost/core/pointer_traits.hpp>
19 #include <boost/type_traits/enable_if.hpp>
20 #include <boost/type_traits/extent.hpp>
21 #include <boost/type_traits/is_array.hpp>
22 #include <boost/type_traits/is_bounded_array.hpp>
23 #include <boost/type_traits/is_unbounded_array.hpp>
24 #include <boost/type_traits/remove_cv.hpp>
25 #include <boost/type_traits/remove_extent.hpp>
26 #include <boost/type_traits/type_identity.hpp>
27 #include <boost/config.hpp>
28 #include <memory>
29 #include <utility>
30
31 namespace boost {
32 namespace detail {
33
34 template<class T>
35 struct sp_alloc_size {
36 BOOST_STATIC_CONSTEXPR std::size_t value = 1;
37 };
38
39 template<class T>
40 struct sp_alloc_size<T[]> {
41 BOOST_STATIC_CONSTEXPR std::size_t value = sp_alloc_size<T>::value;
42 };
43
44 template<class T, std::size_t N>
45 struct sp_alloc_size<T[N]> {
46 BOOST_STATIC_CONSTEXPR std::size_t value = N * sp_alloc_size<T>::value;
47 };
48
49 template<class T>
50 struct sp_alloc_result {
51 typedef T type;
52 };
53
54 template<class T, std::size_t N>
55 struct sp_alloc_result<T[N]> {
56 typedef T type[];
57 };
58
59 template<class T>
60 struct sp_alloc_value {
61 typedef typename boost::remove_cv<typename
62 boost::remove_extent<T>::type>::type type;
63 };
64
65 template<class T, class P>
66 class sp_alloc_ptr {
67 public:
68 typedef T element_type;
69
sp_alloc_ptr()70 sp_alloc_ptr() BOOST_SP_NOEXCEPT
71 : p_() { }
72
73 #if defined(BOOST_MSVC) && BOOST_MSVC == 1600
sp_alloc_ptr(T * p)74 sp_alloc_ptr(T* p) BOOST_SP_NOEXCEPT
75 : p_(const_cast<typename boost::remove_cv<T>::type*>(p)) { }
76 #endif
77
sp_alloc_ptr(std::size_t,P p)78 sp_alloc_ptr(std::size_t, P p) BOOST_SP_NOEXCEPT
79 : p_(p) { }
80
81 #if !defined(BOOST_NO_CXX11_NULLPTR)
sp_alloc_ptr(detail::sp_nullptr_t)82 sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
83 : p_() { }
84 #endif
85
operator *() const86 T& operator*() const {
87 return *p_;
88 }
89
operator ->() const90 T* operator->() const BOOST_SP_NOEXCEPT {
91 return boost::to_address(p_);
92 }
93
94 #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
operator bool() const95 explicit operator bool() const BOOST_SP_NOEXCEPT {
96 return !!p_;
97 }
98 #endif
99
operator !() const100 bool operator!() const BOOST_SP_NOEXCEPT {
101 return !p_;
102 }
103
ptr() const104 P ptr() const BOOST_SP_NOEXCEPT {
105 return p_;
106 }
107
size()108 BOOST_STATIC_CONSTEXPR std::size_t size() BOOST_SP_NOEXCEPT {
109 return 1;
110 }
111
112 #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
pointer_to(T & v)113 static sp_alloc_ptr pointer_to(T& v) {
114 return sp_alloc_ptr(1,
115 std::pointer_traits<P>::pointer_to(const_cast<typename
116 boost::remove_cv<T>::type&>(v)));
117 }
118 #endif
119
120 private:
121 P p_;
122 };
123
124 template<class T, class P>
125 class sp_alloc_ptr<T[], P> {
126 public:
127 typedef T element_type;
128
sp_alloc_ptr()129 sp_alloc_ptr() BOOST_SP_NOEXCEPT
130 : p_() { }
131
sp_alloc_ptr(std::size_t n,P p)132 sp_alloc_ptr(std::size_t n, P p) BOOST_SP_NOEXCEPT
133 : p_(p)
134 , n_(n) { }
135
136 #if !defined(BOOST_NO_CXX11_NULLPTR)
sp_alloc_ptr(detail::sp_nullptr_t)137 sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
138 : p_() { }
139 #endif
140
operator [](std::size_t i) const141 T& operator[](std::size_t i) const {
142 return p_[i];
143 }
144
145 #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
operator bool() const146 explicit operator bool() const BOOST_SP_NOEXCEPT {
147 return !!p_;
148 }
149 #endif
150
operator !() const151 bool operator!() const BOOST_SP_NOEXCEPT {
152 return !p_;
153 }
154
ptr() const155 P ptr() const BOOST_SP_NOEXCEPT {
156 return p_;
157 }
158
size() const159 std::size_t size() const BOOST_SP_NOEXCEPT {
160 return n_;
161 }
162
163 #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
pointer_to(T & v)164 static sp_alloc_ptr pointer_to(T& v) {
165 return sp_alloc_ptr(n_,
166 std::pointer_traits<P>::pointer_to(const_cast<typename
167 boost::remove_cv<T>::type&>(v)));
168 }
169 #endif
170
171 private:
172 P p_;
173 std::size_t n_;
174 };
175
176 template<class T, std::size_t N, class P>
177 class sp_alloc_ptr<T[N], P> {
178 public:
179 typedef T element_type;
180
sp_alloc_ptr()181 sp_alloc_ptr() BOOST_SP_NOEXCEPT
182 : p_() { }
183
sp_alloc_ptr(std::size_t,P p)184 sp_alloc_ptr(std::size_t, P p) BOOST_SP_NOEXCEPT
185 : p_(p) { }
186
187 #if !defined(BOOST_NO_CXX11_NULLPTR)
sp_alloc_ptr(detail::sp_nullptr_t)188 sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
189 : p_() { }
190 #endif
191
operator [](std::size_t i) const192 T& operator[](std::size_t i) const {
193 return p_[i];
194 }
195
196 #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
operator bool() const197 explicit operator bool() const BOOST_SP_NOEXCEPT {
198 return !!p_;
199 }
200 #endif
201
operator !() const202 bool operator!() const BOOST_SP_NOEXCEPT {
203 return !p_;
204 }
205
ptr() const206 P ptr() const BOOST_SP_NOEXCEPT {
207 return p_;
208 }
209
size()210 BOOST_STATIC_CONSTEXPR std::size_t size() BOOST_SP_NOEXCEPT {
211 return N;
212 }
213
214 #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
pointer_to(T & v)215 static sp_alloc_ptr pointer_to(T& v) {
216 return sp_alloc_ptr(N,
217 std::pointer_traits<P>::pointer_to(const_cast<typename
218 boost::remove_cv<T>::type&>(v)));
219 }
220 #endif
221
222 private:
223 P p_;
224 };
225
226 template<class T, class P>
227 inline bool
operator ==(const sp_alloc_ptr<T,P> & lhs,const sp_alloc_ptr<T,P> & rhs)228 operator==(const sp_alloc_ptr<T, P>& lhs, const sp_alloc_ptr<T, P>& rhs)
229 {
230 return lhs.ptr() == rhs.ptr();
231 }
232
233 template<class T, class P>
234 inline bool
operator !=(const sp_alloc_ptr<T,P> & lhs,const sp_alloc_ptr<T,P> & rhs)235 operator!=(const sp_alloc_ptr<T, P>& lhs, const sp_alloc_ptr<T, P>& rhs)
236 {
237 return !(lhs == rhs);
238 }
239
240 #if !defined(BOOST_NO_CXX11_NULLPTR)
241 template<class T, class P>
242 inline bool
operator ==(const sp_alloc_ptr<T,P> & lhs,detail::sp_nullptr_t)243 operator==(const sp_alloc_ptr<T, P>& lhs,
244 detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
245 {
246 return !lhs.ptr();
247 }
248
249 template<class T, class P>
250 inline bool
operator ==(detail::sp_nullptr_t,const sp_alloc_ptr<T,P> & rhs)251 operator==(detail::sp_nullptr_t,
252 const sp_alloc_ptr<T, P>& rhs) BOOST_SP_NOEXCEPT
253 {
254 return !rhs.ptr();
255 }
256
257 template<class T, class P>
258 inline bool
operator !=(const sp_alloc_ptr<T,P> & lhs,detail::sp_nullptr_t)259 operator!=(const sp_alloc_ptr<T, P>& lhs,
260 detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
261 {
262 return !!lhs.ptr();
263 }
264
265 template<class T, class P>
266 inline bool
operator !=(detail::sp_nullptr_t,const sp_alloc_ptr<T,P> & rhs)267 operator!=(detail::sp_nullptr_t,
268 const sp_alloc_ptr<T, P>& rhs) BOOST_SP_NOEXCEPT
269 {
270 return !!rhs.ptr();
271 }
272 #endif
273
274 template<class A>
275 inline void
sp_alloc_clear(A & a,typename boost::allocator_pointer<A>::type p,std::size_t,boost::false_type)276 sp_alloc_clear(A& a, typename boost::allocator_pointer<A>::type p, std::size_t,
277 boost::false_type)
278 {
279 boost::alloc_destroy(a, boost::to_address(p));
280 }
281
282 template<class A>
283 inline void
sp_alloc_clear(A & a,typename boost::allocator_pointer<A>::type p,std::size_t n,boost::true_type)284 sp_alloc_clear(A& a, typename boost::allocator_pointer<A>::type p,
285 std::size_t n, boost::true_type)
286 {
287 #if defined(BOOST_MSVC) && BOOST_MSVC < 1800
288 if (!p) {
289 return;
290 }
291 #endif
292 boost::alloc_destroy_n(a, boost::first_scalar(boost::to_address(p)),
293 n * sp_alloc_size<typename A::value_type>::value);
294 }
295
296 } /* detail */
297
298 template<class T, class A>
299 class alloc_deleter
300 : empty_value<typename allocator_rebind<A,
301 typename detail::sp_alloc_value<T>::type>::type> {
302 typedef typename allocator_rebind<A,
303 typename detail::sp_alloc_value<T>::type>::type allocator;
304 typedef empty_value<allocator> base;
305
306 public:
307 typedef detail::sp_alloc_ptr<T,
308 typename allocator_pointer<allocator>::type> pointer;
309
alloc_deleter(const allocator & a)310 explicit alloc_deleter(const allocator& a) BOOST_SP_NOEXCEPT
311 : base(empty_init_t(), a) { }
312
operator ()(pointer p)313 void operator()(pointer p) {
314 detail::sp_alloc_clear(base::get(), p.ptr(), p.size(), is_array<T>());
315 base::get().deallocate(p.ptr(), p.size());
316 }
317 };
318
319 #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
320 template<class T, class A>
321 using alloc_noinit_deleter = alloc_deleter<T, noinit_adaptor<A> >;
322 #endif
323
324 namespace detail {
325
326 template<class T, class A>
327 class sp_alloc_make {
328 public:
329 typedef typename boost::allocator_rebind<A,
330 typename sp_alloc_value<T>::type>::type allocator;
331
332 private:
333 typedef boost::alloc_deleter<T, A> deleter;
334
335 public:
336 typedef std::unique_ptr<typename sp_alloc_result<T>::type, deleter> type;
337
sp_alloc_make(const A & a,std::size_t n)338 sp_alloc_make(const A& a, std::size_t n)
339 : a_(a)
340 , n_(n)
341 , p_(a_.allocate(n)) { }
342
~sp_alloc_make()343 ~sp_alloc_make() {
344 if (p_) {
345 a_.deallocate(p_, n_);
346 }
347 }
348
get() const349 typename allocator::value_type* get() const BOOST_SP_NOEXCEPT {
350 return boost::to_address(p_);
351 }
352
state()353 allocator& state() BOOST_SP_NOEXCEPT {
354 return a_;
355 }
356
release()357 type release() BOOST_SP_NOEXCEPT {
358 pointer p = p_;
359 p_ = pointer();
360 return type(typename deleter::pointer(n_, p), deleter(a_));
361 }
362
363 private:
364 typedef typename boost::allocator_pointer<allocator>::type pointer;
365
366 allocator a_;
367 std::size_t n_;
368 pointer p_;
369 };
370
371 } /* detail */
372
373 template<class T, class A>
374 inline typename enable_if_<!is_array<T>::value,
375 std::unique_ptr<T, alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc)376 allocate_unique(const A& alloc)
377 {
378 detail::sp_alloc_make<T, A> c(alloc, 1);
379 boost::alloc_construct(c.state(), c.get());
380 return c.release();
381 }
382
383 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
384 template<class T, class A, class... Args>
385 inline typename enable_if_<!is_array<T>::value,
386 std::unique_ptr<T, alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc,Args &&...args)387 allocate_unique(const A& alloc, Args&&... args)
388 {
389 detail::sp_alloc_make<T, A> c(alloc, 1);
390 boost::alloc_construct(c.state(), c.get(), std::forward<Args>(args)...);
391 return c.release();
392 }
393 #endif
394
395 template<class T, class A>
396 inline typename enable_if_<!is_array<T>::value,
397 std::unique_ptr<T, alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc,typename type_identity<T>::type && value)398 allocate_unique(const A& alloc, typename type_identity<T>::type&& value)
399 {
400 detail::sp_alloc_make<T, A> c(alloc, 1);
401 boost::alloc_construct(c.state(), c.get(), std::move(value));
402 return c.release();
403 }
404
405 template<class T, class A>
406 inline typename enable_if_<!is_array<T>::value,
407 std::unique_ptr<T, alloc_deleter<T, noinit_adaptor<A> > > >::type
allocate_unique_noinit(const A & alloc)408 allocate_unique_noinit(const A& alloc)
409 {
410 return boost::allocate_unique<T, noinit_adaptor<A> >(alloc);
411 }
412
413 template<class T, class A>
414 inline typename enable_if_<is_unbounded_array<T>::value,
415 std::unique_ptr<T, alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc,std::size_t size)416 allocate_unique(const A& alloc, std::size_t size)
417 {
418 detail::sp_alloc_make<T, A> c(alloc, size);
419 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
420 size * detail::sp_alloc_size<T>::value);
421 return c.release();
422 }
423
424 template<class T, class A>
425 inline typename enable_if_<is_bounded_array<T>::value,
426 std::unique_ptr<typename detail::sp_alloc_result<T>::type,
427 alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc)428 allocate_unique(const A& alloc)
429 {
430 detail::sp_alloc_make<T, A> c(alloc, extent<T>::value);
431 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
432 detail::sp_alloc_size<T>::value);
433 return c.release();
434 }
435
436 template<class T, class A>
437 inline typename enable_if_<is_unbounded_array<T>::value,
438 std::unique_ptr<T, alloc_deleter<T, noinit_adaptor<A> > > >::type
allocate_unique_noinit(const A & alloc,std::size_t size)439 allocate_unique_noinit(const A& alloc, std::size_t size)
440 {
441 return boost::allocate_unique<T, noinit_adaptor<A> >(alloc, size);
442 }
443
444 template<class T, class A>
445 inline typename enable_if_<is_bounded_array<T>::value,
446 std::unique_ptr<typename detail::sp_alloc_result<T>::type,
447 alloc_deleter<T, noinit_adaptor<A> > > >::type
allocate_unique_noinit(const A & alloc)448 allocate_unique_noinit(const A& alloc)
449 {
450 return boost::allocate_unique<T, noinit_adaptor<A> >(alloc);
451 }
452
453 template<class T, class A>
454 inline typename enable_if_<is_unbounded_array<T>::value,
455 std::unique_ptr<T, alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc,std::size_t size,const typename remove_extent<T>::type & value)456 allocate_unique(const A& alloc, std::size_t size,
457 const typename remove_extent<T>::type& value)
458 {
459 detail::sp_alloc_make<T, A> c(alloc, size);
460 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
461 size * detail::sp_alloc_size<T>::value, boost::first_scalar(&value),
462 detail::sp_alloc_size<typename remove_extent<T>::type>::value);
463 return c.release();
464 }
465
466 template<class T, class A>
467 inline typename enable_if_<is_bounded_array<T>::value,
468 std::unique_ptr<typename detail::sp_alloc_result<T>::type,
469 alloc_deleter<T, A> > >::type
allocate_unique(const A & alloc,const typename remove_extent<T>::type & value)470 allocate_unique(const A& alloc,
471 const typename remove_extent<T>::type& value)
472 {
473 detail::sp_alloc_make<T, A> c(alloc, extent<T>::value);
474 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
475 detail::sp_alloc_size<T>::value, boost::first_scalar(&value),
476 detail::sp_alloc_size<typename remove_extent<T>::type>::value);
477 return c.release();
478 }
479
480 } /* boost */
481
482 #endif
483