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
27struct move_tracker
28{
29 move_tracker(int n):n(n),move_cted(false){}
30 move_tracker(const move_tracker& x):n(x.n),move_cted(false){}
31 move_tracker(BOOST_RV_REF(move_tracker) x):n(x.n),move_cted(true){}
32 move_tracker& operator=(BOOST_COPY_ASSIGN_REF(move_tracker) x)
33 {n=x.n;return *this;}
34 move_tracker& operator=(BOOST_RV_REF(move_tracker) x){n=x.n;return *this;}
35
36 int n;
37 bool move_cted;
38
39private:
40 BOOST_COPYABLE_AND_MOVABLE(move_tracker)
41};
42
43inline bool operator==(const move_tracker& x,const move_tracker& y)
44{
45 return x.n==y.n;
46}
47
48inline 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)
54namespace boost{
55#endif
56
57inline 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
72template<bool Propagate,bool AlwaysEqual>
73void 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
148void 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

source code of boost/libs/multi_index/test/test_alloc_awareness.cpp