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       if (boost::has_trivial_destructor_after_move<cont>::value !=
344           boost::has_trivial_destructor_after_move<allocator_type>::value &&
345           boost::has_trivial_destructor_after_move<pointer>::value) {
346          std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl;
347          return 1;
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       if (boost::has_trivial_destructor_after_move<cont>::value !=
356           boost::has_trivial_destructor_after_move<allocator_type>::value &&
357           boost::has_trivial_destructor_after_move<pointer>::value) {
358          std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl;
359          return 1;
360       }
361    }
362 
363    return 0;
364 }
365