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 <memory> |
11 | |
12 | #include <boost/move/utility_core.hpp> |
13 | #include <boost/container/vector.hpp> |
14 | #include <boost/container/deque.hpp> |
15 | #include <boost/container/list.hpp> |
16 | #include <boost/container/slist.hpp> |
17 | #include <boost/container/stable_vector.hpp> |
18 | #include <boost/container/small_vector.hpp> |
19 | #include <boost/container/flat_map.hpp> |
20 | #include <boost/container/flat_set.hpp> |
21 | #include <boost/container/map.hpp> |
22 | #include <boost/container/set.hpp> |
23 | #include <boost/container/detail/mpl.hpp> |
24 | |
25 | #include <boost/container/scoped_allocator.hpp> |
26 | |
27 | template <typename Ty> |
28 | class SimpleAllocator |
29 | { |
30 | public: |
31 | typedef Ty value_type; |
32 | |
33 | explicit SimpleAllocator(int value) |
34 | : m_state(value) |
35 | {} |
36 | |
37 | template <typename T> |
38 | SimpleAllocator(const SimpleAllocator<T> &other) |
39 | : m_state(other.m_state) |
40 | {} |
41 | |
42 | Ty* allocate(std::size_t n) |
43 | { |
44 | return m_allocator.allocate(n); |
45 | } |
46 | |
47 | void deallocate(Ty* p, std::size_t n) |
48 | { |
49 | m_allocator.deallocate(p, n); |
50 | } |
51 | |
52 | int get_value() const |
53 | { return m_state; } |
54 | |
55 | private: |
56 | int m_state; |
57 | std::allocator<Ty> m_allocator; |
58 | |
59 | template <typename T> friend class SimpleAllocator; |
60 | |
61 | friend bool operator == (const SimpleAllocator &a, const SimpleAllocator &b) |
62 | { return a.m_state == b.m_state; } |
63 | |
64 | friend bool operator != (const SimpleAllocator &a, const SimpleAllocator &b) |
65 | { return a.m_state != b.m_state; } |
66 | }; |
67 | |
68 | class alloc_int |
69 | { |
70 | private: // Not copyable |
71 | |
72 | BOOST_COPYABLE_AND_MOVABLE(alloc_int) |
73 | |
74 | public: |
75 | typedef SimpleAllocator<int> allocator_type; |
76 | |
77 | alloc_int(BOOST_RV_REF(alloc_int)other) |
78 | : m_value(other.m_value), m_allocator(boost::move(t&: other.m_allocator)) |
79 | { |
80 | other.m_value = -1; |
81 | } |
82 | |
83 | alloc_int(BOOST_RV_REF(alloc_int)other, const allocator_type &allocator) |
84 | : m_value(other.m_value), m_allocator(allocator) |
85 | { |
86 | other.m_value = -1; |
87 | } |
88 | |
89 | alloc_int(const alloc_int &other) |
90 | : m_value(other.m_value), m_allocator(boost::move(t: other.m_allocator)) |
91 | { |
92 | } |
93 | |
94 | alloc_int(const alloc_int &other, const allocator_type &allocator) |
95 | : m_value(other.m_value), m_allocator(allocator) |
96 | { |
97 | } |
98 | |
99 | alloc_int(int value, const allocator_type &allocator) |
100 | : m_value(value), m_allocator(allocator) |
101 | {} |
102 | |
103 | alloc_int & operator=(BOOST_RV_REF(alloc_int)other) |
104 | { |
105 | m_value = other.m_value; |
106 | other.m_value = -1; |
107 | return *this; |
108 | } |
109 | |
110 | alloc_int & operator=(const alloc_int &other) |
111 | { |
112 | m_value = other.m_value; |
113 | return *this; |
114 | } |
115 | |
116 | int get_allocator_state() const |
117 | { return m_allocator.get_value(); } |
118 | |
119 | int get_value() const |
120 | { return m_value; } |
121 | |
122 | friend bool operator < (const alloc_int &l, const alloc_int &r) |
123 | { return l.m_value < r.m_value; } |
124 | |
125 | friend bool operator == (const alloc_int &l, const alloc_int &r) |
126 | { return l.m_value == r.m_value; } |
127 | |
128 | private: |
129 | int m_value; |
130 | allocator_type m_allocator; |
131 | }; |
132 | |
133 | using namespace ::boost::container; |
134 | |
135 | //general allocator |
136 | typedef scoped_allocator_adaptor<SimpleAllocator<alloc_int> > AllocIntAllocator; |
137 | |
138 | //[multi]map/set |
139 | typedef std::pair<const alloc_int, alloc_int> MapNode; |
140 | typedef scoped_allocator_adaptor<SimpleAllocator<MapNode> > MapAllocator; |
141 | typedef map<alloc_int, alloc_int, std::less<alloc_int>, MapAllocator> Map; |
142 | typedef set<alloc_int, std::less<alloc_int>, AllocIntAllocator> Set; |
143 | typedef multimap<alloc_int, alloc_int, std::less<alloc_int>, MapAllocator> MultiMap; |
144 | typedef multiset<alloc_int, std::less<alloc_int>, AllocIntAllocator> MultiSet; |
145 | |
146 | //[multi]flat_map/set |
147 | typedef std::pair<alloc_int, alloc_int> FlatMapNode; |
148 | typedef scoped_allocator_adaptor<SimpleAllocator<FlatMapNode> > FlatMapAllocator; |
149 | typedef flat_map<alloc_int, alloc_int, std::less<alloc_int>, FlatMapAllocator> FlatMap; |
150 | typedef flat_set<alloc_int, std::less<alloc_int>, AllocIntAllocator> FlatSet; |
151 | typedef flat_multimap<alloc_int, alloc_int, std::less<alloc_int>, FlatMapAllocator> FlatMultiMap; |
152 | typedef flat_multiset<alloc_int, std::less<alloc_int>, AllocIntAllocator> FlatMultiSet; |
153 | |
154 | //vector, deque, list, slist, stable_vector. |
155 | typedef vector<alloc_int, AllocIntAllocator> Vector; |
156 | typedef deque<alloc_int, AllocIntAllocator> Deque; |
157 | typedef list<alloc_int, AllocIntAllocator> List; |
158 | typedef slist<alloc_int, AllocIntAllocator> Slist; |
159 | typedef stable_vector<alloc_int, AllocIntAllocator> StableVector; |
160 | typedef small_vector<alloc_int, 9, AllocIntAllocator> SmallVector; |
161 | |
162 | ///////// |
163 | //is_unique_assoc |
164 | ///////// |
165 | |
166 | template<class T> |
167 | struct is_unique_assoc |
168 | { |
169 | static const bool value = false; |
170 | }; |
171 | |
172 | template<class Key, class T, class Compare, class Allocator> |
173 | struct is_unique_assoc< map<Key, T, Compare, Allocator> > |
174 | { |
175 | static const bool value = true; |
176 | }; |
177 | |
178 | template<class Key, class T, class Compare, class Allocator> |
179 | struct is_unique_assoc< flat_map<Key, T, Compare, Allocator> > |
180 | { |
181 | static const bool value = true; |
182 | }; |
183 | |
184 | template<class Key, class Compare, class Allocator> |
185 | struct is_unique_assoc< set<Key, Compare, Allocator> > |
186 | { |
187 | static const bool value = true; |
188 | }; |
189 | |
190 | template<class Key, class Compare, class Allocator> |
191 | struct is_unique_assoc< flat_set<Key, Compare, Allocator> > |
192 | { |
193 | static const bool value = true; |
194 | }; |
195 | |
196 | |
197 | ///////// |
198 | //is_map |
199 | ///////// |
200 | |
201 | template<class T> |
202 | struct is_map |
203 | { |
204 | static const bool value = false; |
205 | }; |
206 | |
207 | template<class Key, class T, class Compare, class Allocator> |
208 | struct is_map< map<Key, T, Compare, Allocator> > |
209 | { |
210 | static const bool value = true; |
211 | }; |
212 | |
213 | template<class Key, class T, class Compare, class Allocator> |
214 | struct is_map< flat_map<Key, T, Compare, Allocator> > |
215 | { |
216 | static const bool value = true; |
217 | }; |
218 | |
219 | template<class Key, class T, class Compare, class Allocator> |
220 | struct is_map< multimap<Key, T, Compare, Allocator> > |
221 | { |
222 | static const bool value = true; |
223 | }; |
224 | |
225 | template<class Key, class T, class Compare, class Allocator> |
226 | struct is_map< flat_multimap<Key, T, Compare, Allocator> > |
227 | { |
228 | static const bool value = true; |
229 | }; |
230 | |
231 | template<class T> |
232 | struct is_set |
233 | { |
234 | static const bool value = false; |
235 | }; |
236 | |
237 | template<class Key, class Compare, class Allocator> |
238 | struct is_set< set<Key, Compare, Allocator> > |
239 | { |
240 | static const bool value = true; |
241 | }; |
242 | |
243 | template<class Key, class Compare, class Allocator> |
244 | struct is_set< flat_set<Key, Compare, Allocator> > |
245 | { |
246 | static const bool value = true; |
247 | }; |
248 | |
249 | template<class Key, class Compare, class Allocator> |
250 | struct is_set< multiset<Key, Compare, Allocator> > |
251 | { |
252 | static const bool value = true; |
253 | }; |
254 | |
255 | template<class Key, class Compare, class Allocator> |
256 | struct is_set< flat_multiset<Key, Compare, Allocator> > |
257 | { |
258 | static const bool value = true; |
259 | }; |
260 | |
261 | ///////// |
262 | //container_wrapper |
263 | ///////// |
264 | |
265 | //Try to define-allocator_aware requirements |
266 | template< class Container |
267 | , bool Assoc = is_set<Container>::value || is_map<Container>::value |
268 | , bool UniqueAssoc = is_unique_assoc<Container>::value |
269 | , bool Map = is_map<Container>::value |
270 | > |
271 | struct container_wrapper_inserter |
272 | { |
273 | typedef typename Container::const_iterator const_iterator; |
274 | typedef typename Container::iterator iterator; |
275 | |
276 | template<class Arg> |
277 | static iterator emplace(Container &c, const_iterator p, const Arg &arg) |
278 | { return c.emplace(p, arg); } |
279 | }; |
280 | |
281 | template<class Container> //map |
282 | struct container_wrapper_inserter<Container, true, true, true> |
283 | { |
284 | typedef typename Container::const_iterator const_iterator; |
285 | typedef typename Container::iterator iterator; |
286 | |
287 | template<class Arg> |
288 | static iterator emplace(Container &c, const_iterator, const Arg &arg) |
289 | { return c.emplace(arg, arg).first; } |
290 | }; |
291 | |
292 | template<class Container> //set |
293 | struct container_wrapper_inserter<Container, true, true, false> |
294 | { |
295 | typedef typename Container::const_iterator const_iterator; |
296 | typedef typename Container::iterator iterator; |
297 | |
298 | template<class Arg> |
299 | static iterator emplace(Container &c, const_iterator, const Arg &arg) |
300 | { return c.emplace(arg).first; } |
301 | }; |
302 | |
303 | template<class Container> //multimap |
304 | struct container_wrapper_inserter<Container, true, false, true> |
305 | { |
306 | typedef typename Container::const_iterator const_iterator; |
307 | typedef typename Container::iterator iterator; |
308 | |
309 | template<class Arg> |
310 | static iterator emplace(Container &c, const_iterator, const Arg &arg) |
311 | { return c.emplace(arg, arg); } |
312 | }; |
313 | |
314 | //multiset |
315 | template<class Container> //multimap |
316 | struct container_wrapper_inserter<Container, true, false, false> |
317 | { |
318 | typedef typename Container::const_iterator const_iterator; |
319 | typedef typename Container::iterator iterator; |
320 | |
321 | template<class Arg> |
322 | static iterator emplace(Container &c, const_iterator, const Arg &arg) |
323 | { return c.emplace(arg); } |
324 | }; |
325 | |
326 | template< class Container> |
327 | struct container_wrapper |
328 | : public Container |
329 | { |
330 | private: |
331 | BOOST_COPYABLE_AND_MOVABLE(container_wrapper) |
332 | |
333 | public: |
334 | typedef typename Container::allocator_type allocator_type; |
335 | typedef typename Container::const_iterator const_iterator; |
336 | typedef typename Container::iterator iterator; |
337 | |
338 | container_wrapper(const allocator_type &a) |
339 | : Container(a) |
340 | {} |
341 | |
342 | container_wrapper(BOOST_RV_REF(container_wrapper) o, const allocator_type &a) |
343 | : Container(BOOST_MOVE_BASE(Container, o), a) |
344 | {} |
345 | |
346 | container_wrapper(const container_wrapper &o, const allocator_type &a) |
347 | : Container(o, a) |
348 | {} |
349 | |
350 | template<class Arg> |
351 | iterator emplace(const_iterator p, const Arg &arg) |
352 | { return container_wrapper_inserter<Container>::emplace(*this, p, arg); } |
353 | }; |
354 | |
355 | |
356 | bool test_value_and_state_equals(const alloc_int &r, int value, int state) |
357 | { return r.get_value() == value && r.get_allocator_state() == state; } |
358 | |
359 | template<class F, class S> |
360 | bool test_value_and_state_equals(const dtl::pair<F, S> &p, int value, int state) |
361 | { return test_value_and_state_equals(p.first, value, state) && test_alloc_state_equals(p.second, value, state); } |
362 | |
363 | template<class F, class S> |
364 | bool test_value_and_state_equals(const std::pair<F, S> &p, int value, int state) |
365 | { return test_value_and_state_equals(p.first, value, state) && test_value_and_state_equals(p.second, value, state); } |
366 | |
367 | template<class Container> |
368 | bool one_level_allocator_propagation_test() |
369 | { |
370 | typedef container_wrapper<Container> ContainerWrapper; |
371 | typedef typename ContainerWrapper::iterator iterator; |
372 | typedef typename ContainerWrapper::allocator_type allocator_type; |
373 | typedef typename ContainerWrapper::value_type value_type; |
374 | { |
375 | allocator_type al(SimpleAllocator<value_type>(5)); |
376 | ContainerWrapper c(al); |
377 | |
378 | c.clear(); |
379 | iterator it = c.emplace(c.cbegin(), 42); |
380 | |
381 | if(!test_value_and_state_equals(*it, 42, 5)) |
382 | return false; |
383 | } |
384 | { |
385 | allocator_type al(SimpleAllocator<value_type>(4)); |
386 | ContainerWrapper c2(al); |
387 | { |
388 | iterator it = c2.emplace(c2.cbegin(), 41); |
389 | if(!test_value_and_state_equals(*it, 41, 4)) |
390 | return false; |
391 | } |
392 | |
393 | ContainerWrapper c(::boost::move(c2), allocator_type(SimpleAllocator<value_type>(5))); |
394 | |
395 | if(!test_value_and_state_equals(*c.begin(), 41, 5)) |
396 | return false; |
397 | |
398 | { |
399 | c.clear(); |
400 | iterator it = c.emplace(c.cbegin(), 42); |
401 | |
402 | if(!test_value_and_state_equals(*it, 42, 5)) |
403 | return false; |
404 | } |
405 | } |
406 | { |
407 | allocator_type al(SimpleAllocator<value_type>(4)); |
408 | ContainerWrapper c2(al); |
409 | { |
410 | iterator it = c2.emplace(c2.cbegin(), 41); |
411 | if(!test_value_and_state_equals(*it, 41, 4)) |
412 | return false; |
413 | } |
414 | |
415 | ContainerWrapper c(c2, allocator_type(SimpleAllocator<value_type>(5))); |
416 | |
417 | if(!test_value_and_state_equals(*c.begin(), 41, 5)) |
418 | return false; |
419 | |
420 | { |
421 | c.clear(); |
422 | iterator it = c.emplace(c.cbegin(), 42); |
423 | |
424 | if(!test_value_and_state_equals(*it, 42, 5)) |
425 | return false; |
426 | } |
427 | } |
428 | return true; |
429 | } |
430 | |
431 | int main() |
432 | { |
433 | //unique assoc |
434 | if(!one_level_allocator_propagation_test<FlatMap>()) |
435 | return 1; |
436 | if(!one_level_allocator_propagation_test<Map>()) |
437 | return 1; |
438 | if(!one_level_allocator_propagation_test<FlatSet>()) |
439 | return 1; |
440 | if(!one_level_allocator_propagation_test<Set>()) |
441 | return 1; |
442 | //multi assoc |
443 | if(!one_level_allocator_propagation_test<FlatMultiMap>()) |
444 | return 1; |
445 | if(!one_level_allocator_propagation_test<MultiMap>()) |
446 | return 1; |
447 | if(!one_level_allocator_propagation_test<FlatMultiSet>()) |
448 | return 1; |
449 | if(!one_level_allocator_propagation_test<MultiSet>()) |
450 | return 1; |
451 | //sequence containers |
452 | if(!one_level_allocator_propagation_test<Vector>()) |
453 | return 1; |
454 | if(!one_level_allocator_propagation_test<Deque>()) |
455 | return 1; |
456 | if(!one_level_allocator_propagation_test<List>()) |
457 | return 1; |
458 | if(!one_level_allocator_propagation_test<Slist>()) |
459 | return 1; |
460 | if(!one_level_allocator_propagation_test<StableVector>()) |
461 | return 1; |
462 | if(!one_level_allocator_propagation_test<SmallVector>()) |
463 | return 1; |
464 | return 0; |
465 | } |
466 | |