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:
recursive_vector(const recursive_vector & x)85 recursive_vector (const recursive_vector &x)
86 : vector_(x.vector_)
87 {}
88
operator =(const recursive_vector & x)89 recursive_vector & operator=(const recursive_vector &x)
90 { this->vector_ = x.vector_; return *this; }
91
92 int id_;
93 vector<recursive_vector> vector_;
94 vector<recursive_vector>::iterator it_;
95 vector<recursive_vector>::const_iterator cit_;
96 vector<recursive_vector>::reverse_iterator rit_;
97 vector<recursive_vector>::const_reverse_iterator crit_;
98 };
99
recursive_vector_test()100 void recursive_vector_test()//Test for recursive types
101 {
102 vector<recursive_vector> recursive_vector_vector;
103 }
104
105 enum Test
106 {
107 zero, one, two, three, four, five, six
108 };
109
110 template<class VoidAllocator>
111 struct GetAllocatorCont
112 {
113 template<class ValueType>
114 struct apply
115 {
116 typedef vector< ValueType
117 , typename allocator_traits<VoidAllocator>
118 ::template portable_rebind_alloc<ValueType>::type
119 > type;
120 };
121 };
122
123 template<class VoidAllocator>
test_cont_variants()124 int test_cont_variants()
125 {
126 typedef typename GetAllocatorCont<VoidAllocator>::template apply<int>::type MyCont;
127 typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_int>::type MyMoveCont;
128 typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont;
129 typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont;
130
131 if(test::vector_test<MyCont>())
132 return 1;
133 if(test::vector_test<MyMoveCont>())
134 return 1;
135 if(test::vector_test<MyCopyMoveCont>())
136 return 1;
137 if(test::vector_test<MyCopyCont>())
138 return 1;
139
140 return 0;
141 }
142
143 struct boost_container_vector;
144
145 namespace boost { namespace container { namespace test {
146
147 template<>
148 struct alloc_propagate_base<boost_container_vector>
149 {
150 template <class T, class Allocator>
151 struct apply
152 {
153 typedef boost::container::vector<T, Allocator> type;
154 };
155 };
156
157 }}} //namespace boost::container::test
158
159 template<typename T>
160 class check_dealloc_allocator : public std::allocator<T>
161 {
162 public:
163 bool allocate_zero_called_;
164 bool deallocate_called_without_allocate_;
165
check_dealloc_allocator()166 check_dealloc_allocator()
167 : std::allocator<T>()
168 , allocate_zero_called_(false)
169 , deallocate_called_without_allocate_(false)
170 {}
171
allocate(std::size_t n)172 T* allocate(std::size_t n)
173 {
174 if (n == 0) {
175 allocate_zero_called_ = true;
176 }
177 return std::allocator<T>::allocate(n);
178 }
179
deallocate(T * p,std::size_t n)180 void deallocate(T* p, std::size_t n)
181 {
182 if (n == 0 && !allocate_zero_called_) {
183 deallocate_called_without_allocate_ = true;
184 }
185 return std::allocator<T>::deallocate(p, n);
186 }
187 };
188
test_merge_empty_free()189 bool test_merge_empty_free()
190 {
191 vector<int> source;
192 source.emplace_back(1);
193
194 vector< int, check_dealloc_allocator<int> > empty;
195 empty.merge(source.begin(), source.end());
196
197 return empty.get_stored_allocator().deallocate_called_without_allocate_;
198 }
199
main()200 int main()
201 {
202 {
203 const std::size_t positions_length = 10;
204 std::size_t positions[positions_length];
205 vector<int> vector_int;
206 vector<int> vector_int2(positions_length);
207 for(std::size_t i = 0; i != positions_length; ++i){
208 positions[i] = 0u;
209 }
210 for(std::size_t i = 0, max = vector_int2.size(); i != max; ++i){
211 vector_int2[i] = (int)i;
212 }
213
214 vector_int.insert(vector_int.begin(), 999);
215
216 vector_int.insert_ordered_at(positions_length, positions + positions_length, vector_int2.end());
217
218 for(std::size_t i = 0, max = vector_int.size(); i != max; ++i){
219 std::cout << vector_int[i] << std::endl;
220 }
221 }
222 recursive_vector_test();
223 {
224 //Now test move semantics
225 vector<recursive_vector> original;
226 vector<recursive_vector> move_ctor(boost::move(original));
227 vector<recursive_vector> move_assign;
228 move_assign = boost::move(move_ctor);
229 move_assign.swap(original);
230 }
231
232 ////////////////////////////////////
233 // Testing allocator implementations
234 ////////////////////////////////////
235 // std:allocator
236 if(test_cont_variants< std::allocator<void> >()){
237 std::cerr << "test_cont_variants< std::allocator<void> > failed" << std::endl;
238 return 1;
239 }
240 // boost::container::allocator
241 if(test_cont_variants< allocator<void> >()){
242 std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl;
243 return 1;
244 }
245
246 {
247 typedef vector<Test, std::allocator<Test> > MyEnumCont;
248 MyEnumCont v;
249 Test t;
250 v.push_back(t);
251 v.push_back(::boost::move(t));
252 v.push_back(Test());
253 }
254
255 if (test_smart_ref_type())
256 return 1;
257
258 ////////////////////////////////////
259 // Backwards expansion test
260 ////////////////////////////////////
261 if(test_expand_bwd())
262 return 1;
263
264 ////////////////////////////////////
265 // Default init test
266 ////////////////////////////////////
267 if(!test::default_init_test< vector<int, test::default_init_allocator<int> > >()){
268 std::cerr << "Default init test failed" << std::endl;
269 return 1;
270 }
271
272 ////////////////////////////////////
273 // Emplace testing
274 ////////////////////////////////////
275 const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE);
276 if(!boost::container::test::test_emplace< vector<test::EmplaceInt>, Options>()){
277 return 1;
278 }
279
280 ////////////////////////////////////
281 // Allocator propagation testing
282 ////////////////////////////////////
283 if(!boost::container::test::test_propagate_allocator<boost_container_vector>()){
284 return 1;
285 }
286
287 ////////////////////////////////////
288 // Initializer lists testing
289 ////////////////////////////////////
290 if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for<
291 boost::container::vector<int>
292 >()) {
293 return 1;
294 }
295
296 ////////////////////////////////////
297 // Iterator testing
298 ////////////////////////////////////
299 {
300 typedef boost::container::vector<int> cont_int;
301 cont_int a; a.push_back(0); a.push_back(1); a.push_back(2);
302 boost::intrusive::test::test_iterator_random< cont_int >(a);
303 if(boost::report_errors() != 0) {
304 return 1;
305 }
306 }
307
308 #ifndef BOOST_CONTAINER_NO_CXX17_CTAD
309 ////////////////////////////////////
310 // Constructor Template Auto Deduction testing
311 ////////////////////////////////////
312 {
313 auto gold = std::vector{ 1, 2, 3 };
314 auto test = boost::container::vector(gold.begin(), gold.end());
315 if (test.size() != 3) {
316 return 1;
317 }
318 if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) {
319 return 1;
320 }
321 }
322 {
323 auto gold = std::vector{ 1, 2, 3 };
324 auto test = boost::container::vector(gold.begin(), gold.end(), boost::container::new_allocator<int>());
325 if (test.size() != 3) {
326 return 1;
327 }
328 if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) {
329 return 1;
330 }
331 }
332 #endif
333
334 if (test_merge_empty_free()) {
335 std::cerr << "Merge into empty vector test failed" << std::endl;
336 return 1;
337 }
338
339 ////////////////////////////////////
340 // has_trivial_destructor_after_move testing
341 ////////////////////////////////////
342 // default allocator
343 {
344 typedef boost::container::vector<int> cont;
345 typedef cont::allocator_type allocator_type;
346 typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
347 BOOST_STATIC_ASSERT_MSG
348 ( !boost::has_trivial_destructor_after_move<pointer>::value ||
349 (boost::has_trivial_destructor_after_move<cont>::value ==
350 boost::has_trivial_destructor_after_move<allocator_type>::value)
351 , "has_trivial_destructor_after_move(default allocator) test failed"
352 );
353 }
354 // std::allocator
355 {
356 typedef boost::container::vector<int, std::allocator<int> > cont;
357 typedef cont::allocator_type allocator_type;
358 typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
359 BOOST_STATIC_ASSERT_MSG
360 ( !boost::has_trivial_destructor_after_move<pointer>::value ||
361 (boost::has_trivial_destructor_after_move<cont>::value ==
362 boost::has_trivial_destructor_after_move<allocator_type>::value)
363 , "has_trivial_destructor_after_move(std::allocator) test failed"
364 );
365 }
366
367 return 0;
368 }
369