1 /*
2 Copyright 2017-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_LOCAL_SHARED_ARRAY_HPP
9 #define BOOST_SMART_PTR_ALLOCATE_LOCAL_SHARED_ARRAY_HPP
10
11 #include <boost/smart_ptr/allocate_shared_array.hpp>
12 #include <boost/smart_ptr/local_shared_ptr.hpp>
13
14 namespace boost {
15 namespace detail {
16
17 class BOOST_SYMBOL_VISIBLE lsp_array_base
18 : public local_counted_base {
19 public:
set(sp_counted_base * base)20 void set(sp_counted_base* base) BOOST_SP_NOEXCEPT {
21 count_ = shared_count(base);
22 }
23
local_cb_destroy()24 void local_cb_destroy() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
25 shared_count().swap(count_);
26 }
27
local_cb_get_shared_count() const28 shared_count local_cb_get_shared_count() const
29 BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
30 return count_;
31 }
32
33 private:
34 shared_count count_;
35 };
36
37 template<class A>
38 class lsp_array_state
39 : public sp_array_state<A> {
40 public:
41 template<class U>
lsp_array_state(const U & other,std::size_t size)42 lsp_array_state(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
43 : sp_array_state<A>(other, size) { }
44
base()45 lsp_array_base& base() BOOST_SP_NOEXCEPT {
46 return base_;
47 }
48
49 private:
50 lsp_array_base base_;
51 };
52
53 template<class A, std::size_t N>
54 class lsp_size_array_state
55 : public sp_size_array_state<A, N> {
56 public:
57 template<class U>
lsp_size_array_state(const U & other,std::size_t size)58 lsp_size_array_state(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
59 : sp_size_array_state<A, N>(other, size) { }
60
base()61 lsp_array_base& base() BOOST_SP_NOEXCEPT {
62 return base_;
63 }
64
65 private:
66 lsp_array_base base_;
67 };
68
69 } /* detail */
70
71 template<class T, class A>
72 inline typename enable_if_<is_unbounded_array<T>::value,
73 local_shared_ptr<T> >::type
allocate_local_shared(const A & allocator,std::size_t count)74 allocate_local_shared(const A& allocator, std::size_t count)
75 {
76 typedef typename detail::sp_array_element<T>::type element;
77 typedef typename allocator_rebind<A, element>::type other;
78 typedef detail::lsp_array_state<other> state;
79 typedef detail::sp_array_base<state> base;
80 detail::sp_array_result<other, base> result(allocator, count);
81 base* node = result.get();
82 element* start = detail::sp_array_start<element>(node);
83 ::new(static_cast<void*>(node)) base(allocator, start, count);
84 detail::lsp_array_base& local = node->state().base();
85 local.set(node);
86 result.release();
87 return local_shared_ptr<T>(detail::lsp_internal_constructor_tag(), start,
88 &local);
89 }
90
91 template<class T, class A>
92 inline typename enable_if_<is_bounded_array<T>::value,
93 local_shared_ptr<T> >::type
allocate_local_shared(const A & allocator)94 allocate_local_shared(const A& allocator)
95 {
96 enum {
97 count = extent<T>::value
98 };
99 typedef typename detail::sp_array_element<T>::type element;
100 typedef typename allocator_rebind<A, element>::type other;
101 typedef detail::lsp_size_array_state<other, count> state;
102 typedef detail::sp_array_base<state> base;
103 detail::sp_array_result<other, base> result(allocator, count);
104 base* node = result.get();
105 element* start = detail::sp_array_start<element>(node);
106 ::new(static_cast<void*>(node)) base(allocator, start, count);
107 detail::lsp_array_base& local = node->state().base();
108 local.set(node);
109 result.release();
110 return local_shared_ptr<T>(detail::lsp_internal_constructor_tag(), start,
111 &local);
112 }
113
114 template<class T, class A>
115 inline typename enable_if_<is_unbounded_array<T>::value,
116 local_shared_ptr<T> >::type
allocate_local_shared(const A & allocator,std::size_t count,const typename remove_extent<T>::type & value)117 allocate_local_shared(const A& allocator, std::size_t count,
118 const typename remove_extent<T>::type& value)
119 {
120 typedef typename detail::sp_array_element<T>::type element;
121 typedef typename allocator_rebind<A, element>::type other;
122 typedef detail::lsp_array_state<other> state;
123 typedef detail::sp_array_base<state> base;
124 detail::sp_array_result<other, base> result(allocator, count);
125 base* node = result.get();
126 element* start = detail::sp_array_start<element>(node);
127 ::new(static_cast<void*>(node)) base(allocator, start, count, value);
128 detail::lsp_array_base& local = node->state().base();
129 local.set(node);
130 result.release();
131 return local_shared_ptr<T>(detail::lsp_internal_constructor_tag(), start,
132 &local);
133 }
134
135 template<class T, class A>
136 inline typename enable_if_<is_bounded_array<T>::value,
137 local_shared_ptr<T> >::type
allocate_local_shared(const A & allocator,const typename remove_extent<T>::type & value)138 allocate_local_shared(const A& allocator,
139 const typename remove_extent<T>::type& value)
140 {
141 enum {
142 count = extent<T>::value
143 };
144 typedef typename detail::sp_array_element<T>::type element;
145 typedef typename allocator_rebind<A, element>::type other;
146 typedef detail::lsp_size_array_state<other, count> state;
147 typedef detail::sp_array_base<state> base;
148 detail::sp_array_result<other, base> result(allocator, count);
149 base* node = result.get();
150 element* start = detail::sp_array_start<element>(node);
151 ::new(static_cast<void*>(node)) base(allocator, start, count, value);
152 detail::lsp_array_base& local = node->state().base();
153 local.set(node);
154 result.release();
155 return local_shared_ptr<T>(detail::lsp_internal_constructor_tag(), start,
156 &local);
157 }
158
159 template<class T, class A>
160 inline typename enable_if_<is_unbounded_array<T>::value,
161 local_shared_ptr<T> >::type
allocate_local_shared_noinit(const A & allocator,std::size_t count)162 allocate_local_shared_noinit(const A& allocator, std::size_t count)
163 {
164 return boost::allocate_local_shared<T>(boost::noinit_adapt(allocator),
165 count);
166 }
167
168 template<class T, class A>
169 inline typename enable_if_<is_bounded_array<T>::value,
170 local_shared_ptr<T> >::type
allocate_local_shared_noinit(const A & allocator)171 allocate_local_shared_noinit(const A& allocator)
172 {
173 return boost::allocate_local_shared<T>(boost::noinit_adapt(allocator));
174 }
175
176 } /* boost */
177
178 #endif
179