1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2004-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
11 // the tests trigger deprecation warnings when compiled with msvc in C++17 mode
12 #if defined(_MSVC_LANG) && _MSVC_LANG > 201402
13 // warning STL4009: std::allocator<void> is deprecated in C++17
14 # define _SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING
15 #endif
16
17 #include <memory>
18 #include <iostream>
19
20 #include <boost/container/vector.hpp>
21 #include <boost/container/allocator.hpp>
22
23 #include <boost/move/utility_core.hpp>
24 #include "check_equal_containers.hpp"
25 #include "movable_int.hpp"
26 #include "expand_bwd_test_allocator.hpp"
27 #include "expand_bwd_test_template.hpp"
28 #include "dummy_test_allocator.hpp"
29 #include "propagate_allocator_test.hpp"
30 #include "vector_test.hpp"
31 #include "default_init_test.hpp"
32 #include "../../intrusive/test/iterator_test.hpp"
33
34 using namespace boost::container;
35
test_expand_bwd()36 int test_expand_bwd()
37 {
38 //Now test all back insertion possibilities
39
40 //First raw ints
41 typedef test::expand_bwd_test_allocator<int>
42 int_allocator_type;
43 typedef vector<int, int_allocator_type>
44 int_vector;
45 if(!test::test_all_expand_bwd<int_vector>())
46 return 1;
47
48 //Now user defined copyable int
49 typedef test::expand_bwd_test_allocator<test::copyable_int>
50 copyable_int_allocator_type;
51 typedef vector<test::copyable_int, copyable_int_allocator_type>
52 copyable_int_vector;
53 if(!test::test_all_expand_bwd<copyable_int_vector>())
54 return 1;
55
56 return 0;
57 }
58
59 struct X;
60
61 template<typename T>
62 struct XRef
63 {
XRefXRef64 explicit XRef(T* ptr) : ptr(ptr) {}
operator T*XRef65 operator T*() const { return ptr; }
66 T* ptr;
67 };
68
69 struct X
70 {
operator &X71 XRef<X const> operator&() const { return XRef<X const>(this); }
operator &X72 XRef<X> operator&() { return XRef<X>(this); }
73 };
74
75
test_smart_ref_type()76 bool test_smart_ref_type()
77 {
78 boost::container::vector<X> x(5);
79 return x.empty();
80 }
81
82 class recursive_vector
83 {
84 public:
operator =(const recursive_vector & x)85 recursive_vector & operator=(const recursive_vector &x)
86 { this->vector_ = x.vector_; return *this; }
87
88 int id_;
89 vector<recursive_vector> vector_;
90 vector<recursive_vector>::iterator it_;
91 vector<recursive_vector>::const_iterator cit_;
92 vector<recursive_vector>::reverse_iterator rit_;
93 vector<recursive_vector>::const_reverse_iterator crit_;
94 };
95
recursive_vector_test()96 void recursive_vector_test()//Test for recursive types
97 {
98 vector<recursive_vector> recursive_vector_vector;
99 }
100
101 enum Test
102 {
103 zero, one, two, three, four, five, six
104 };
105
106 template<class VoidAllocator>
107 struct GetAllocatorCont
108 {
109 template<class ValueType>
110 struct apply
111 {
112 typedef vector< ValueType
113 , typename allocator_traits<VoidAllocator>
114 ::template portable_rebind_alloc<ValueType>::type
115 > type;
116 };
117 };
118
119 template<class VoidAllocator>
test_cont_variants()120 int test_cont_variants()
121 {
122 typedef typename GetAllocatorCont<VoidAllocator>::template apply<int>::type MyCont;
123 typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_int>::type MyMoveCont;
124 typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont;
125 typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont;
126
127 if(test::vector_test<MyCont>())
128 return 1;
129 if(test::vector_test<MyMoveCont>())
130 return 1;
131 if(test::vector_test<MyCopyMoveCont>())
132 return 1;
133 if(test::vector_test<MyCopyCont>())
134 return 1;
135
136 return 0;
137 }
138
139 struct boost_container_vector;
140
141 namespace boost { namespace container { namespace test {
142
143 template<>
144 struct alloc_propagate_base<boost_container_vector>
145 {
146 template <class T, class Allocator>
147 struct apply
148 {
149 typedef boost::container::vector<T, Allocator> type;
150 };
151 };
152
153 }}} //namespace boost::container::test
154
155 template<typename T>
156 class check_dealloc_allocator : public std::allocator<T>
157 {
158 public:
159 bool allocate_zero_called_;
160 bool deallocate_called_without_allocate_;
161
check_dealloc_allocator()162 check_dealloc_allocator()
163 : std::allocator<T>()
164 , allocate_zero_called_(false)
165 , deallocate_called_without_allocate_(false)
166 {}
167
allocate(std::size_t n)168 T* allocate(std::size_t n)
169 {
170 if (n == 0) {
171 allocate_zero_called_ = true;
172 }
173 return std::allocator<T>::allocate(n);
174 }
175
deallocate(T * p,std::size_t n)176 void deallocate(T* p, std::size_t n)
177 {
178 if (n == 0 && !allocate_zero_called_) {
179 deallocate_called_without_allocate_ = true;
180 }
181 return std::allocator<T>::deallocate(p, n);
182 }
183 };
184
test_merge_empty_free()185 bool test_merge_empty_free()
186 {
187 vector<int> source;
188 source.emplace_back(1);
189
190 vector< int, check_dealloc_allocator<int> > empty;
191 empty.merge(source.begin(), source.end());
192
193 return empty.get_stored_allocator().deallocate_called_without_allocate_;
194 }
195
main()196 int main()
197 {
198 {
199 const std::size_t positions_length = 10;
200 std::size_t positions[positions_length];
201 vector<int> vector_int;
202 vector<int> vector_int2(positions_length);
203 for(std::size_t i = 0; i != positions_length; ++i){
204 positions[i] = 0u;
205 }
206 for(std::size_t i = 0, max = vector_int2.size(); i != max; ++i){
207 vector_int2[i] = (int)i;
208 }
209
210 vector_int.insert(vector_int.begin(), 999);
211
212 vector_int.insert_ordered_at(positions_length, positions + positions_length, vector_int2.end());
213
214 for(std::size_t i = 0, max = vector_int.size(); i != max; ++i){
215 std::cout << vector_int[i] << std::endl;
216 }
217 }
218 recursive_vector_test();
219 {
220 //Now test move semantics
221 vector<recursive_vector> original;
222 vector<recursive_vector> move_ctor(boost::move(original));
223 vector<recursive_vector> move_assign;
224 move_assign = boost::move(move_ctor);
225 move_assign.swap(original);
226 }
227
228 ////////////////////////////////////
229 // Testing allocator implementations
230 ////////////////////////////////////
231 // std:allocator
232 if(test_cont_variants< std::allocator<void> >()){
233 std::cerr << "test_cont_variants< std::allocator<void> > failed" << std::endl;
234 return 1;
235 }
236 // boost::container::allocator
237 if(test_cont_variants< allocator<void> >()){
238 std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl;
239 return 1;
240 }
241
242 {
243 typedef vector<Test, std::allocator<Test> > MyEnumCont;
244 MyEnumCont v;
245 Test t;
246 v.push_back(t);
247 v.push_back(::boost::move(t));
248 v.push_back(Test());
249 }
250
251 if (test_smart_ref_type())
252 return 1;
253
254 ////////////////////////////////////
255 // Backwards expansion test
256 ////////////////////////////////////
257 if(test_expand_bwd())
258 return 1;
259
260 ////////////////////////////////////
261 // Default init test
262 ////////////////////////////////////
263 if(!test::default_init_test< vector<int, test::default_init_allocator<int> > >()){
264 std::cerr << "Default init test failed" << std::endl;
265 return 1;
266 }
267
268 ////////////////////////////////////
269 // Emplace testing
270 ////////////////////////////////////
271 const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE);
272 if(!boost::container::test::test_emplace< vector<test::EmplaceInt>, Options>()){
273 return 1;
274 }
275
276 ////////////////////////////////////
277 // Allocator propagation testing
278 ////////////////////////////////////
279 if(!boost::container::test::test_propagate_allocator<boost_container_vector>()){
280 return 1;
281 }
282
283 ////////////////////////////////////
284 // Initializer lists testing
285 ////////////////////////////////////
286 if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for<
287 boost::container::vector<int>
288 >()) {
289 return 1;
290 }
291
292 ////////////////////////////////////
293 // Iterator testing
294 ////////////////////////////////////
295 {
296 typedef boost::container::vector<int> cont_int;
297 cont_int a; a.push_back(0); a.push_back(1); a.push_back(2);
298 boost::intrusive::test::test_iterator_random< cont_int >(a);
299 if(boost::report_errors() != 0) {
300 return 1;
301 }
302 }
303
304 #ifndef BOOST_CONTAINER_NO_CXX17_CTAD
305 ////////////////////////////////////
306 // Constructor Template Auto Deduction testing
307 ////////////////////////////////////
308 {
309 auto gold = std::vector{ 1, 2, 3 };
310 auto test = boost::container::vector(gold.begin(), gold.end());
311 if (test.size() != 3) {
312 return 1;
313 }
314 if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) {
315 return 1;
316 }
317 }
318 {
319 auto gold = std::vector{ 1, 2, 3 };
320 auto test = boost::container::vector(gold.begin(), gold.end(), boost::container::new_allocator<int>());
321 if (test.size() != 3) {
322 return 1;
323 }
324 if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) {
325 return 1;
326 }
327 }
328 #endif
329
330 if (test_merge_empty_free()) {
331 std::cerr << "Merge into empty vector test failed" << std::endl;
332 return 1;
333 }
334
335 ////////////////////////////////////
336 // has_trivial_destructor_after_move testing
337 ////////////////////////////////////
338 // default allocator
339 {
340 typedef boost::container::vector<int> cont;
341 typedef cont::allocator_type allocator_type;
342 typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
343 BOOST_STATIC_ASSERT_MSG
344 ( !boost::has_trivial_destructor_after_move<pointer>::value ||
345 (boost::has_trivial_destructor_after_move<cont>::value ==
346 boost::has_trivial_destructor_after_move<allocator_type>::value)
347 , "has_trivial_destructor_after_move(default allocator) test failed"
348 );
349 }
350 // std::allocator
351 {
352 typedef boost::container::vector<int, std::allocator<int> > cont;
353 typedef cont::allocator_type allocator_type;
354 typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
355 BOOST_STATIC_ASSERT_MSG
356 ( !boost::has_trivial_destructor_after_move<pointer>::value ||
357 (boost::has_trivial_destructor_after_move<cont>::value ==
358 boost::has_trivial_destructor_after_move<allocator_type>::value)
359 , "has_trivial_destructor_after_move(std::allocator) test failed"
360 );
361 }
362
363 return 0;
364 }
365