1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2015-2015. 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 <boost/container/pmr/resource_adaptor.hpp> |
11 | #include <boost/core/lightweight_test.hpp> |
12 | #include "propagation_test_allocator.hpp" |
13 | #include "derived_from_memory_resource.hpp" |
14 | #include <boost/container/new_allocator.hpp> |
15 | #include <memory> |
16 | |
17 | using namespace boost::container::pmr; |
18 | |
19 | static const std::size_t max_alignment_value = boost::move_detail::alignment_of<boost::move_detail::max_align_t>::value; |
20 | |
21 | void test_default_constructor() |
22 | { |
23 | typedef propagation_test_allocator<char, 0> alloc_t; |
24 | resource_adaptor<alloc_t> ra; |
25 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
26 | } |
27 | |
28 | void test_copy_constructor() |
29 | { |
30 | typedef propagation_test_allocator<char, 0> alloc_t; |
31 | resource_adaptor<alloc_t> ra; |
32 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
33 | resource_adaptor<alloc_t> rb(ra); |
34 | BOOST_TEST(rb.get_allocator().m_default_contructed == false); |
35 | BOOST_TEST(rb.get_allocator().m_move_contructed == false); |
36 | } |
37 | |
38 | void test_move_constructor() |
39 | { |
40 | typedef propagation_test_allocator<char, 0> alloc_t; |
41 | resource_adaptor<alloc_t> ra; |
42 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
43 | resource_adaptor<alloc_t> rb(::boost::move(t&: ra)); |
44 | BOOST_TEST(rb.get_allocator().m_default_contructed == false); |
45 | BOOST_TEST(rb.get_allocator().m_move_contructed == true); |
46 | } |
47 | |
48 | void test_lvalue_alloc_constructor() |
49 | { |
50 | typedef propagation_test_allocator<char, 0> alloc_t; |
51 | alloc_t a; |
52 | resource_adaptor<alloc_t> ra(a); |
53 | BOOST_TEST(ra.get_allocator().m_default_contructed == false); |
54 | BOOST_TEST(ra.get_allocator().m_move_contructed == false); |
55 | } |
56 | |
57 | void test_rvalue_alloc_constructor() |
58 | { |
59 | typedef propagation_test_allocator<char, 0> alloc_t; |
60 | alloc_t a; |
61 | resource_adaptor<alloc_t> ra(::boost::move(t&: a)); |
62 | BOOST_TEST(ra.get_allocator().m_default_contructed == false); |
63 | BOOST_TEST(ra.get_allocator().m_move_contructed == true); |
64 | } |
65 | |
66 | void test_copy_assign() |
67 | { |
68 | typedef propagation_test_allocator<char, 0> alloc_t; |
69 | resource_adaptor<alloc_t> ra; |
70 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
71 | resource_adaptor<alloc_t> rb; |
72 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
73 | rb = ra; |
74 | BOOST_TEST(rb.get_allocator().m_move_contructed == false); |
75 | BOOST_TEST(rb.get_allocator().m_move_assigned == false); |
76 | } |
77 | |
78 | void test_move_assign() |
79 | { |
80 | typedef propagation_test_allocator<char, 0> alloc_t; |
81 | resource_adaptor<alloc_t> ra; |
82 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
83 | resource_adaptor<alloc_t> rb; |
84 | BOOST_TEST(ra.get_allocator().m_default_contructed == true); |
85 | rb = ::boost::move(t&: ra); |
86 | BOOST_TEST(rb.get_allocator().m_move_contructed == false); |
87 | BOOST_TEST(rb.get_allocator().m_move_assigned == true); |
88 | } |
89 | |
90 | struct stateful |
91 | { |
92 | public: |
93 | typedef char value_type; |
94 | |
95 | template<class U> |
96 | struct rebind |
97 | { typedef stateful other; }; |
98 | |
99 | stateful() |
100 | : m_u(0u) |
101 | {} |
102 | |
103 | char *allocate(std::size_t n) |
104 | { allocate_size = n; return allocate_return; } |
105 | |
106 | void deallocate(char *p, std::size_t n) |
107 | { deallocate_p = p; deallocate_size = n; } |
108 | |
109 | friend bool operator==(const stateful &l, const stateful &r) |
110 | { return l.m_u == r.m_u; } |
111 | |
112 | friend bool operator!=(const stateful &l, const stateful &r) |
113 | { return l.m_u != r.m_u; } |
114 | |
115 | public: |
116 | unsigned m_u; |
117 | std::size_t allocate_size; |
118 | char *allocate_return; |
119 | std::size_t deallocate_size; |
120 | char *deallocate_p; |
121 | }; |
122 | |
123 | void test_get_allocator() |
124 | { |
125 | stateful a; |
126 | a.m_u = 999; |
127 | resource_adaptor<stateful> ra(a); |
128 | const resource_adaptor<stateful> & cra = ra; |
129 | BOOST_TEST( ra.get_allocator().m_u == 999); |
130 | BOOST_TEST(cra.get_allocator().m_u == 999); |
131 | } |
132 | |
133 | typedef resource_adaptor<stateful> stateful_resource_adaptor_t; |
134 | |
135 | struct derived_from_resource_adaptor_stateful |
136 | : public stateful_resource_adaptor_t |
137 | { |
138 | public: |
139 | typedef stateful_resource_adaptor_t base_t; |
140 | using base_t::do_allocate; |
141 | using base_t::do_deallocate; |
142 | using base_t::do_is_equal; |
143 | }; |
144 | |
145 | void test_do_allocate_deallocate() |
146 | { |
147 | { |
148 | derived_from_resource_adaptor_stateful dra; |
149 | char dummy = 0; |
150 | dra.get_allocator().allocate_return = &dummy; |
151 | void *allocate_ret = dra.do_allocate(bytes: 998, alignment: 1); |
152 | BOOST_TEST(allocate_ret == &dummy); |
153 | BOOST_TEST(dra.get_allocator().allocate_size == 998); |
154 | } |
155 | { |
156 | derived_from_resource_adaptor_stateful dra; |
157 | char dummy = 0; |
158 | dra.do_deallocate(p: &dummy, bytes: 1234, alignment: 1); |
159 | BOOST_TEST(dra.get_allocator().deallocate_p == &dummy); |
160 | BOOST_TEST(dra.get_allocator().deallocate_size == 1234); |
161 | } |
162 | { |
163 | //Overaligned allocation |
164 | derived_from_resource_adaptor_stateful dra; |
165 | const std::size_t alignment = max_alignment_value*2u; |
166 | const std::size_t bytes = alignment/2; |
167 | char dummy[alignment*2u+sizeof(void*)]; |
168 | dra.get_allocator().allocate_return = dummy; |
169 | |
170 | //First allocate |
171 | void *allocate_ret = dra.do_allocate(bytes, alignment); |
172 | BOOST_TEST( (char*)allocate_ret >= (dummy+sizeof(void*)) && (char*)allocate_ret < (dummy + sizeof(dummy)) ); |
173 | BOOST_TEST( (std::size_t(allocate_ret) & (alignment - 1u)) == 0 ); |
174 | BOOST_TEST( dra.get_allocator().allocate_size >= (alignment/2+sizeof(void*)) ); |
175 | |
176 | //Then allocate |
177 | dra.do_deallocate(p: allocate_ret, bytes, alignment); |
178 | BOOST_TEST(dra.get_allocator().deallocate_p == dummy); |
179 | BOOST_TEST(dra.get_allocator().deallocate_size == dra.get_allocator().allocate_size); |
180 | } |
181 | { |
182 | typedef resource_adaptor< boost::container::new_allocator<int> > new_resource_alloc_t; |
183 | new_resource_alloc_t ra; |
184 | boost::container::pmr::memory_resource &mr = ra; |
185 | |
186 | //new_allocator, low alignment |
187 | mr.deallocate(p: mr.allocate(bytes: 16, alignment: 1), bytes: 16, alignment: 1); |
188 | |
189 | //new_allocator, high alignment |
190 | mr.deallocate(p: mr.allocate(bytes: 16, alignment: max_alignment_value*4u), bytes: 16, alignment: max_alignment_value*4u); |
191 | } |
192 | { |
193 | typedef resource_adaptor<std ::allocator<int> > new_resource_alloc_t; |
194 | new_resource_alloc_t ra; |
195 | boost::container::pmr::memory_resource &mr = ra; |
196 | |
197 | //std::allocator, low alignment |
198 | mr.deallocate(p: mr.allocate(bytes: 16, alignment: 1), bytes: 16, alignment: 1); |
199 | |
200 | //std::allocator, high alignment |
201 | mr.deallocate(p: mr.allocate(bytes: 16, alignment: max_alignment_value*4u), bytes: 16, alignment: max_alignment_value*4u); |
202 | } |
203 | } |
204 | |
205 | void test_do_is_equal() |
206 | { |
207 | derived_from_resource_adaptor_stateful dra; |
208 | derived_from_memory_resource dmr; |
209 | //Different dynamic type must return false |
210 | BOOST_TEST(dra.do_is_equal(dmr) == false); |
211 | |
212 | //Same dynamic type with same state must return true |
213 | derived_from_resource_adaptor_stateful dra2; |
214 | BOOST_TEST(dra.do_is_equal(dra2) == true); |
215 | |
216 | //Same dynamic type with different state must return false |
217 | dra2.get_allocator().m_u = 1234; |
218 | BOOST_TEST(dra.do_is_equal(dra2) == false); |
219 | } |
220 | |
221 | int main() |
222 | { |
223 | test_default_constructor(); |
224 | test_copy_constructor(); |
225 | test_move_constructor(); |
226 | test_lvalue_alloc_constructor(); |
227 | test_rvalue_alloc_constructor(); |
228 | test_copy_assign(); |
229 | test_move_assign(); |
230 | test_get_allocator(); |
231 | test_do_allocate_deallocate(); |
232 | test_do_is_equal(); |
233 | return ::boost::report_errors(); |
234 | } |
235 | |