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