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 | { |
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 | |
39 | private: |
40 | BOOST_COPYABLE_AND_MOVABLE(move_tracker) |
41 | }; |
42 | |
43 | inline bool operator==(const move_tracker& x,const move_tracker& y) |
44 | { |
45 | return x.n==y.n; |
46 | } |
47 | |
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 | |
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> |
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 | |
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 | |