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/has_trivial_constructor.hpp>
13 #include <boost/type_traits/has_trivial_destructor.hpp>
14 #include <boost/type_traits/alignment_of.hpp>
15 #include <boost/type_traits/type_with_alignment.hpp>
21 struct sp_if_array { };
24 struct sp_if_array<T[]> {
25 typedef boost::shared_ptr<T[]> type;
29 struct sp_if_size_array { };
31 template<class T, std::size_t N>
32 struct sp_if_size_array<T[N]> {
33 typedef boost::shared_ptr<T[N]> type;
37 struct sp_array_element { };
40 struct sp_array_element<T[]> {
44 template<class T, std::size_t N>
45 struct sp_array_element<T[N]> {
50 struct sp_array_scalar {
54 template<class T, std::size_t N>
55 struct sp_array_scalar<T[N]> {
56 typedef typename sp_array_scalar<T>::type type;
59 template<class T, std::size_t N>
60 struct sp_array_scalar<const T[N]> {
61 typedef typename sp_array_scalar<T>::type type;
64 template<class T, std::size_t N>
65 struct sp_array_scalar<volatile T[N]> {
66 typedef typename sp_array_scalar<T>::type type;
69 template<class T, std::size_t N>
70 struct sp_array_scalar<const volatile T[N]> {
71 typedef typename sp_array_scalar<T>::type type;
75 struct sp_array_scalar<T[]> {
76 typedef typename sp_array_scalar<T>::type type;
80 struct sp_array_scalar<const T[]> {
81 typedef typename sp_array_scalar<T>::type type;
85 struct sp_array_scalar<volatile T[]> {
86 typedef typename sp_array_scalar<T>::type type;
90 struct sp_array_scalar<const volatile T[]> {
91 typedef typename sp_array_scalar<T>::type type;
95 struct sp_array_count {
101 template<class T, std::size_t N>
102 struct sp_array_count<T[N]> {
104 value = N * sp_array_count<T>::value
109 struct sp_array_count<T[]> { };
111 template<class D, class T>
114 boost::shared_ptr<T>& value) BOOST_NOEXCEPT_OR_NOTHROW
116 return static_cast<D*>(value._internal_get_untyped_deleter());
119 template<std::size_t N, std::size_t A>
120 struct sp_array_storage {
123 typename boost::type_with_alignment<A>::type other;
127 template<std::size_t N, std::size_t M>
130 value = N < M ? M : N
134 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
135 template<class A, class T>
136 struct sp_bind_allocator {
137 typedef typename std::allocator_traits<A>::template
138 rebind_alloc<T> type;
141 template<class A, class T>
142 struct sp_bind_allocator {
143 typedef typename A::template rebind<T>::other type;
147 template<bool, class = void>
148 struct sp_enable { };
151 struct sp_enable<true, T> {
157 typename sp_enable<boost::has_trivial_destructor<T>::value>::type
158 sp_array_destroy(T*, std::size_t) BOOST_NOEXCEPT { }
162 typename sp_enable<!boost::has_trivial_destructor<T>::value>::type
163 sp_array_destroy(T* storage, std::size_t size)
166 storage[--size].~T();
170 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
171 template<class A, class T>
173 sp_array_destroy(A& allocator, T* storage, std::size_t size)
176 std::allocator_traits<A>::destroy(allocator, &storage[--size]);
181 #if !defined(BOOST_NO_EXCEPTIONS)
184 typename sp_enable<boost::has_trivial_constructor<T>::value ||
185 boost::has_trivial_destructor<T>::value>::type
186 sp_array_construct(T* storage, std::size_t size)
188 for (std::size_t i = 0; i < size; ++i) {
189 ::new(static_cast<void*>(storage + i)) T();
195 typename sp_enable<!boost::has_trivial_constructor<T>::value &&
196 !boost::has_trivial_destructor<T>::value>::type
197 sp_array_construct(T* storage, std::size_t size)
201 for (; i < size; ++i) {
202 ::new(static_cast<void*>(storage + i)) T();
214 sp_array_construct(T* storage, std::size_t size, const T* list,
219 for (; i < size; ++i) {
220 ::new(static_cast<void*>(storage + i)) T(list[i % count]);
232 sp_array_construct(T* storage, std::size_t size)
234 for (std::size_t i = 0; i < size; ++i) {
235 ::new(static_cast<void*>(storage + i)) T();
241 sp_array_construct(T* storage, std::size_t size, const T* list,
244 for (std::size_t i = 0; i < size; ++i) {
245 ::new(static_cast<void*>(storage + i)) T(list[i % count]);
250 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
251 #if !defined(BOOST_NO_EXCEPTIONS)
252 template<class A, class T>
254 sp_array_construct(A& allocator, T* storage, std::size_t size)
258 for (i = 0; i < size; ++i) {
259 std::allocator_traits<A>::construct(allocator, storage + i);
262 sp_array_destroy(allocator, storage, i);
267 template<class A, class T>
269 sp_array_construct(A& allocator, T* storage, std::size_t size,
270 const T* list, std::size_t count)
274 for (i = 0; i < size; ++i) {
275 std::allocator_traits<A>::construct(allocator, storage + i,
279 sp_array_destroy(allocator, storage, i);
284 template<class A, class T>
286 sp_array_construct(A& allocator, T* storage, std::size_t size)
288 for (std::size_t i = 0; i < size; ++i) {
289 std::allocator_traits<A>::construct(allocator, storage + i);
293 template<class A, class T>
295 sp_array_construct(A& allocator, T* storage, std::size_t size,
296 const T* list, std::size_t count)
298 for (std::size_t i = 0; i < size; ++i) {
299 std::allocator_traits<A>::construct(allocator, storage + i,
308 typename sp_enable<boost::has_trivial_constructor<T>::value>::type
309 sp_array_default(T*, std::size_t) BOOST_NOEXCEPT { }
311 #if !defined(BOOST_NO_EXCEPTIONS)
314 typename sp_enable<!boost::has_trivial_constructor<T>::value &&
315 boost::has_trivial_destructor<T>::value>::type
316 sp_array_default(T* storage, std::size_t size)
318 for (std::size_t i = 0; i < size; ++i) {
319 ::new(static_cast<void*>(storage + i)) T;
325 typename sp_enable<!boost::has_trivial_constructor<T>::value &&
326 !boost::has_trivial_destructor<T>::value>::type
327 sp_array_default(T* storage, std::size_t size)
331 for (; i < size; ++i) {
332 ::new(static_cast<void*>(storage + i)) T;
344 typename sp_enable<!boost::has_trivial_constructor<T>::value>::type
345 sp_array_default(T* storage, std::size_t size)
347 for (std::size_t i = 0; i < size; ++i) {
348 ::new(static_cast<void*>(storage + i)) T;
353 template<class T, std::size_t N>
354 struct sp_less_align {
356 value = (boost::alignment_of<T>::value) < N
360 template<class T, std::size_t N>
361 BOOST_CONSTEXPR inline
362 typename sp_enable<sp_less_align<T, N>::value, std::size_t>::type
363 sp_align(std::size_t size) BOOST_NOEXCEPT
365 return (sizeof(T) * size + N - 1) & ~(N - 1);
368 template<class T, std::size_t N>
369 BOOST_CONSTEXPR inline
370 typename sp_enable<!sp_less_align<T, N>::value, std::size_t>::type
371 sp_align(std::size_t size) BOOST_NOEXCEPT
373 return sizeof(T) * size;
377 BOOST_CONSTEXPR inline std::size_t
378 sp_types(std::size_t size) BOOST_NOEXCEPT
380 return (size + sizeof(T) - 1) / sizeof(T);
383 template<class T, std::size_t N>
384 class sp_size_array_deleter {
387 static void operator_fn(U) BOOST_NOEXCEPT { }
389 sp_size_array_deleter() BOOST_NOEXCEPT
390 : enabled_(false) { }
393 sp_size_array_deleter(const A&) BOOST_NOEXCEPT
394 : enabled_(false) { }
396 sp_size_array_deleter(const sp_size_array_deleter&) BOOST_NOEXCEPT
397 : enabled_(false) { }
399 ~sp_size_array_deleter() {
401 sp_array_destroy(reinterpret_cast<T*>(&storage_), N);
408 sp_array_destroy(reinterpret_cast<T*>(&storage_), N);
414 sp_array_construct(reinterpret_cast<T*>(&storage_), N);
419 void* construct(const T* list, std::size_t count) {
420 sp_array_construct(reinterpret_cast<T*>(&storage_), N,
426 void* construct_default() {
427 sp_array_default(reinterpret_cast<T*>(&storage_), N);
434 typename sp_array_storage<sizeof(T) * N,
435 boost::alignment_of<T>::value>::type storage_;
438 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
439 template<class T, std::size_t N, class A>
440 class sp_size_array_destroyer {
443 static void operator_fn(U) BOOST_NOEXCEPT { }
446 sp_size_array_destroyer(const U& allocator) BOOST_NOEXCEPT
447 : allocator_(allocator),
450 sp_size_array_destroyer(const sp_size_array_destroyer& other)
452 : allocator_(other.allocator_),
455 ~sp_size_array_destroyer() {
457 sp_array_destroy(allocator_,
458 reinterpret_cast<T*>(&storage_), N);
465 sp_array_destroy(allocator_,
466 reinterpret_cast<T*>(&storage_), N);
472 sp_array_construct(allocator_,
473 reinterpret_cast<T*>(&storage_), N);
478 void* construct(const T* list, std::size_t count) {
479 sp_array_construct(allocator_,
480 reinterpret_cast<T*>(&storage_), N, list, count);
485 const A& allocator() const BOOST_NOEXCEPT {
490 typename sp_array_storage<sizeof(T) * N,
491 boost::alignment_of<T>::value>::type storage_;
498 class sp_array_deleter {
501 static void operator_fn(U) BOOST_NOEXCEPT { }
503 sp_array_deleter(std::size_t size) BOOST_NOEXCEPT
508 sp_array_deleter(const A& allocator) BOOST_NOEXCEPT
510 size_(allocator.size()) { }
513 sp_array_deleter(const A&, std::size_t size) BOOST_NOEXCEPT
517 sp_array_deleter(const sp_array_deleter& other) BOOST_NOEXCEPT
519 size_(other.size_) { }
521 ~sp_array_deleter() {
523 sp_array_destroy(static_cast<T*>(address_), size_);
530 sp_array_destroy(static_cast<T*>(address_), size_);
535 void construct(T* address) {
536 sp_array_construct(address, size_);
540 void construct(T* address, const T* list, std::size_t count) {
541 sp_array_construct(address, size_, list, count);
545 void construct_default(T* address) {
546 sp_array_default(address, size_);
550 std::size_t size() const BOOST_NOEXCEPT {
559 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
560 template<class T, class A>
561 class sp_array_destroyer {
564 static void operator_fn(U) BOOST_NOEXCEPT { }
567 sp_array_destroyer(const U& allocator, std::size_t size)
569 : allocator_(allocator),
574 sp_array_destroyer(const U& allocator) BOOST_NOEXCEPT
575 : allocator_(allocator.allocator()),
576 size_(allocator.size()),
579 sp_array_destroyer(const sp_array_destroyer& other) BOOST_NOEXCEPT
580 : allocator_(other.allocator_),
584 ~sp_array_destroyer() {
586 sp_array_destroy(allocator_, static_cast<T*>(address_),
594 sp_array_destroy(allocator_, static_cast<T*>(address_),
600 void construct(T* address) {
601 sp_array_construct(allocator_, address, size_);
605 void construct(T* address, const T* list, std::size_t count) {
606 sp_array_construct(allocator_, address, size_, list, count);
610 const A& allocator() const BOOST_NOEXCEPT {
614 std::size_t size() const BOOST_NOEXCEPT {
625 template<class T, class A>
626 class sp_array_allocator {
627 template<class U, class V>
628 friend class sp_array_allocator;
631 typedef typename A::value_type value_type;
635 alignment = sp_max_size<boost::alignment_of<T>::value,
636 boost::alignment_of<value_type>::value>::value
639 typedef typename boost::type_with_alignment<alignment>::type type;
640 typedef typename sp_bind_allocator<A, type>::type type_allocator;
645 typedef sp_array_allocator<T,
646 typename sp_bind_allocator<A, U>::type> other;
649 sp_array_allocator(const A& allocator, std::size_t size,
650 void** result) BOOST_NOEXCEPT
651 : allocator_(allocator),
655 sp_array_allocator(const A& allocator, std::size_t size)
657 : allocator_(allocator),
661 sp_array_allocator(const sp_array_allocator<T, U>& other)
663 : allocator_(other.allocator_),
665 result_(other.result_) { }
667 value_type* allocate(std::size_t count) {
668 type_allocator allocator(allocator_);
669 std::size_t node = sp_align<value_type, alignment>(count);
670 std::size_t size = sp_types<type>(node + sizeof(T) * size_);
671 type* address = allocator.allocate(size);
672 *result_ = reinterpret_cast<char*>(address) + node;
673 return reinterpret_cast<value_type*>(address);
676 void deallocate(value_type* value, std::size_t count) {
677 type_allocator allocator(allocator_);
678 std::size_t node = sp_align<value_type, alignment>(count);
679 std::size_t size = sp_types<type>(node + sizeof(T) * size_);
680 allocator.deallocate(reinterpret_cast<type*>(value), size);
683 const A& allocator() const BOOST_NOEXCEPT {
687 std::size_t size() const BOOST_NOEXCEPT {
697 template<class T, class U, class V>
699 operator==(const sp_array_allocator<T, U>& first,
700 const sp_array_allocator<T, V>& second) BOOST_NOEXCEPT
702 return first.allocator() == second.allocator() &&
703 first.size() == second.size();
706 template<class T, class U, class V>
708 operator!=(const sp_array_allocator<T, U>& first,
709 const sp_array_allocator<T, V>& second) BOOST_NOEXCEPT
711 return !(first == second);
714 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
715 template<class A, class T, std::size_t N>
716 struct sp_select_size_deleter {
717 typedef sp_size_array_destroyer<T, N,
718 typename sp_bind_allocator<A, T>::type> type;
721 template<class U, class T, std::size_t N>
722 struct sp_select_size_deleter<std::allocator<U>, T, N> {
723 typedef sp_size_array_deleter<T, N> type;
726 template<class A, class T>
727 struct sp_select_deleter {
728 typedef sp_array_destroyer<T,
729 typename sp_bind_allocator<A, T>::type> type;
732 template<class U, class T>
733 struct sp_select_deleter<std::allocator<U>, T> {
734 typedef sp_array_deleter<T> type;
737 template<class, class T, std::size_t N>
738 struct sp_select_size_deleter {
739 typedef sp_size_array_deleter<T, N> type;
742 template<class, class T>
743 struct sp_select_deleter {
744 typedef sp_array_deleter<T> type;
748 template<class P, class T, std::size_t N, class A>
749 class sp_counted_impl_pda<P, sp_size_array_deleter<T, N>, A>
750 : public sp_counted_base {
752 typedef sp_size_array_deleter<T, N> deleter_type;
755 typedef sp_counted_impl_pda<P, deleter_type, A> type;
756 typedef typename sp_bind_allocator<A, type>::type deallocator;
759 sp_counted_impl_pda(P, const deleter_type&, const A& allocator)
760 : deleter_(allocator),
761 allocator_(allocator) { }
763 sp_counted_impl_pda(P, const A& allocator)
764 : deleter_(allocator) { }
771 deallocator allocator(allocator_);
773 allocator.deallocate(this, 1);
776 void* get_deleter(const sp_typeinfo&) {
777 return &reinterpret_cast<char&>(deleter_);
780 void* get_untyped_deleter() {
781 return &reinterpret_cast<char&>(deleter_);
785 deleter_type deleter_;
789 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
790 template<class P, class T, std::size_t N, class U, class A>
791 class sp_counted_impl_pda<P, sp_size_array_destroyer<T, N, U>, A>
792 : public sp_counted_base {
794 typedef sp_size_array_destroyer<T, N, U> deleter_type;
797 typedef sp_counted_impl_pda<P, deleter_type, A> type;
798 typedef typename sp_bind_allocator<A, type>::type deallocator;
801 sp_counted_impl_pda(P, const deleter_type&, const A& allocator)
802 : deleter_(allocator) { }
804 sp_counted_impl_pda(P, const A& allocator)
805 : deleter_(allocator) { }
812 deallocator allocator(deleter_.allocator());
814 allocator.deallocate(this, 1);
817 void* get_deleter(const sp_typeinfo&) {
818 return &reinterpret_cast<char&>(deleter_);
821 void* get_untyped_deleter() {
822 return &reinterpret_cast<char&>(deleter_);
826 deleter_type deleter_;
830 template<class P, class T, class A>
831 class sp_counted_impl_pda<P, sp_array_deleter<T>,
832 sp_array_allocator<T, A> >
833 : public sp_counted_base {
835 typedef sp_array_deleter<T> deleter_type;
836 typedef sp_array_allocator<T, A> allocator_type;
839 typedef sp_counted_impl_pda<P, deleter_type, allocator_type> type;
840 typedef sp_array_allocator<T,
841 typename sp_bind_allocator<A, type>::type> deallocator;
844 sp_counted_impl_pda(P, const deleter_type&,
845 const allocator_type& allocator)
846 : deleter_(allocator),
847 allocator_(allocator.allocator()) { }
849 sp_counted_impl_pda(P, const allocator_type& allocator)
850 : deleter_(allocator),
851 allocator_(allocator.allocator()) { }
858 deallocator allocator(allocator_, deleter_.size());
860 allocator.deallocate(this, 1);
863 void* get_deleter(const sp_typeinfo&) {
864 return &reinterpret_cast<char&>(deleter_);
867 void* get_untyped_deleter() {
868 return &reinterpret_cast<char&>(deleter_);
872 deleter_type deleter_;
876 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
877 template<class P, class T, class U, class A>
878 class sp_counted_impl_pda<P, sp_array_destroyer<T, U>,
879 sp_array_allocator<T, A> >
880 : public sp_counted_base {
882 typedef sp_array_destroyer<T, U> deleter_type;
883 typedef sp_array_allocator<T, A> allocator_type;
886 typedef sp_counted_impl_pda<P, deleter_type, allocator_type> type;
887 typedef sp_array_allocator<T,
888 typename sp_bind_allocator<A, type>::type> deallocator;
891 sp_counted_impl_pda(P, const deleter_type&,
892 const allocator_type& allocator)
893 : deleter_(allocator) { }
895 sp_counted_impl_pda(P, const allocator_type& allocator)
896 : deleter_(allocator) { }
903 deallocator allocator(deleter_.allocator(), deleter_.size());
905 allocator.deallocate(this, 1);
908 void* get_deleter(const sp_typeinfo&) {
909 return &reinterpret_cast<char&>(deleter_);
912 void* get_untyped_deleter() {
913 return &reinterpret_cast<char&>(deleter_);
917 deleter_type deleter_;
923 template<class T, class A>
924 inline typename detail::sp_if_size_array<T>::type
925 allocate_shared(const A& allocator)
927 typedef typename detail::sp_array_element<T>::type type;
928 typedef typename detail::sp_array_scalar<T>::type scalar;
929 typedef typename detail::sp_select_size_deleter<A, scalar,
930 detail::sp_array_count<T>::value>::type deleter;
931 shared_ptr<T> result(static_cast<type*>(0),
932 detail::sp_inplace_tag<deleter>(), allocator);
933 deleter* state = detail::sp_get_deleter<deleter>(result);
934 void* start = state->construct();
935 return shared_ptr<T>(result, static_cast<type*>(start));
938 template<class T, class A>
939 inline typename detail::sp_if_size_array<T>::type
940 allocate_shared(const A& allocator,
941 const typename detail::sp_array_element<T>::type& value)
943 typedef typename detail::sp_array_element<T>::type type;
944 typedef typename detail::sp_array_scalar<T>::type scalar;
945 typedef typename detail::sp_select_size_deleter<A, scalar,
946 detail::sp_array_count<T>::value>::type deleter;
947 shared_ptr<T> result(static_cast<type*>(0),
948 detail::sp_inplace_tag<deleter>(), allocator);
949 deleter* state = detail::sp_get_deleter<deleter>(result);
950 void* start = state->construct(reinterpret_cast<const
951 scalar*>(&value), detail::sp_array_count<type>::value);
952 return shared_ptr<T>(result, static_cast<type*>(start));
955 template<class T, class A>
956 inline typename detail::sp_if_size_array<T>::type
957 allocate_shared_noinit(const A& allocator)
959 typedef typename detail::sp_array_element<T>::type type;
960 typedef typename detail::sp_array_scalar<T>::type scalar;
961 typedef detail::sp_size_array_deleter<scalar,
962 detail::sp_array_count<T>::value> deleter;
963 shared_ptr<T> result(static_cast<type*>(0),
964 detail::sp_inplace_tag<deleter>(), allocator);
965 deleter* state = detail::sp_get_deleter<deleter>(result);
966 void* start = state->construct_default();
967 return shared_ptr<T>(result, static_cast<type*>(start));
970 template<class T, class A>
971 inline typename detail::sp_if_array<T>::type
972 allocate_shared(const A& allocator, std::size_t count)
974 typedef typename detail::sp_array_element<T>::type type;
975 typedef typename detail::sp_array_scalar<T>::type scalar;
976 typedef typename detail::sp_select_deleter<A, scalar>::type deleter;
977 std::size_t size = count * detail::sp_array_count<type>::value;
979 shared_ptr<T> result(static_cast<type*>(0),
980 detail::sp_inplace_tag<deleter>(),
981 detail::sp_array_allocator<scalar, A>(allocator, size, &start));
982 deleter* state = detail::sp_get_deleter<deleter>(result);
983 state->construct(static_cast<scalar*>(start));
984 return shared_ptr<T>(result, static_cast<type*>(start));
987 template<class T, class A>
988 inline typename detail::sp_if_array<T>::type
989 allocate_shared(const A& allocator, std::size_t count,
990 const typename detail::sp_array_element<T>::type& value)
992 typedef typename detail::sp_array_element<T>::type type;
993 typedef typename detail::sp_array_scalar<T>::type scalar;
994 typedef typename detail::sp_select_deleter<A, scalar>::type deleter;
995 std::size_t size = count * detail::sp_array_count<type>::value;
997 shared_ptr<T> result(static_cast<type*>(0),
998 detail::sp_inplace_tag<deleter>(),
999 detail::sp_array_allocator<scalar, A>(allocator, size, &start));
1000 deleter* state = detail::sp_get_deleter<deleter>(result);
1001 state->construct(static_cast<scalar*>(start),
1002 reinterpret_cast<const scalar*>(&value),
1003 detail::sp_array_count<type>::value);
1004 return shared_ptr<T>(result, static_cast<type*>(start));
1007 template<class T, class A>
1008 inline typename detail::sp_if_array<T>::type
1009 allocate_shared_noinit(const A& allocator, std::size_t count)
1011 typedef typename detail::sp_array_element<T>::type type;
1012 typedef typename detail::sp_array_scalar<T>::type scalar;
1013 typedef detail::sp_array_deleter<scalar> deleter;
1014 std::size_t size = count * detail::sp_array_count<type>::value;
1016 shared_ptr<T> result(static_cast<type*>(0),
1017 detail::sp_inplace_tag<deleter>(),
1018 detail::sp_array_allocator<scalar, A>(allocator, size, &start));
1019 deleter* state = detail::sp_get_deleter<deleter>(result);
1020 state->construct_default(static_cast<scalar*>(start));
1021 return shared_ptr<T>(result, static_cast<type*>(start));