2 Copyright 2012-2017 Glen Joseph Fernandes
5 Distributed under the Boost Software License, Version 1.0.
6 (http://www.boost.org/LICENSE_1_0.txt)
8 #ifndef BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
9 #define BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
11 #include <boost/smart_ptr/shared_ptr.hpp>
12 #include <boost/type_traits/alignment_of.hpp>
13 #include <boost/type_traits/has_trivial_assign.hpp>
14 #include <boost/type_traits/has_trivial_constructor.hpp>
15 #include <boost/type_traits/has_trivial_destructor.hpp>
16 #include <boost/type_traits/type_with_alignment.hpp>
22 struct sp_if_array { };
25 struct sp_if_array<T[]> {
26 typedef boost::shared_ptr<T[]> type;
30 struct sp_if_size_array { };
32 template<class T, std::size_t N>
33 struct sp_if_size_array<T[N]> {
34 typedef boost::shared_ptr<T[N]> type;
38 struct sp_array_element { };
41 struct sp_array_element<T[]> {
45 template<class T, std::size_t N>
46 struct sp_array_element<T[N]> {
51 struct sp_array_scalar {
55 template<class T, std::size_t N>
56 struct sp_array_scalar<T[N]> {
57 typedef typename sp_array_scalar<T>::type type;
60 template<class T, std::size_t N>
61 struct sp_array_scalar<const T[N]> {
62 typedef typename sp_array_scalar<T>::type type;
65 template<class T, std::size_t N>
66 struct sp_array_scalar<volatile T[N]> {
67 typedef typename sp_array_scalar<T>::type type;
70 template<class T, std::size_t N>
71 struct sp_array_scalar<const volatile T[N]> {
72 typedef typename sp_array_scalar<T>::type type;
76 struct sp_array_scalar<T[]> {
77 typedef typename sp_array_scalar<T>::type type;
81 struct sp_array_scalar<const T[]> {
82 typedef typename sp_array_scalar<T>::type type;
86 struct sp_array_scalar<volatile T[]> {
87 typedef typename sp_array_scalar<T>::type type;
91 struct sp_array_scalar<const volatile T[]> {
92 typedef typename sp_array_scalar<T>::type type;
96 struct sp_array_count {
102 template<class T, std::size_t N>
103 struct sp_array_count<T[N]> {
105 value = N * sp_array_count<T>::value
109 template<std::size_t N, std::size_t M>
112 value = N < M ? M : N
116 template<std::size_t N, std::size_t M>
119 value = (N + M - 1) & ~(M - 1)
123 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
124 template<class A, class T>
125 struct sp_bind_allocator {
126 typedef typename std::allocator_traits<A>::template rebind_alloc<T> type;
129 template<class A, class T>
130 struct sp_bind_allocator {
131 typedef typename A::template rebind<T>::other type;
136 BOOST_CONSTEXPR inline std::size_t
137 sp_objects(std::size_t size) BOOST_SP_NOEXCEPT
139 return (size + sizeof(T) - 1) / sizeof(T);
142 template<bool, class = void>
143 struct sp_enable { };
146 struct sp_enable<true, T> {
150 template<bool E, class A, class T>
151 inline typename sp_enable<!E && boost::has_trivial_destructor<T>::value>::type
152 sp_array_destroy(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
154 template<bool E, class A, class T>
155 inline typename sp_enable<!E &&
156 !boost::has_trivial_destructor<T>::value>::type
157 sp_array_destroy(A&, T* start, std::size_t size)
164 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
165 template<bool E, class A, class T>
166 inline typename sp_enable<E>::type
167 sp_array_destroy(A& allocator, T* start, std::size_t size)
170 std::allocator_traits<A>::destroy(allocator, start + --size);
175 template<bool E, class A, class T>
176 inline typename sp_enable<!E &&
177 boost::has_trivial_constructor<T>::value &&
178 boost::has_trivial_assign<T>::value &&
179 boost::has_trivial_destructor<T>::value>::type
180 sp_array_construct(A&, T* start, std::size_t size)
182 for (std::size_t i = 0; i < size; ++i) {
187 template<bool E, class A, class T>
188 inline typename sp_enable<!E &&
189 boost::has_trivial_constructor<T>::value &&
190 boost::has_trivial_assign<T>::value &&
191 boost::has_trivial_destructor<T>::value>::type
192 sp_array_construct(A&, T* start, std::size_t size, const T* list,
195 for (std::size_t i = 0; i < size; ++i) {
196 start[i] = list[i % count];
200 #if !defined(BOOST_NO_EXCEPTIONS)
201 template<bool E, class A, class T>
202 inline typename sp_enable<!E &&
203 !(boost::has_trivial_constructor<T>::value &&
204 boost::has_trivial_assign<T>::value &&
205 boost::has_trivial_destructor<T>::value)>::type
206 sp_array_construct(A& none, T* start, std::size_t size)
210 for (; i < size; ++i) {
211 ::new(static_cast<void*>(start + i)) T();
214 sp_array_destroy<E>(none, start, i);
219 template<bool E, class A, class T>
220 inline typename sp_enable<!E &&
221 !(boost::has_trivial_constructor<T>::value &&
222 boost::has_trivial_assign<T>::value &&
223 boost::has_trivial_destructor<T>::value)>::type
224 sp_array_construct(A& none, T* start, std::size_t size, const T* list,
229 for (; i < size; ++i) {
230 ::new(static_cast<void*>(start + i)) T(list[i % count]);
233 sp_array_destroy<E>(none, start, i);
238 template<bool E, class A, class T>
239 inline typename sp_enable<!E &&
240 !(boost::has_trivial_constructor<T>::value &&
241 boost::has_trivial_assign<T>::value &&
242 boost::has_trivial_destructor<T>::value)>::type
243 sp_array_construct(A&, T* start, std::size_t size)
245 for (std::size_t i = 0; i < size; ++i) {
246 ::new(static_cast<void*>(start + i)) T();
250 template<bool E, class A, class T>
251 inline typename sp_enable<!E &&
252 !(boost::has_trivial_constructor<T>::value &&
253 boost::has_trivial_assign<T>::value &&
254 boost::has_trivial_destructor<T>::value)>::type
255 sp_array_construct(A&, T* start, std::size_t size, const T* list,
258 for (std::size_t i = 0; i < size; ++i) {
259 ::new(static_cast<void*>(start + i)) T(list[i % count]);
264 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
265 #if !defined(BOOST_NO_EXCEPTIONS)
266 template<bool E, class A, class T>
267 inline typename sp_enable<E>::type
268 sp_array_construct(A& allocator, T* start, std::size_t size)
272 for (i = 0; i < size; ++i) {
273 std::allocator_traits<A>::construct(allocator, start + i);
276 sp_array_destroy<E>(allocator, start, i);
281 template<bool E, class A, class T>
282 inline typename sp_enable<E>::type
283 sp_array_construct(A& allocator, T* start, std::size_t size, const T* list,
288 for (i = 0; i < size; ++i) {
289 std::allocator_traits<A>::construct(allocator, start + i,
293 sp_array_destroy<E>(allocator, start, i);
298 template<bool E, class A, class T>
299 inline typename sp_enable<E>::type
300 sp_array_construct(A& allocator, T* start, std::size_t size)
302 for (std::size_t i = 0; i < size; ++i) {
303 std::allocator_traits<A>::construct(allocator, start + i);
307 template<bool E, class A, class T>
308 inline typename sp_enable<E>::type
309 sp_array_construct(A& allocator, T* start, std::size_t size, const T* list,
312 for (std::size_t i = 0; i < size; ++i) {
313 std::allocator_traits<A>::construct(allocator, start + i,
320 template<class A, class T>
321 inline typename sp_enable<boost::has_trivial_constructor<T>::value>::type
322 sp_array_default(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
324 #if !defined(BOOST_NO_EXCEPTIONS)
325 template<class A, class T>
326 inline typename sp_enable<!boost::has_trivial_constructor<T>::value>::type
327 sp_array_default(A& none, T* start, std::size_t size)
331 for (; i < size; ++i) {
332 ::new(static_cast<void*>(start + i)) T;
335 sp_array_destroy<false>(none, start, i);
340 template<bool E, class A, class T>
341 inline typename sp_enable<!boost::has_trivial_constructor<T>::value>::type
342 sp_array_default(A&, T* start, std::size_t size)
344 for (std::size_t i = 0; i < size; ++i) {
345 ::new(static_cast<void*>(start + i)) T;
351 class sp_array_state {
356 sp_array_state(const U& allocator, std::size_t size) BOOST_SP_NOEXCEPT
357 : allocator_(allocator),
360 A& allocator() BOOST_SP_NOEXCEPT {
364 std::size_t size() const BOOST_SP_NOEXCEPT {
373 template<class A, std::size_t N>
374 class sp_size_array_state {
379 sp_size_array_state(const U& allocator, std::size_t) BOOST_SP_NOEXCEPT
380 : allocator_(allocator) { }
382 A& allocator() BOOST_SP_NOEXCEPT {
386 BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT {
394 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
396 struct sp_use_construct {
403 struct sp_use_construct<std::allocator<T> > {
410 struct sp_use_construct {
417 template<class T, class U>
418 struct sp_array_alignment {
420 value = sp_max_size<boost::alignment_of<T>::value,
421 boost::alignment_of<U>::value>::value
425 template<class T, class U>
426 struct sp_array_offset {
428 value = sp_align_up<sizeof(T), sp_array_alignment<T, U>::value>::value
432 template<class T, class U>
433 struct sp_array_storage {
435 value = sp_array_alignment<T, U>::value
437 typedef typename boost::type_with_alignment<value>::type type;
440 template<class T, class U>
442 sp_array_start(void* base) BOOST_SP_NOEXCEPT
445 size = sp_array_offset<T, U>::value
447 return reinterpret_cast<U*>(static_cast<char*>(base) + size);
450 template<class A, class T>
451 class sp_array_creator {
452 typedef typename A::value_type scalar;
455 offset = sp_array_offset<T, scalar>::value
458 typedef typename sp_array_storage<T, scalar>::type type;
462 sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
464 size_(sp_objects<type>(offset + sizeof(scalar) * size)) { }
467 return reinterpret_cast<T*>(other_.allocate(size_));
470 void destroy(T* base) {
471 other_.deallocate(reinterpret_cast<type*>(base), size_);
475 typename sp_bind_allocator<A, type>::type other_;
479 struct sp_default { };
481 template<class T, bool E = sp_use_construct<T>::value>
483 : public sp_counted_base {
484 typedef typename T::type allocator;
487 typedef typename allocator::value_type type;
490 sp_array_base(const A& other, std::size_t size, type* start)
491 : state_(other, size) {
492 sp_array_construct<E>(state_.allocator(), start, state_.size());
496 sp_array_base(const A& other, std::size_t size, const type* list,
497 std::size_t count, type* start)
498 : state_(other, size) {
499 sp_array_construct<E>(state_.allocator(), start, state_.size(), list,
504 sp_array_base(sp_default, const A& other, std::size_t size, type* start)
505 : state_(other, size) {
506 sp_array_default(state_.allocator(), start, state_.size());
509 T& state() BOOST_SP_NOEXCEPT {
513 virtual void dispose() {
514 sp_array_destroy<E>(state_.allocator(),
515 sp_array_start<sp_array_base, type>(this), state_.size());
518 virtual void destroy() {
519 sp_array_creator<allocator, sp_array_base> other(state_.allocator(),
521 this->~sp_array_base();
525 virtual void* get_deleter(const sp_typeinfo&) {
529 virtual void* get_local_deleter(const sp_typeinfo&) {
533 virtual void* get_untyped_deleter() {
541 template<class A, class T>
542 struct sp_array_result {
545 sp_array_result(const U& other, std::size_t size)
546 : creator_(other, size),
547 result_(creator_.create()) { }
551 creator_.destroy(result_);
564 sp_array_result(const sp_array_result&);
565 sp_array_result& operator=(const sp_array_result&);
567 sp_array_creator<A, T> creator_;
573 template<class T, class A>
574 inline typename detail::sp_if_array<T>::type
575 allocate_shared(const A& allocator, std::size_t count)
577 typedef typename detail::sp_array_element<T>::type type;
578 typedef typename detail::sp_array_scalar<T>::type scalar;
579 typedef typename detail::sp_bind_allocator<A, scalar>::type other;
580 typedef detail::sp_array_state<other> state;
581 typedef detail::sp_array_base<state> base;
582 std::size_t size = count * detail::sp_array_count<type>::value;
583 detail::sp_array_result<other, base> result(allocator, size);
584 detail::sp_counted_base* node = result.get();
585 scalar* start = detail::sp_array_start<base, scalar>(node);
586 ::new(static_cast<void*>(node)) base(allocator, size, start);
588 return shared_ptr<T>(detail::sp_internal_constructor_tag(),
589 reinterpret_cast<type*>(start), detail::shared_count(node));
592 template<class T, class A>
593 inline typename detail::sp_if_size_array<T>::type
594 allocate_shared(const A& allocator)
597 size = detail::sp_array_count<T>::value
599 typedef typename detail::sp_array_element<T>::type type;
600 typedef typename detail::sp_array_scalar<T>::type scalar;
601 typedef typename detail::sp_bind_allocator<A, scalar>::type other;
602 typedef detail::sp_size_array_state<other, size> state;
603 typedef detail::sp_array_base<state> base;
604 detail::sp_array_result<other, base> result(allocator, size);
605 detail::sp_counted_base* node = result.get();
606 scalar* start = detail::sp_array_start<base, scalar>(node);
607 ::new(static_cast<void*>(node)) base(allocator, size, start);
609 return shared_ptr<T>(detail::sp_internal_constructor_tag(),
610 reinterpret_cast<type*>(start), detail::shared_count(node));
613 template<class T, class A>
614 inline typename detail::sp_if_array<T>::type
615 allocate_shared(const A& allocator, std::size_t count,
616 const typename detail::sp_array_element<T>::type& value)
618 typedef typename detail::sp_array_element<T>::type type;
619 typedef typename detail::sp_array_scalar<T>::type scalar;
620 typedef typename detail::sp_bind_allocator<A, scalar>::type other;
621 typedef detail::sp_array_state<other> state;
622 typedef detail::sp_array_base<state> base;
623 std::size_t size = count * detail::sp_array_count<type>::value;
624 detail::sp_array_result<other, base> result(allocator, size);
625 detail::sp_counted_base* node = result.get();
626 scalar* start = detail::sp_array_start<base, scalar>(node);
627 ::new(static_cast<void*>(node)) base(allocator, size,
628 reinterpret_cast<const scalar*>(&value),
629 detail::sp_array_count<type>::value, start);
631 return shared_ptr<T>(detail::sp_internal_constructor_tag(),
632 reinterpret_cast<type*>(start), detail::shared_count(node));
635 template<class T, class A>
636 inline typename detail::sp_if_size_array<T>::type
637 allocate_shared(const A& allocator,
638 const typename detail::sp_array_element<T>::type& value)
641 size = detail::sp_array_count<T>::value
643 typedef typename detail::sp_array_element<T>::type type;
644 typedef typename detail::sp_array_scalar<T>::type scalar;
645 typedef typename detail::sp_bind_allocator<A, scalar>::type other;
646 typedef detail::sp_size_array_state<other, size> state;
647 typedef detail::sp_array_base<state> base;
648 detail::sp_array_result<other, base> result(allocator, size);
649 detail::sp_counted_base* node = result.get();
650 scalar* start = detail::sp_array_start<base, scalar>(node);
651 ::new(static_cast<void*>(node)) base(allocator, size,
652 reinterpret_cast<const scalar*>(&value),
653 detail::sp_array_count<type>::value, start);
655 return shared_ptr<T>(detail::sp_internal_constructor_tag(),
656 reinterpret_cast<type*>(start), detail::shared_count(node));
659 template<class T, class A>
660 inline typename detail::sp_if_array<T>::type
661 allocate_shared_noinit(const A& allocator, std::size_t count)
663 typedef typename detail::sp_array_element<T>::type type;
664 typedef typename detail::sp_array_scalar<T>::type scalar;
665 typedef typename detail::sp_bind_allocator<A, scalar>::type other;
666 typedef detail::sp_array_state<other> state;
667 typedef detail::sp_array_base<state, false> base;
668 std::size_t size = count * detail::sp_array_count<type>::value;
669 detail::sp_array_result<other, base> result(allocator, size);
670 detail::sp_counted_base* node = result.get();
671 scalar* start = detail::sp_array_start<base, scalar>(node);
672 ::new(static_cast<void*>(node)) base(detail::sp_default(), allocator,
675 return shared_ptr<T>(detail::sp_internal_constructor_tag(),
676 reinterpret_cast<type*>(start), detail::shared_count(node));
679 template<class T, class A>
680 inline typename detail::sp_if_size_array<T>::type
681 allocate_shared_noinit(const A& allocator)
684 size = detail::sp_array_count<T>::value
686 typedef typename detail::sp_array_element<T>::type type;
687 typedef typename detail::sp_array_scalar<T>::type scalar;
688 typedef typename detail::sp_bind_allocator<A, scalar>::type other;
689 typedef detail::sp_size_array_state<other, size> state;
690 typedef detail::sp_array_base<state, false> base;
691 detail::sp_array_result<other, base> result(allocator, size);
692 detail::sp_counted_base* node = result.get();
693 scalar* start = detail::sp_array_start<base, scalar>(node);
694 ::new(static_cast<void*>(node)) base(detail::sp_default(), allocator,
697 return shared_ptr<T>(detail::sp_internal_constructor_tag(),
698 reinterpret_cast<type*>(start), detail::shared_count(node));