1 /* Boost.MultiIndex test for allocator awareness.
2 *
3 * Copyright 2003-2020 Joaquin M Lopez Munoz.
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE_1_0.txt or copy at
6 * http://www.boost.org/LICENSE_1_0.txt)
7 *
8 * See http://www.boost.org/libs/multi_index for library home page.
9 */
10
11 #include "test_alloc_awareness.hpp"
12
13 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
14 #include <boost/detail/lightweight_test.hpp>
15 #include <boost/move/core.hpp>
16 #include <boost/move/utility_core.hpp>
17 #include "pre_multi_index.hpp"
18 #include <boost/multi_index_container.hpp>
19 #include <boost/multi_index/hashed_index.hpp>
20 #include <boost/multi_index/member.hpp>
21 #include <boost/multi_index/ordered_index.hpp>
22 #include <boost/multi_index/random_access_index.hpp>
23 #include <boost/multi_index/ranked_index.hpp>
24 #include <boost/multi_index/sequenced_index.hpp>
25 #include "rooted_allocator.hpp"
26
27 struct move_tracker
28 {
move_trackermove_tracker29 move_tracker(int n):n(n),move_cted(false){}
move_trackermove_tracker30 move_tracker(const move_tracker& x):n(x.n),move_cted(false){}
move_trackermove_tracker31 move_tracker(BOOST_RV_REF(move_tracker) x):n(x.n),move_cted(true){}
operator =move_tracker32 move_tracker& operator=(BOOST_COPY_ASSIGN_REF(move_tracker) x)
33 {n=x.n;return *this;}
operator =move_tracker34 move_tracker& operator=(BOOST_RV_REF(move_tracker) x){n=x.n;return *this;}
35
36 int n;
37 bool move_cted;
38
39 private:
40 BOOST_COPYABLE_AND_MOVABLE(move_tracker)
41 };
42
operator ==(const move_tracker & x,const move_tracker & y)43 inline bool operator==(const move_tracker& x,const move_tracker& y)
44 {
45 return x.n==y.n;
46 }
47
operator <(const move_tracker & x,const move_tracker & y)48 inline bool operator<(const move_tracker& x,const move_tracker& y)
49 {
50 return x.n<y.n;
51 }
52
53 #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
54 namespace boost{
55 #endif
56
hash_value(const move_tracker & x)57 inline std::size_t hash_value(const move_tracker& x)
58 {
59 boost::hash<int> h;
60 return h(x.n);
61 }
62
63 #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
64 } /* namespace boost */
65 #endif
66
67 #if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC)
68 #pragma warning(push)
69 #pragma warning(disable:4127) /* conditional expression is constant */
70 #endif
71
72 template<bool Propagate,bool AlwaysEqual>
test_allocator_awareness_for()73 void test_allocator_awareness_for()
74 {
75 using namespace boost::multi_index;
76
77 typedef rooted_allocator<move_tracker,Propagate,AlwaysEqual> allocator;
78 typedef multi_index_container<
79 move_tracker,
80 indexed_by<
81 hashed_unique<identity<move_tracker> >,
82 ordered_unique<identity<move_tracker> >,
83 random_access<>,
84 ranked_unique<identity<move_tracker> >,
85 sequenced<>
86 >,
87 allocator
88 > container;
89
90 allocator root1(0),root2(0);
91 container c(root1);
92 for(int i=0;i<10;++i)c.emplace(i);
93
94 BOOST_TEST(c.get_allocator().comes_from(root1));
95
96 {
97 container c2(c,root2);
98 BOOST_TEST(c2.get_allocator().comes_from(root2));
99 BOOST_TEST(c2==c);
100 }
101 {
102 container c2(c);
103 const move_tracker* pfirst=&*c2.begin();
104 container c3(boost::move(c2),root2);
105 BOOST_TEST(c3.get_allocator().comes_from(root2));
106 BOOST_TEST(c3==c);
107 BOOST_TEST(c2.empty());
108 BOOST_TEST(AlwaysEqual==(&*c3.begin()==pfirst));
109 BOOST_TEST(!AlwaysEqual==(c3.begin()->move_cted));
110 }
111 {
112 container c2(root2);
113 c2=c;
114 BOOST_TEST(c2.get_allocator().comes_from(Propagate?root1:root2));
115 BOOST_TEST(c2==c);
116 }
117 {
118 const bool element_transfer=Propagate||AlwaysEqual;
119
120 container c2(c);
121 const move_tracker* pfirst=&*c2.begin();
122 container c3(root2);
123 c3=boost::move(c2);
124 BOOST_TEST(c3.get_allocator().comes_from(Propagate?root1:root2));
125 BOOST_TEST(c3==c);
126 BOOST_TEST(c2.empty());
127 BOOST_TEST(element_transfer==(&*c3.begin()==pfirst));
128 BOOST_TEST(!element_transfer==(c3.begin()->move_cted));
129 }
130 if(Propagate||AlwaysEqual){
131 container c2(c);
132 const move_tracker* pfirst=&*c2.begin();
133 container c3(root2);
134 c3.swap(c2);
135 BOOST_TEST(c2.get_allocator().comes_from(Propagate?root2:root1));
136 BOOST_TEST(c3.get_allocator().comes_from(Propagate?root1:root2));
137 BOOST_TEST(c3==c);
138 BOOST_TEST(c2.empty());
139 BOOST_TEST(&*c3.begin()==pfirst);
140 BOOST_TEST(!c3.begin()->move_cted);
141 }
142 }
143
144 #if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC)
145 #pragma warning(pop) /* C4127 */
146 #endif
147
test_allocator_awareness()148 void test_allocator_awareness()
149 {
150 test_allocator_awareness_for<false,false>();
151 test_allocator_awareness_for<false,true>();
152
153 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
154 /* only in C+11 onwards are allocators potentially expected to propagate */
155
156 test_allocator_awareness_for<true,false>();
157 test_allocator_awareness_for<true,true>();
158
159 #endif
160 }
161