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