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