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

source code of boost/boost/smart_ptr/detail/array_allocator.hpp