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