Chris@102
|
1 /*
|
Chris@102
|
2 * Copyright (c) 2012-2014 Glen Joseph Fernandes
|
Chris@102
|
3 * glenfe at live dot com
|
Chris@102
|
4 *
|
Chris@102
|
5 * Distributed under the Boost Software License,
|
Chris@102
|
6 * Version 1.0. (See accompanying file LICENSE_1_0.txt
|
Chris@102
|
7 * or copy at http://boost.org/LICENSE_1_0.txt)
|
Chris@102
|
8 */
|
Chris@102
|
9 #ifndef BOOST_SMART_PTR_DETAIL_ARRAY_ALLOCATOR_HPP
|
Chris@102
|
10 #define BOOST_SMART_PTR_DETAIL_ARRAY_ALLOCATOR_HPP
|
Chris@102
|
11
|
Chris@102
|
12 #include <boost/align/align.hpp>
|
Chris@102
|
13 #include <boost/smart_ptr/detail/array_traits.hpp>
|
Chris@102
|
14 #include <boost/smart_ptr/detail/array_utility.hpp>
|
Chris@102
|
15 #include <boost/type_traits/alignment_of.hpp>
|
Chris@102
|
16
|
Chris@102
|
17 namespace boost {
|
Chris@102
|
18 namespace detail {
|
Chris@102
|
19 struct ms_init_tag { };
|
Chris@102
|
20 struct ms_noinit_tag { };
|
Chris@102
|
21
|
Chris@102
|
22 template<class T>
|
Chris@102
|
23 struct ms_allocator_state;
|
Chris@102
|
24
|
Chris@102
|
25 template<class T>
|
Chris@102
|
26 struct ms_allocator_state<T[]> {
|
Chris@102
|
27 typedef typename array_base<T>::type type;
|
Chris@102
|
28
|
Chris@102
|
29 ms_allocator_state(std::size_t size_,
|
Chris@102
|
30 type** result_)
|
Chris@102
|
31 : size(size_ * array_total<T>::size),
|
Chris@102
|
32 result(result_) {
|
Chris@102
|
33 }
|
Chris@102
|
34
|
Chris@102
|
35 std::size_t size;
|
Chris@102
|
36
|
Chris@102
|
37 union {
|
Chris@102
|
38 type** result;
|
Chris@102
|
39 type* object;
|
Chris@102
|
40 };
|
Chris@102
|
41 };
|
Chris@102
|
42
|
Chris@102
|
43 template<class T, std::size_t N>
|
Chris@102
|
44 struct ms_allocator_state<T[N]> {
|
Chris@102
|
45 typedef typename array_base<T>::type type;
|
Chris@102
|
46
|
Chris@102
|
47 ms_allocator_state(type** result_)
|
Chris@102
|
48 : result(result_) {
|
Chris@102
|
49 }
|
Chris@102
|
50
|
Chris@102
|
51 enum {
|
Chris@102
|
52 size = array_total<T[N]>::size
|
Chris@102
|
53 };
|
Chris@102
|
54
|
Chris@102
|
55 union {
|
Chris@102
|
56 type** result;
|
Chris@102
|
57 type* object;
|
Chris@102
|
58 };
|
Chris@102
|
59 };
|
Chris@102
|
60
|
Chris@102
|
61 template<class A, class T, class R>
|
Chris@102
|
62 class as_allocator
|
Chris@102
|
63 : public A {
|
Chris@102
|
64 template<class A_, class T_, class R_>
|
Chris@102
|
65 friend class as_allocator;
|
Chris@102
|
66
|
Chris@102
|
67 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
Chris@102
|
68 typedef std::allocator_traits<A> AT;
|
Chris@102
|
69 typedef typename AT::template rebind_alloc<char> CA;
|
Chris@102
|
70 typedef typename AT::template rebind_traits<char> CT;
|
Chris@102
|
71 #else
|
Chris@102
|
72 typedef typename A::template rebind<char>::other CA;
|
Chris@102
|
73 #endif
|
Chris@102
|
74
|
Chris@102
|
75 public:
|
Chris@102
|
76 typedef A allocator_type;
|
Chris@102
|
77
|
Chris@102
|
78 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
Chris@102
|
79 typedef typename AT::value_type value_type;
|
Chris@102
|
80 typedef typename AT::pointer pointer;
|
Chris@102
|
81 typedef typename AT::const_pointer const_pointer;
|
Chris@102
|
82 typedef typename AT::void_pointer void_pointer;
|
Chris@102
|
83 typedef typename AT::const_void_pointer const_void_pointer;
|
Chris@102
|
84 typedef typename AT::size_type size_type;
|
Chris@102
|
85 typedef typename AT::difference_type difference_type;
|
Chris@102
|
86 #else
|
Chris@102
|
87 typedef typename A::value_type value_type;
|
Chris@102
|
88 typedef typename A::pointer pointer;
|
Chris@102
|
89 typedef typename A::const_pointer const_pointer;
|
Chris@102
|
90 typedef typename A::size_type size_type;
|
Chris@102
|
91 typedef typename A::difference_type difference_type;
|
Chris@102
|
92 typedef typename A::reference reference;
|
Chris@102
|
93 typedef typename A::const_reference const_reference;
|
Chris@102
|
94 typedef void* void_pointer;
|
Chris@102
|
95 typedef const void* const_void_pointer;
|
Chris@102
|
96 #endif
|
Chris@102
|
97
|
Chris@102
|
98 template<class U>
|
Chris@102
|
99 struct rebind {
|
Chris@102
|
100 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
Chris@102
|
101 typedef as_allocator<typename AT::
|
Chris@102
|
102 template rebind_alloc<U>, T, R> other;
|
Chris@102
|
103 #else
|
Chris@102
|
104 typedef as_allocator<typename A::
|
Chris@102
|
105 template rebind<U>::other, T, R> other;
|
Chris@102
|
106 #endif
|
Chris@102
|
107 };
|
Chris@102
|
108
|
Chris@102
|
109 typedef typename array_base<T>::type type;
|
Chris@102
|
110
|
Chris@102
|
111 as_allocator(const A& allocator_, type** result)
|
Chris@102
|
112 : A(allocator_),
|
Chris@102
|
113 data(result) {
|
Chris@102
|
114 }
|
Chris@102
|
115
|
Chris@102
|
116 as_allocator(const A& allocator_, std::size_t size,
|
Chris@102
|
117 type** result)
|
Chris@102
|
118 : A(allocator_),
|
Chris@102
|
119 data(size, result) {
|
Chris@102
|
120 }
|
Chris@102
|
121
|
Chris@102
|
122 template<class U>
|
Chris@102
|
123 as_allocator(const as_allocator<U, T, R>& other)
|
Chris@102
|
124 : A(other.allocator()),
|
Chris@102
|
125 data(other.data) {
|
Chris@102
|
126 }
|
Chris@102
|
127
|
Chris@102
|
128 pointer allocate(size_type count, const_void_pointer = 0) {
|
Chris@102
|
129 enum {
|
Chris@102
|
130 M = boost::alignment_of<type>::value
|
Chris@102
|
131 };
|
Chris@102
|
132 std::size_t n1 = count * sizeof(value_type);
|
Chris@102
|
133 std::size_t n2 = data.size * sizeof(type);
|
Chris@102
|
134 std::size_t n3 = n2 + M;
|
Chris@102
|
135 CA ca(allocator());
|
Chris@102
|
136 void* p1 = ca.allocate(n1 + n3);
|
Chris@102
|
137 void* p2 = static_cast<char*>(p1) + n1;
|
Chris@102
|
138 (void)boost::alignment::align(M, n2, p2, n3);
|
Chris@102
|
139 *data.result = static_cast<type*>(p2);
|
Chris@102
|
140 return static_cast<value_type*>(p1);
|
Chris@102
|
141 }
|
Chris@102
|
142
|
Chris@102
|
143 void deallocate(pointer memory, size_type count) {
|
Chris@102
|
144 enum {
|
Chris@102
|
145 M = boost::alignment_of<type>::value
|
Chris@102
|
146 };
|
Chris@102
|
147 std::size_t n1 = count * sizeof(value_type);
|
Chris@102
|
148 std::size_t n2 = data.size * sizeof(type) + M;
|
Chris@102
|
149 char* p1 = reinterpret_cast<char*>(memory);
|
Chris@102
|
150 CA ca(allocator());
|
Chris@102
|
151 ca.deallocate(p1, n1 + n2);
|
Chris@102
|
152 }
|
Chris@102
|
153
|
Chris@102
|
154 const A& allocator() const {
|
Chris@102
|
155 return static_cast<const A&>(*this);
|
Chris@102
|
156 }
|
Chris@102
|
157
|
Chris@102
|
158 A& allocator() {
|
Chris@102
|
159 return static_cast<A&>(*this);
|
Chris@102
|
160 }
|
Chris@102
|
161
|
Chris@102
|
162 void set(type* memory) {
|
Chris@102
|
163 data.object = memory;
|
Chris@102
|
164 }
|
Chris@102
|
165
|
Chris@102
|
166 void operator()() {
|
Chris@102
|
167 if (data.object) {
|
Chris@102
|
168 R tag;
|
Chris@102
|
169 release(tag);
|
Chris@102
|
170 }
|
Chris@102
|
171 }
|
Chris@102
|
172
|
Chris@102
|
173 private:
|
Chris@102
|
174 void release(ms_init_tag) {
|
Chris@102
|
175 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
Chris@102
|
176 as_destroy(allocator(), data.object, data.size);
|
Chris@102
|
177 #else
|
Chris@102
|
178 ms_destroy(data.object, data.size);
|
Chris@102
|
179 #endif
|
Chris@102
|
180 }
|
Chris@102
|
181
|
Chris@102
|
182 void release(ms_noinit_tag) {
|
Chris@102
|
183 ms_destroy(data.object, data.size);
|
Chris@102
|
184 }
|
Chris@102
|
185
|
Chris@102
|
186 ms_allocator_state<T> data;
|
Chris@102
|
187 };
|
Chris@102
|
188
|
Chris@102
|
189 template<class A1, class A2, class T, class R>
|
Chris@102
|
190 bool operator==(const as_allocator<A1, T, R>& a1,
|
Chris@102
|
191 const as_allocator<A2, T, R>& a2) {
|
Chris@102
|
192 return a1.allocator() == a2.allocator();
|
Chris@102
|
193 }
|
Chris@102
|
194
|
Chris@102
|
195 template<class A1, class A2, class T, class R>
|
Chris@102
|
196 bool operator!=(const as_allocator<A1, T, R>& a1,
|
Chris@102
|
197 const as_allocator<A2, T, R>& a2) {
|
Chris@102
|
198 return a1.allocator() != a2.allocator();
|
Chris@102
|
199 }
|
Chris@102
|
200
|
Chris@102
|
201 template<class T, class Y = char>
|
Chris@102
|
202 class ms_allocator;
|
Chris@102
|
203
|
Chris@102
|
204 template<class T, class Y>
|
Chris@102
|
205 class ms_allocator {
|
Chris@102
|
206 template<class T_, class Y_>
|
Chris@102
|
207 friend class ms_allocator;
|
Chris@102
|
208
|
Chris@102
|
209 public:
|
Chris@102
|
210 typedef typename array_base<T>::type type;
|
Chris@102
|
211
|
Chris@102
|
212 typedef Y value_type;
|
Chris@102
|
213 typedef Y* pointer;
|
Chris@102
|
214 typedef const Y* const_pointer;
|
Chris@102
|
215 typedef std::size_t size_type;
|
Chris@102
|
216 typedef std::ptrdiff_t difference_type;
|
Chris@102
|
217 typedef Y& reference;
|
Chris@102
|
218 typedef const Y& const_reference;
|
Chris@102
|
219
|
Chris@102
|
220 template<class U>
|
Chris@102
|
221 struct rebind {
|
Chris@102
|
222 typedef ms_allocator<T, U> other;
|
Chris@102
|
223 };
|
Chris@102
|
224
|
Chris@102
|
225 ms_allocator(type** result)
|
Chris@102
|
226 : data(result) {
|
Chris@102
|
227 }
|
Chris@102
|
228
|
Chris@102
|
229 ms_allocator(std::size_t size, type** result)
|
Chris@102
|
230 : data(size, result) {
|
Chris@102
|
231 }
|
Chris@102
|
232
|
Chris@102
|
233 template<class U>
|
Chris@102
|
234 ms_allocator(const ms_allocator<T, U>& other)
|
Chris@102
|
235 : data(other.data) {
|
Chris@102
|
236 }
|
Chris@102
|
237
|
Chris@102
|
238 pointer allocate(size_type count, const void* = 0) {
|
Chris@102
|
239 enum {
|
Chris@102
|
240 M = boost::alignment_of<type>::value
|
Chris@102
|
241 };
|
Chris@102
|
242 std::size_t n1 = count * sizeof(Y);
|
Chris@102
|
243 std::size_t n2 = data.size * sizeof(type);
|
Chris@102
|
244 std::size_t n3 = n2 + M;
|
Chris@102
|
245 void* p1 = ::operator new(n1 + n3);
|
Chris@102
|
246 void* p2 = static_cast<char*>(p1) + n1;
|
Chris@102
|
247 (void)boost::alignment::align(M, n2, p2, n3);
|
Chris@102
|
248 *data.result = static_cast<type*>(p2);
|
Chris@102
|
249 return static_cast<Y*>(p1);
|
Chris@102
|
250 }
|
Chris@102
|
251
|
Chris@102
|
252 void deallocate(pointer memory, size_type) {
|
Chris@102
|
253 void* p1 = memory;
|
Chris@102
|
254 ::operator delete(p1);
|
Chris@102
|
255 }
|
Chris@102
|
256
|
Chris@102
|
257 #if defined(BOOST_NO_CXX11_ALLOCATOR)
|
Chris@102
|
258 pointer address(reference value) const {
|
Chris@102
|
259 return &value;
|
Chris@102
|
260 }
|
Chris@102
|
261
|
Chris@102
|
262 const_pointer address(const_reference value) const {
|
Chris@102
|
263 return &value;
|
Chris@102
|
264 }
|
Chris@102
|
265
|
Chris@102
|
266 size_type max_size() const {
|
Chris@102
|
267 enum {
|
Chris@102
|
268 N = static_cast<std::size_t>(-1) / sizeof(Y)
|
Chris@102
|
269 };
|
Chris@102
|
270 return N;
|
Chris@102
|
271 }
|
Chris@102
|
272
|
Chris@102
|
273 void construct(pointer memory, const_reference value) {
|
Chris@102
|
274 void* p1 = memory;
|
Chris@102
|
275 ::new(p1) Y(value);
|
Chris@102
|
276 }
|
Chris@102
|
277
|
Chris@102
|
278 void destroy(pointer memory) {
|
Chris@102
|
279 (void)memory;
|
Chris@102
|
280 memory->~Y();
|
Chris@102
|
281 }
|
Chris@102
|
282 #endif
|
Chris@102
|
283
|
Chris@102
|
284 void set(type* memory) {
|
Chris@102
|
285 data.object = memory;
|
Chris@102
|
286 }
|
Chris@102
|
287
|
Chris@102
|
288 void operator()() {
|
Chris@102
|
289 if (data.object) {
|
Chris@102
|
290 ms_destroy(data.object, data.size);
|
Chris@102
|
291 }
|
Chris@102
|
292 }
|
Chris@102
|
293
|
Chris@102
|
294 private:
|
Chris@102
|
295 ms_allocator_state<T> data;
|
Chris@102
|
296 };
|
Chris@102
|
297
|
Chris@102
|
298 template<class T, class Y1, class Y2>
|
Chris@102
|
299 bool operator==(const ms_allocator<T, Y1>&,
|
Chris@102
|
300 const ms_allocator<T, Y2>&) {
|
Chris@102
|
301 return true;
|
Chris@102
|
302 }
|
Chris@102
|
303
|
Chris@102
|
304 template<class T, class Y1, class Y2>
|
Chris@102
|
305 bool operator!=(const ms_allocator<T, Y1>&,
|
Chris@102
|
306 const ms_allocator<T, Y2>&) {
|
Chris@102
|
307 return false;
|
Chris@102
|
308 }
|
Chris@102
|
309
|
Chris@102
|
310 class ms_in_allocator_tag {
|
Chris@102
|
311 public:
|
Chris@102
|
312 void operator()(const void*) {
|
Chris@102
|
313 }
|
Chris@102
|
314 };
|
Chris@102
|
315 }
|
Chris@102
|
316 }
|
Chris@102
|
317
|
Chris@102
|
318 #endif
|