1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost |
4 | // Software License, Version 1.0. (See accompanying file |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
6 | // |
7 | // See http://www.boost.org/libs/container for documentation. |
8 | // |
9 | ////////////////////////////////////////////////////////////////////////////// |
10 | #include <cstddef> |
11 | #include <boost/container/allocator_traits.hpp> |
12 | #include <boost/container/detail/type_traits.hpp> |
13 | #include <boost/container/detail/function_detector.hpp> |
14 | #include <boost/move/utility_core.hpp> |
15 | #include <memory> |
16 | #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
17 | #include <boost/move/detail/fwd_macros.hpp> |
18 | #endif |
19 | #include <boost/core/lightweight_test.hpp> |
20 | |
21 | template<class T> |
22 | class SimpleAllocator |
23 | { |
24 | public: |
25 | bool allocate_called_; |
26 | bool deallocate_called_; |
27 | |
28 | typedef boost::container::dtl:: |
29 | true_type is_always_equal; |
30 | |
31 | typedef T value_type; |
32 | |
33 | template <class U> |
34 | SimpleAllocator(SimpleAllocator<U>) |
35 | : allocate_called_(false) |
36 | , deallocate_called_(false) |
37 | {} |
38 | |
39 | SimpleAllocator() |
40 | : allocate_called_(false) |
41 | , deallocate_called_(false) |
42 | {} |
43 | |
44 | T* allocate(std::size_t) |
45 | { allocate_called_ = true; return 0; } |
46 | |
47 | void deallocate(T*, std::size_t) |
48 | { deallocate_called_ = true; } |
49 | |
50 | bool allocate_called() const |
51 | { return allocate_called_; } |
52 | |
53 | bool deallocate_called() const |
54 | { return deallocate_called_; } |
55 | |
56 | friend bool operator==(const SimpleAllocator &, const SimpleAllocator &) |
57 | { return true; } |
58 | |
59 | friend bool operator!=(const SimpleAllocator &, const SimpleAllocator &) |
60 | { return false; } |
61 | }; |
62 | |
63 | template<class T> |
64 | class SimpleSmartPtr |
65 | { |
66 | void unspecified_bool_type_func() const {} |
67 | typedef void (SimpleSmartPtr::*unspecified_bool_type)() const; |
68 | |
69 | public: |
70 | |
71 | typedef T* pointer; |
72 | |
73 | explicit SimpleSmartPtr(pointer p = 0) |
74 | : ptr_(p) |
75 | {} |
76 | |
77 | SimpleSmartPtr(const SimpleSmartPtr &c) |
78 | { this->ptr_ = c.ptr_; } |
79 | |
80 | SimpleSmartPtr & operator=(const SimpleSmartPtr &c) |
81 | { this->ptr_ = c.ptr_; } |
82 | |
83 | operator unspecified_bool_type() const |
84 | { return ptr_? &SimpleSmartPtr::unspecified_bool_type_func : 0; } |
85 | |
86 | private: |
87 | T *ptr_; |
88 | }; |
89 | |
90 | template<class T> |
91 | class ComplexAllocator |
92 | { |
93 | public: |
94 | bool allocate_called_; |
95 | bool deallocate_called_; |
96 | bool allocate_hint_called_; |
97 | bool destroy_called_; |
98 | mutable bool max_size_called_; |
99 | mutable bool select_on_container_copy_construction_called_; |
100 | bool construct_called_; |
101 | mutable bool storage_is_unpropagable_; |
102 | |
103 | typedef T value_type; |
104 | typedef SimpleSmartPtr<T> pointer; |
105 | typedef SimpleSmartPtr<const T> const_pointer; |
106 | typedef typename ::boost::container:: |
107 | dtl::unvoid_ref<T>::type reference; |
108 | typedef typename ::boost::container:: |
109 | dtl::unvoid_ref<const T>::type const_reference; |
110 | typedef SimpleSmartPtr<void> void_pointer; |
111 | typedef SimpleSmartPtr<const void> const_void_pointer; |
112 | typedef signed short difference_type; |
113 | typedef unsigned short size_type; |
114 | typedef boost::container::dtl:: |
115 | true_type propagate_on_container_copy_assignment; |
116 | typedef boost::container::dtl:: |
117 | true_type propagate_on_container_move_assignment; |
118 | typedef boost::container::dtl:: |
119 | true_type propagate_on_container_swap; |
120 | typedef boost::container::dtl:: |
121 | true_type is_partially_propagable; |
122 | |
123 | ComplexAllocator() |
124 | : allocate_called_(false) |
125 | , deallocate_called_(false) |
126 | , allocate_hint_called_(false) |
127 | , destroy_called_(false) |
128 | , max_size_called_(false) |
129 | , select_on_container_copy_construction_called_(false) |
130 | , construct_called_(false) |
131 | {} |
132 | |
133 | pointer allocate(size_type) |
134 | { allocate_called_ = true; return pointer(); } |
135 | |
136 | void deallocate(pointer, size_type) |
137 | { deallocate_called_ = true; } |
138 | |
139 | //optional |
140 | ComplexAllocator select_on_container_copy_construction() const |
141 | { select_on_container_copy_construction_called_ = true; return *this; } |
142 | |
143 | pointer allocate(size_type n, const const_void_pointer &) |
144 | { allocate_hint_called_ = true; return allocate(n); } |
145 | |
146 | template<class U> |
147 | void destroy(U*) |
148 | { destroy_called_ = true; } |
149 | |
150 | size_type max_size() const |
151 | { max_size_called_ = true; return size_type(size_type(0)-1); } |
152 | |
153 | #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
154 | |
155 | #define BOOST_CONTAINER_COMPLEXALLOCATOR_CONSTRUCT_IMPL(N)\ |
156 | \ |
157 | template< class U BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \ |
158 | void construct(U *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ |
159 | { construct_called_ = true; ::new(p) U ( BOOST_MOVE_FWD##N ); }\ |
160 | // |
161 | BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_COMPLEXALLOCATOR_CONSTRUCT_IMPL) |
162 | #undef BOOST_CONTAINER_COMPLEXALLOCATOR_CONSTRUCT_IMPL |
163 | #else |
164 | |
165 | template< class U, class ...Args> |
166 | void construct(U *p, BOOST_FWD_REF(Args) ...args) |
167 | { construct_called_ = true; ::new(p) U( ::boost::forward<Args>(args)...); } |
168 | |
169 | #endif |
170 | |
171 | template<class U> |
172 | void construct(U *p, boost::container::default_init_t) |
173 | { construct_called_ = true; ::new(p)U; } |
174 | |
175 | bool storage_is_unpropagable(pointer p) const |
176 | { storage_is_unpropagable_ = true; return !p; } |
177 | |
178 | //getters |
179 | bool allocate_called() const |
180 | { return allocate_called_; } |
181 | |
182 | bool deallocate_called() const |
183 | { return deallocate_called_; } |
184 | |
185 | bool allocate_hint_called() const |
186 | { return allocate_hint_called_; } |
187 | |
188 | bool destroy_called() const |
189 | { return destroy_called_; } |
190 | |
191 | bool max_size_called() const |
192 | { return max_size_called_; } |
193 | |
194 | bool select_on_container_copy_construction_called() const |
195 | { return select_on_container_copy_construction_called_; } |
196 | |
197 | bool construct_called() const |
198 | { return construct_called_; } |
199 | |
200 | bool storage_is_unpropagable_called() const |
201 | { return storage_is_unpropagable_; } |
202 | }; |
203 | |
204 | class copymovable |
205 | { |
206 | BOOST_COPYABLE_AND_MOVABLE(copymovable) |
207 | |
208 | public: |
209 | |
210 | bool copymoveconstructed_; |
211 | bool moved_; |
212 | |
213 | copymovable(int, int, int) |
214 | : copymoveconstructed_(false), moved_(false) |
215 | {} |
216 | |
217 | copymovable() |
218 | : copymoveconstructed_(false), moved_(false) |
219 | {} |
220 | |
221 | copymovable(const copymovable &) |
222 | : copymoveconstructed_(true), moved_(false) |
223 | {} |
224 | |
225 | copymovable(BOOST_RV_REF(copymovable)) |
226 | : copymoveconstructed_(true), moved_(true) |
227 | {} |
228 | |
229 | copymovable & operator=(BOOST_COPY_ASSIGN_REF(copymovable) ){ return *this; } |
230 | copymovable & operator=(BOOST_RV_REF(copymovable) ){ return *this; } |
231 | |
232 | bool copymoveconstructed() const |
233 | { return copymoveconstructed_; } |
234 | |
235 | bool moved() const |
236 | { return moved_; } |
237 | }; |
238 | |
239 | void test_void_allocator() |
240 | { |
241 | boost::container::allocator_traits<std::allocator<void> > stdtraits; (void)stdtraits; |
242 | boost::container::allocator_traits<SimpleAllocator<void> > simtraits; (void)simtraits; |
243 | boost::container::allocator_traits<ComplexAllocator<void> > comtraits; (void)comtraits; |
244 | } |
245 | |
246 | int main() |
247 | { |
248 | using namespace boost::container::dtl; |
249 | test_void_allocator(); |
250 | |
251 | //SimpleAllocator |
252 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
253 | < SimpleAllocator<int> >::value_type, int>::value )); |
254 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
255 | < SimpleAllocator<int> >::pointer, int*>::value )); |
256 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
257 | < SimpleAllocator<int> >::const_pointer, const int*>::value )); |
258 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
259 | < SimpleAllocator<int> >::void_pointer, void*>::value )); |
260 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
261 | < SimpleAllocator<int> >::const_void_pointer, const void*>::value )); |
262 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
263 | < SimpleAllocator<int> >::difference_type, std::ptrdiff_t>::value )); |
264 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
265 | < SimpleAllocator<int> >::size_type, std::size_t>::value )); |
266 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
267 | < SimpleAllocator<int> >::propagate_on_container_copy_assignment::value == false )); |
268 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
269 | < SimpleAllocator<int> >::propagate_on_container_move_assignment::value == false )); |
270 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
271 | < SimpleAllocator<int> >::propagate_on_container_swap::value == false )); |
272 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
273 | < SimpleAllocator<int> >::is_always_equal::value == true )); |
274 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
275 | < SimpleAllocator<int> >::is_partially_propagable::value == false )); |
276 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
277 | < SimpleAllocator<int> >::rebind_traits<double>::allocator_type |
278 | , SimpleAllocator<double> >::value )); |
279 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
280 | < SimpleAllocator<int> >::rebind_alloc<double>::value_type |
281 | , double >::value )); |
282 | |
283 | //ComplexAllocator |
284 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
285 | < ComplexAllocator<int> >::value_type, int>::value )); |
286 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
287 | < ComplexAllocator<int> >::pointer, SimpleSmartPtr<int> >::value )); |
288 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
289 | < ComplexAllocator<int> >::const_pointer, SimpleSmartPtr<const int> >::value )); |
290 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
291 | < ComplexAllocator<int> >::void_pointer, SimpleSmartPtr<void> >::value )); |
292 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
293 | < ComplexAllocator<int> >::const_void_pointer, SimpleSmartPtr<const void> >::value )); |
294 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
295 | < ComplexAllocator<int> >::difference_type, signed short>::value )); |
296 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
297 | < ComplexAllocator<int> >::size_type, unsigned short>::value )); |
298 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
299 | < ComplexAllocator<int> >::propagate_on_container_copy_assignment::value == true )); |
300 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
301 | < ComplexAllocator<int> >::propagate_on_container_move_assignment::value == true )); |
302 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
303 | < ComplexAllocator<int> >::propagate_on_container_swap::value == true )); |
304 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
305 | < ComplexAllocator<int> >::is_always_equal::value == false )); |
306 | BOOST_CONTAINER_STATIC_ASSERT(( boost::container::allocator_traits |
307 | < ComplexAllocator<int> >::is_partially_propagable::value == true )); |
308 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
309 | < ComplexAllocator<int> >::rebind_traits<double>::allocator_type |
310 | , ComplexAllocator<double> >::value )); |
311 | BOOST_CONTAINER_STATIC_ASSERT(( is_same<boost::container::allocator_traits |
312 | < ComplexAllocator<int> >::rebind_alloc<double>::value_type |
313 | , double >::value )); |
314 | |
315 | typedef ComplexAllocator<int> CAlloc; |
316 | typedef SimpleAllocator<int> SAlloc; |
317 | typedef boost::container::allocator_traits<CAlloc> CAllocTraits; |
318 | typedef boost::container::allocator_traits<SAlloc> SAllocTraits; |
319 | CAlloc c_alloc; |
320 | SAlloc s_alloc; |
321 | |
322 | //allocate |
323 | CAllocTraits::allocate(a&: c_alloc, n: 1); |
324 | BOOST_TEST(c_alloc.allocate_called()); |
325 | |
326 | SAllocTraits::allocate(a&: s_alloc, n: 1); |
327 | BOOST_TEST(s_alloc.allocate_called()); |
328 | |
329 | //deallocate |
330 | CAllocTraits::deallocate(a&: c_alloc, p: CAllocTraits::pointer(), n: 1); |
331 | BOOST_TEST(c_alloc.deallocate_called()); |
332 | |
333 | SAllocTraits::deallocate(a&: s_alloc, p: SAllocTraits::pointer(), n: 1); |
334 | BOOST_TEST(s_alloc.deallocate_called()); |
335 | |
336 | //allocate with hint |
337 | CAllocTraits::allocate(a&: c_alloc, n: 1, p: CAllocTraits::const_void_pointer()); |
338 | BOOST_TEST(c_alloc.allocate_hint_called()); |
339 | |
340 | s_alloc.allocate_called_ = false; |
341 | SAllocTraits::allocate(a&: s_alloc, n: 1, p: SAllocTraits::const_void_pointer()); |
342 | BOOST_TEST(s_alloc.allocate_called()); |
343 | |
344 | //destroy |
345 | float dummy; |
346 | CAllocTraits::destroy(a&: c_alloc, p: &dummy); |
347 | BOOST_TEST(c_alloc.destroy_called()); |
348 | |
349 | SAllocTraits::destroy(a&: s_alloc, p: &dummy); |
350 | |
351 | //max_size |
352 | CAllocTraits::max_size(a: c_alloc); |
353 | BOOST_TEST(c_alloc.max_size_called()); |
354 | |
355 | BOOST_TEST(SAllocTraits::size_type(-1)/sizeof(SAllocTraits::value_type) == SAllocTraits::max_size(s_alloc)); |
356 | |
357 | //select_on_container_copy_construction |
358 | CAllocTraits::select_on_container_copy_construction(a: c_alloc); |
359 | BOOST_TEST(c_alloc.select_on_container_copy_construction_called()); |
360 | |
361 | SAllocTraits::select_on_container_copy_construction(a: s_alloc); |
362 | |
363 | //construct |
364 | { |
365 | copymovable c; |
366 | c.copymoveconstructed_ = true; |
367 | c.copymoveconstructed_ = true; |
368 | CAllocTraits::construct(a&: c_alloc, p: &c); |
369 | BOOST_TEST(c_alloc.construct_called() && !c.copymoveconstructed() && !c.moved()); |
370 | } |
371 | { |
372 | int i = 5; |
373 | CAllocTraits::construct(a&: c_alloc, p: &i, args: boost::container::default_init); |
374 | BOOST_TEST(c_alloc.construct_called() && i == 5); |
375 | } |
376 | { |
377 | copymovable c; |
378 | copymovable c2; |
379 | CAllocTraits::construct(a&: c_alloc, p: &c, args&: c2); |
380 | BOOST_TEST(c_alloc.construct_called() && c.copymoveconstructed() && !c.moved()); |
381 | } |
382 | { |
383 | copymovable c; |
384 | copymovable c2; |
385 | CAllocTraits::construct(a&: c_alloc, p: &c, args: ::boost::move(t&: c2)); |
386 | BOOST_TEST(c_alloc.construct_called() && c.copymoveconstructed() && c.moved()); |
387 | } |
388 | { |
389 | copymovable c; |
390 | c.copymoveconstructed_ = true; |
391 | c.copymoveconstructed_ = true; |
392 | SAllocTraits::construct(a&: s_alloc, p: &c); |
393 | BOOST_TEST(!c.copymoveconstructed() && !c.moved()); |
394 | } |
395 | { |
396 | int i = 4; |
397 | SAllocTraits::construct(a&: s_alloc, p: &i, args: boost::container::default_init); |
398 | BOOST_TEST(i == 4); |
399 | } |
400 | { |
401 | copymovable c; |
402 | copymovable c2; |
403 | SAllocTraits::construct(a&: s_alloc, p: &c, args&: c2); |
404 | BOOST_TEST(c.copymoveconstructed() && !c.moved()); |
405 | } |
406 | { |
407 | copymovable c; |
408 | copymovable c2; |
409 | SAllocTraits::construct(a&: s_alloc, p: &c, args: ::boost::move(t&: c2)); |
410 | BOOST_TEST(c.copymoveconstructed() && c.moved()); |
411 | } |
412 | { |
413 | copymovable c; |
414 | CAllocTraits::construct(a&: c_alloc, p: &c, args: 0, args: 1, args: 2); |
415 | BOOST_TEST(c_alloc.construct_called() && !c.copymoveconstructed() && !c.moved()); |
416 | } |
417 | { |
418 | copymovable c; |
419 | copymovable c2; |
420 | SAllocTraits::construct(a&: s_alloc, p: &c, args: 0, args: 1, args: 2); |
421 | BOOST_TEST(!c.copymoveconstructed() && !c.moved()); |
422 | } |
423 | //storage_is_unpropagable |
424 | { |
425 | SAlloc s_alloc2; |
426 | BOOST_TEST(!SAllocTraits::storage_is_unpropagable(s_alloc, SAllocTraits::pointer())); |
427 | } |
428 | { |
429 | { |
430 | CAlloc c_alloc2; |
431 | CAlloc::value_type v; |
432 | BOOST_TEST(!CAllocTraits::storage_is_unpropagable(c_alloc, CAllocTraits::pointer(&v))); |
433 | BOOST_TEST(c_alloc.storage_is_unpropagable_called()); |
434 | } |
435 | { |
436 | CAlloc c_alloc2; |
437 | BOOST_TEST( CAllocTraits::storage_is_unpropagable(c_alloc2, CAllocTraits::pointer())); |
438 | BOOST_TEST(c_alloc2.storage_is_unpropagable_called()); |
439 | } |
440 | |
441 | } |
442 | |
443 | return ::boost::report_errors(); |
444 | } |
445 | |