bd7077340f596c9d480544e28be35489023ba112
[platform/upstream/boost.git] / libs / unordered / test / objects / cxx11_allocator.hpp
1
2 // Copyright 2006-2011 Daniel James.
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #if !defined(BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER)
7 #define BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER
8
9 #include <boost/config.hpp>
10 #include <boost/limits.hpp>
11 #include <cstddef>
12
13 #include "../helpers/fwd.hpp"
14 #include "../helpers/memory.hpp"
15
16 namespace test
17 {
18     struct allocator_false
19     {
20         enum {
21             is_select_on_copy = 0,
22             is_propagate_on_swap = 0,
23             is_propagate_on_assign = 0,
24             is_propagate_on_move = 0,
25             cxx11_construct = 0
26         };
27     };
28
29     struct allocator_flags_all
30     {
31         enum {
32             is_select_on_copy = 1,
33             is_propagate_on_swap = 1,
34             is_propagate_on_assign = 1,
35             is_propagate_on_move = 1,
36             cxx11_construct = 1
37         };
38     };
39     
40     struct select_copy : allocator_false
41     { enum { is_select_on_copy = 1 }; };
42     struct propagate_swap : allocator_false
43     { enum { is_propagate_on_swap = 1 }; };
44     struct propagate_assign : allocator_false
45     { enum { is_propagate_on_assign = 1 }; };
46     struct propagate_move : allocator_false
47     { enum { is_propagate_on_move = 1 }; };
48
49     struct no_select_copy : allocator_flags_all
50     { enum { is_select_on_copy = 0 }; };
51     struct no_propagate_swap : allocator_flags_all
52     { enum { is_propagate_on_swap = 0 }; };
53     struct no_propagate_assign : allocator_flags_all
54     { enum { is_propagate_on_assign = 0 }; };
55     struct no_propagate_move : allocator_flags_all
56     { enum { is_propagate_on_move = 0 }; };
57     
58     template <typename Flag>
59     struct swap_allocator_base
60     {
61         struct propagate_on_container_swap {
62             enum { value = Flag::is_propagate_on_swap }; };
63     };
64
65     template <typename Flag>
66     struct assign_allocator_base
67     {
68         struct propagate_on_container_copy_assignment {
69             enum { value = Flag::is_propagate_on_assign }; };
70     };
71
72     template <typename Flag>
73     struct move_allocator_base
74     {
75         struct propagate_on_container_move_assignment {
76             enum { value = Flag::is_propagate_on_move }; };
77     };
78
79     namespace
80     {
81         // boostinspect:nounnamed
82         bool force_equal_allocator_value = false;
83     }
84
85     struct force_equal_allocator
86     {
87         bool old_value_;
88     
89         explicit force_equal_allocator(bool value)
90             : old_value_(force_equal_allocator_value)
91         { force_equal_allocator_value = value; }
92         
93         ~force_equal_allocator()
94         { force_equal_allocator_value = old_value_; }
95     };
96
97     template <typename T>
98     struct cxx11_allocator_base
99     {
100         int tag_;
101         int selected_;
102
103         typedef std::size_t size_type;
104         typedef std::ptrdiff_t difference_type;
105         typedef T* pointer;
106         typedef T const* const_pointer;
107         typedef T& reference;
108         typedef T const& const_reference;
109         typedef T value_type;
110
111         explicit cxx11_allocator_base(int t)
112             : tag_(t), selected_(0)
113         {
114             detail::tracker.allocator_ref();
115         }
116         
117         template <typename Y> cxx11_allocator_base(
118                 cxx11_allocator_base<Y> const& x)
119             : tag_(x.tag_), selected_(x.selected_)
120         {
121             detail::tracker.allocator_ref();
122         }
123
124         cxx11_allocator_base(cxx11_allocator_base const& x)
125             : tag_(x.tag_), selected_(x.selected_)
126         {
127             detail::tracker.allocator_ref();
128         }
129
130         ~cxx11_allocator_base()
131         {
132             detail::tracker.allocator_unref();
133         }
134
135         pointer address(reference r)
136         {
137             return pointer(&r);
138         }
139
140         const_pointer address(const_reference r)
141         {
142             return const_pointer(&r);
143         }
144
145         pointer allocate(size_type n) {
146             pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
147             detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
148             return ptr;
149         }
150
151         pointer allocate(size_type n, void const* u)
152         {
153             pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
154             detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
155             return ptr;
156         }
157
158         void deallocate(pointer p, size_type n)
159         {
160             // Only checking tags when propagating swap.
161             // Note that tags will be tested
162             // properly in the normal allocator.
163             detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_,
164                  !force_equal_allocator_value);
165             ::operator delete((void*) p);
166         }
167
168         void construct(T* p, T const& t) {
169             detail::tracker.track_construct((void*) p, sizeof(T), tag_);
170             new(p) T(t);
171         }
172
173 #if !defined(BOOST_NO_VARIADIC_TEMPLATES)
174         template<typename... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
175             detail::tracker.track_construct((void*) p, sizeof(T), tag_);
176             new(p) T(boost::forward<Args>(args)...);
177         }
178 #endif
179
180         void destroy(T* p) {
181             detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
182             p->~T();
183         }
184
185         size_type max_size() const {
186             return (std::numeric_limits<size_type>::max)();
187         }
188     };
189
190     template <typename T, typename Flags = propagate_swap,
191         typename Enable = void>
192     struct cxx11_allocator;
193
194     template <typename T, typename Flags>
195     struct cxx11_allocator<
196         T, Flags,
197         typename boost::disable_if_c<Flags::is_select_on_copy>::type
198     > : public cxx11_allocator_base<T>,
199         public swap_allocator_base<Flags>,
200         public assign_allocator_base<Flags>,
201         public move_allocator_base<Flags>,
202         Flags
203     {
204         template <typename U> struct rebind {
205             typedef cxx11_allocator<U, Flags> other;
206         };
207
208         explicit cxx11_allocator(int t = 0)
209             : cxx11_allocator_base<T>(t)
210         {
211         }
212         
213         template <typename Y> cxx11_allocator(
214                 cxx11_allocator<Y, Flags> const& x)
215             : cxx11_allocator_base<T>(x)
216         {
217         }
218
219         cxx11_allocator(cxx11_allocator const& x)
220             : cxx11_allocator_base<T>(x)
221         {
222         }
223
224         // When not propagating swap, allocators are always equal
225         // to avoid undefined behaviour.
226         bool operator==(cxx11_allocator const& x) const
227         {
228             return force_equal_allocator_value || (this->tag_ == x.tag_);
229         }
230
231         bool operator!=(cxx11_allocator const& x) const
232         {
233             return !(*this == x);
234         }
235     };
236
237     template <typename T, typename Flags>
238     struct cxx11_allocator<
239         T, Flags,
240         typename boost::enable_if_c<Flags::is_select_on_copy>::type
241     > : public cxx11_allocator_base<T>,
242         public swap_allocator_base<Flags>,
243         public assign_allocator_base<Flags>,
244         public move_allocator_base<Flags>,
245         Flags
246     {
247         cxx11_allocator select_on_container_copy_construction() const
248         {
249             cxx11_allocator tmp(*this);
250             ++tmp.selected_;
251             return tmp;
252         }
253
254         template <typename U> struct rebind {
255             typedef cxx11_allocator<U, Flags> other;
256         };
257
258         explicit cxx11_allocator(int t = 0)
259             : cxx11_allocator_base<T>(t)
260         {
261         }
262         
263         template <typename Y> cxx11_allocator(
264                 cxx11_allocator<Y, Flags> const& x)
265             : cxx11_allocator_base<T>(x)
266         {
267         }
268
269         cxx11_allocator(cxx11_allocator const& x)
270             : cxx11_allocator_base<T>(x)
271         {
272         }
273
274         // When not propagating swap, allocators are always equal
275         // to avoid undefined behaviour.
276         bool operator==(cxx11_allocator const& x) const
277         {
278             return force_equal_allocator_value || (this->tag_ == x.tag_);
279         }
280
281         bool operator!=(cxx11_allocator const& x) const
282         {
283             return !(*this == x);
284         }
285     };
286
287     template <typename T, typename Flags>
288     bool equivalent_impl(
289             cxx11_allocator<T, Flags> const& x,
290             cxx11_allocator<T, Flags> const& y,
291             test::derived_type)
292     {
293         return x.tag_ == y.tag_;
294     }
295
296     // Function to check how many times an allocator has been selected,
297     // return 0 for other allocators.
298
299     struct convert_from_anything
300     {
301         template <typename T>
302         convert_from_anything(T const&) {}
303     };
304
305     inline int selected_count(convert_from_anything)
306     {
307         return 0;
308     }
309
310     template <typename T, typename Flags>
311     int selected_count(cxx11_allocator<T, Flags> const& x)
312     {
313         return x.selected_;
314     }
315 }
316
317 #endif