|
1 /* Boost.MultiIndex test for safe_mode. |
|
2 * |
|
3 * Copyright 2003-2006 Joaquín M López Muñoz. |
|
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_safe_mode.hpp" |
|
12 |
|
13 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ |
|
14 #include "pre_multi_index.hpp" |
|
15 #include "employee.hpp" |
|
16 #include "pair_of_ints.hpp" |
|
17 #include <stdexcept> |
|
18 #include <boost/test/test_tools.hpp> |
|
19 |
|
20 using namespace boost::multi_index; |
|
21 |
|
22 #define TRY_SAFE_MODE \ |
|
23 try{ |
|
24 |
|
25 #define CATCH_SAFE_MODE(err) \ |
|
26 throw std::runtime_error("safe mode violation not detected");\ |
|
27 }catch(const safe_mode_exception& e){\ |
|
28 if(e.error_code!=(err))throw std::runtime_error(\ |
|
29 "safe mode violation not expected");\ |
|
30 } |
|
31 |
|
32 template<typename Policy> |
|
33 static void local_test_safe_mode( |
|
34 std::forward_iterator_tag |
|
35 BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Policy)) |
|
36 { |
|
37 typedef typename Policy::container container; |
|
38 typedef typename Policy::index_type index_type; |
|
39 typedef typename index_type::value_type value_type; |
|
40 typedef typename index_type::iterator iterator; |
|
41 |
|
42 container c,c2; |
|
43 index_type& i=Policy::index_from_container(c); |
|
44 index_type& i2=Policy::index_from_container(c2); |
|
45 Policy::insert(i,Policy::some_value()); |
|
46 |
|
47 TRY_SAFE_MODE |
|
48 iterator it; |
|
49 iterator it2=i.begin(); |
|
50 it2=it; |
|
51 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
52 |
|
53 TRY_SAFE_MODE |
|
54 iterator it; |
|
55 value_type e=*it; |
|
56 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
57 |
|
58 TRY_SAFE_MODE |
|
59 iterator it=i.end(); |
|
60 value_type e=*it; |
|
61 CATCH_SAFE_MODE(safe_mode::not_dereferenceable_iterator) |
|
62 |
|
63 TRY_SAFE_MODE |
|
64 iterator it=i.end(); |
|
65 ++it; |
|
66 CATCH_SAFE_MODE(safe_mode::not_incrementable_iterator) |
|
67 |
|
68 TRY_SAFE_MODE |
|
69 iterator it; |
|
70 iterator it2; |
|
71 bool b=(it==it2); |
|
72 b=true; /* avoid warning about unused var */ |
|
73 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
74 |
|
75 TRY_SAFE_MODE |
|
76 iterator it=i.begin(); |
|
77 iterator it2; |
|
78 bool b=(it==it2); |
|
79 b=true; /* avoid warning about unused var */ |
|
80 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
81 |
|
82 TRY_SAFE_MODE |
|
83 iterator it=i.begin(); |
|
84 iterator it2=i2.begin(); |
|
85 bool b=(it==it2); |
|
86 b=true; /* avoid warning about unused var */ |
|
87 CATCH_SAFE_MODE(safe_mode::not_same_owner) |
|
88 |
|
89 TRY_SAFE_MODE |
|
90 i.erase(i.end(),i.begin()); |
|
91 CATCH_SAFE_MODE(safe_mode::invalid_range) |
|
92 |
|
93 TRY_SAFE_MODE |
|
94 iterator it; |
|
95 Policy::insert(i,it,Policy::some_value()); |
|
96 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
97 |
|
98 TRY_SAFE_MODE |
|
99 i.erase(i.end()); |
|
100 CATCH_SAFE_MODE(safe_mode::not_dereferenceable_iterator) |
|
101 |
|
102 TRY_SAFE_MODE |
|
103 iterator it=i.begin(); |
|
104 Policy::insert(i2,it,Policy::some_value()); |
|
105 CATCH_SAFE_MODE(safe_mode::not_owner) |
|
106 |
|
107 TRY_SAFE_MODE |
|
108 iterator it=i.begin(); |
|
109 iterator it2=i2.end(); |
|
110 i2.erase(it,it2); |
|
111 CATCH_SAFE_MODE(safe_mode::not_owner) |
|
112 |
|
113 TRY_SAFE_MODE |
|
114 iterator it=Policy::insert(i,Policy::another_value()); |
|
115 i.erase(it); |
|
116 i.erase(it); |
|
117 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
118 |
|
119 TRY_SAFE_MODE |
|
120 container c3(c); |
|
121 index_type& i3=Policy::index_from_container(c3); |
|
122 iterator it=Policy::insert(i3,Policy::another_value()); |
|
123 i3.clear(); |
|
124 i3.erase(it); |
|
125 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
126 |
|
127 TRY_SAFE_MODE |
|
128 iterator it; |
|
129 { |
|
130 container c3; |
|
131 index_type& i3=Policy::index_from_container(c3); |
|
132 it=i3.end(); |
|
133 } |
|
134 it=it; |
|
135 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
136 |
|
137 TRY_SAFE_MODE |
|
138 iterator it; |
|
139 { |
|
140 container c3; |
|
141 index_type& i3=Policy::index_from_container(c3); |
|
142 it=Policy::insert(i3,Policy::some_value()); |
|
143 } |
|
144 value_type e=*it; |
|
145 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
146 |
|
147 TRY_SAFE_MODE |
|
148 iterator it; |
|
149 { |
|
150 container c3; |
|
151 index_type& i3=Policy::index_from_container(c3); |
|
152 it=Policy::insert(i3,Policy::some_value()); |
|
153 } |
|
154 iterator it2; |
|
155 it2=it; |
|
156 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
157 |
|
158 TRY_SAFE_MODE |
|
159 container c3(c); |
|
160 container c4; |
|
161 index_type& i3=Policy::index_from_container(c3); |
|
162 index_type& i4=Policy::index_from_container(c4); |
|
163 iterator it=i3.begin(); |
|
164 i3.swap(i4); |
|
165 i3.erase(it); |
|
166 CATCH_SAFE_MODE(safe_mode::not_owner) |
|
167 |
|
168 /* this, unlike the previous case, is indeed correct, test safe mode |
|
169 * gets it right |
|
170 */ |
|
171 { |
|
172 container c3(c); |
|
173 container c4; |
|
174 index_type& i3=Policy::index_from_container(c3); |
|
175 index_type& i4=Policy::index_from_container(c4); |
|
176 iterator it=i3.begin(); |
|
177 i3.swap(i4); |
|
178 i4.erase(it); |
|
179 } |
|
180 |
|
181 TRY_SAFE_MODE |
|
182 iterator it=i.end(); |
|
183 typename container::iterator it2=project<0>(c2,it); |
|
184 CATCH_SAFE_MODE(safe_mode::not_owner) |
|
185 |
|
186 TRY_SAFE_MODE |
|
187 iterator it=Policy::insert(i,Policy::another_value()); |
|
188 typename container::iterator it2=project<0>(c,it); |
|
189 i.erase(it); |
|
190 value_type e=*it2; |
|
191 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
192 |
|
193 /* testcase for bug reported at |
|
194 * http://lists.boost.org/boost-users/2006/02/17230.php |
|
195 */ |
|
196 { |
|
197 container c3(c); |
|
198 index_type& i3=Policy::index_from_container(c3); |
|
199 iterator it=i3.end(); |
|
200 i3.clear(); |
|
201 it=i3.end(); |
|
202 } |
|
203 |
|
204 /* testcase for doppelganger bug of that discovered for STLport at |
|
205 * http://lists.boost.org/Archives/boost/2006/04/102740.php |
|
206 */ |
|
207 { |
|
208 container c3; |
|
209 index_type& i3=Policy::index_from_container(c3); |
|
210 iterator it=i3.end(); |
|
211 i3.clear(); |
|
212 it=it; |
|
213 BOOST_CHECK(it==i3.end()); |
|
214 } |
|
215 } |
|
216 |
|
217 template<typename Policy> |
|
218 static void local_test_safe_mode( |
|
219 std::bidirectional_iterator_tag |
|
220 BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Policy)) |
|
221 { |
|
222 ::local_test_safe_mode<Policy>(std::forward_iterator_tag()); |
|
223 |
|
224 typedef typename Policy::container container; |
|
225 typedef typename Policy::index_type index_type; |
|
226 typedef typename index_type::value_type value_type; |
|
227 typedef typename index_type::iterator iterator; |
|
228 |
|
229 container c; |
|
230 index_type& i=Policy::index_from_container(c); |
|
231 Policy::insert(i,Policy::some_value()); |
|
232 |
|
233 TRY_SAFE_MODE |
|
234 iterator it=i.begin(); |
|
235 --it; |
|
236 CATCH_SAFE_MODE(safe_mode::not_decrementable_iterator) |
|
237 } |
|
238 |
|
239 template<typename Policy> |
|
240 static void local_test_safe_mode( |
|
241 std::random_access_iterator_tag |
|
242 BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Policy)) |
|
243 { |
|
244 ::local_test_safe_mode<Policy>(std::bidirectional_iterator_tag()); |
|
245 |
|
246 typedef typename Policy::container container; |
|
247 typedef typename Policy::index_type index_type; |
|
248 typedef typename index_type::value_type value_type; |
|
249 typedef typename index_type::iterator iterator; |
|
250 |
|
251 container c; |
|
252 index_type& i=Policy::index_from_container(c); |
|
253 Policy::insert(i,Policy::some_value()); |
|
254 |
|
255 TRY_SAFE_MODE |
|
256 iterator it=i.begin(); |
|
257 it+=2; |
|
258 CATCH_SAFE_MODE(safe_mode::out_of_bounds) |
|
259 |
|
260 TRY_SAFE_MODE |
|
261 iterator it=i.begin(); |
|
262 it-=1; |
|
263 CATCH_SAFE_MODE(safe_mode::out_of_bounds) |
|
264 } |
|
265 |
|
266 template<typename Policy> |
|
267 static void local_test_safe_mode(BOOST_EXPLICIT_TEMPLATE_TYPE(Policy)) |
|
268 { |
|
269 typedef typename Policy::index_type::iterator::iterator_category category; |
|
270 ::local_test_safe_mode<Policy>(category()); |
|
271 } |
|
272 |
|
273 template<typename Policy> |
|
274 static void local_test_safe_mode_with_rearrange( |
|
275 BOOST_EXPLICIT_TEMPLATE_TYPE(Policy)) |
|
276 { |
|
277 ::local_test_safe_mode<Policy>(); |
|
278 |
|
279 typedef typename Policy::container container; |
|
280 typedef typename Policy::index_type index_type; |
|
281 typedef typename index_type::value_type value_type; |
|
282 typedef typename index_type::iterator iterator; |
|
283 |
|
284 container c; |
|
285 index_type& i=Policy::index_from_container(c); |
|
286 Policy::insert(i,Policy::some_value()); |
|
287 |
|
288 TRY_SAFE_MODE |
|
289 iterator it; |
|
290 i.splice(it,i,i.begin(),i.end()); |
|
291 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
292 |
|
293 TRY_SAFE_MODE |
|
294 container c2(c); |
|
295 index_type& i2=Policy::index_from_container(c2); |
|
296 iterator it2=i2.begin(); |
|
297 iterator it=i.begin(); |
|
298 i.splice(it2,i2,it); |
|
299 CATCH_SAFE_MODE(safe_mode::not_owner) |
|
300 |
|
301 TRY_SAFE_MODE |
|
302 i.splice(i.begin(),i,i.begin(),i.end()); |
|
303 CATCH_SAFE_MODE(safe_mode::inside_range) |
|
304 |
|
305 TRY_SAFE_MODE |
|
306 i.splice(i.begin(),i,i.end(),i.begin()); |
|
307 CATCH_SAFE_MODE(safe_mode::invalid_range) |
|
308 |
|
309 TRY_SAFE_MODE |
|
310 i.splice(i.begin(),i); |
|
311 CATCH_SAFE_MODE(safe_mode::same_container) |
|
312 |
|
313 TRY_SAFE_MODE |
|
314 iterator it; |
|
315 i.relocate(it,i.begin(),i.end()); |
|
316 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
317 |
|
318 TRY_SAFE_MODE |
|
319 i.relocate(i.begin(),i.begin(),i.end()); |
|
320 CATCH_SAFE_MODE(safe_mode::inside_range) |
|
321 |
|
322 TRY_SAFE_MODE |
|
323 i.relocate(i.begin(),i.end(),i.begin()); |
|
324 CATCH_SAFE_MODE(safe_mode::invalid_range) |
|
325 } |
|
326 |
|
327 template<typename MultiIndexContainer,int N> |
|
328 struct index_policy_base |
|
329 { |
|
330 typedef MultiIndexContainer container; |
|
331 typedef typename |
|
332 boost::multi_index::detail::prevent_eti< |
|
333 container, |
|
334 typename nth_index<container,N>::type>::type index_type; |
|
335 |
|
336 static index_type& index_from_container(container& c){return get<N>(c);} |
|
337 }; |
|
338 |
|
339 template<typename MultiIndexContainer,int N> |
|
340 struct key_based_index_policy_base: |
|
341 index_policy_base<MultiIndexContainer,N> |
|
342 { |
|
343 typedef index_policy_base<MultiIndexContainer,N> super; |
|
344 |
|
345 typedef typename super::container container; |
|
346 typedef typename super::index_type index_type; |
|
347 typedef typename index_type::value_type value_type; |
|
348 typedef typename index_type::iterator iterator; |
|
349 |
|
350 static iterator insert(index_type& i,const value_type& v) |
|
351 { |
|
352 return i.insert(v).first; |
|
353 } |
|
354 |
|
355 static iterator insert(index_type& i,iterator it,const value_type& v) |
|
356 { |
|
357 return i.insert(it,v); |
|
358 } |
|
359 }; |
|
360 |
|
361 template<typename MultiIndexContainer,int N> |
|
362 struct non_key_based_index_policy_base: |
|
363 index_policy_base<MultiIndexContainer,N> |
|
364 { |
|
365 typedef index_policy_base<MultiIndexContainer,N> super; |
|
366 |
|
367 typedef typename super::container container; |
|
368 typedef typename super::index_type index_type; |
|
369 typedef typename index_type::value_type value_type; |
|
370 typedef typename index_type::iterator iterator; |
|
371 |
|
372 static iterator insert(index_type& i,const value_type& v) |
|
373 { |
|
374 return i.push_back(v).first; |
|
375 } |
|
376 |
|
377 static iterator insert(index_type& i,iterator it,const value_type& v) |
|
378 { |
|
379 return i.insert(it,v).first; |
|
380 } |
|
381 }; |
|
382 |
|
383 struct employee_set_policy_base |
|
384 { |
|
385 static employee some_value(){return employee(0,"Joe",31,1123);} |
|
386 static employee another_value(){return employee(1,"Robert",27,5601);} |
|
387 }; |
|
388 |
|
389 struct employee_set_policy: |
|
390 employee_set_policy_base, |
|
391 key_based_index_policy_base<employee_set,0> |
|
392 {}; |
|
393 |
|
394 struct employee_set_by_name_policy: |
|
395 employee_set_policy_base, |
|
396 key_based_index_policy_base<employee_set,1> |
|
397 {}; |
|
398 |
|
399 struct employee_set_as_inserted_policy: |
|
400 employee_set_policy_base, |
|
401 non_key_based_index_policy_base<employee_set,3> |
|
402 {}; |
|
403 |
|
404 struct employee_set_randomly_policy: |
|
405 employee_set_policy_base, |
|
406 non_key_based_index_policy_base<employee_set,5> |
|
407 {}; |
|
408 |
|
409 template<typename IntegralBimap> |
|
410 static void test_integral_bimap(BOOST_EXPLICIT_TEMPLATE_TYPE(IntegralBimap)) |
|
411 { |
|
412 typedef typename IntegralBimap::value_type value_type; |
|
413 typedef typename IntegralBimap::iterator iterator; |
|
414 |
|
415 TRY_SAFE_MODE |
|
416 IntegralBimap bm; |
|
417 iterator it=bm.insert(value_type(0,0)).first; |
|
418 bm.insert(value_type(1,1)); |
|
419 bm.modify(it,increment_first); |
|
420 value_type v=*it; |
|
421 v.first=0; /* avoid warning about unused var */ |
|
422 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
423 |
|
424 TRY_SAFE_MODE |
|
425 IntegralBimap bm; |
|
426 iterator it=bm.insert(value_type(0,0)).first; |
|
427 bm.insert(value_type(1,1)); |
|
428 bm.modify(it,increment_second); |
|
429 pair_of_ints v=*it; |
|
430 v.first=0; /* avoid warning about unused var */ |
|
431 CATCH_SAFE_MODE(safe_mode::invalid_iterator) |
|
432 } |
|
433 |
|
434 void test_safe_mode() |
|
435 { |
|
436 local_test_safe_mode<employee_set_policy>(); |
|
437 local_test_safe_mode<employee_set_by_name_policy>(); |
|
438 local_test_safe_mode_with_rearrange<employee_set_as_inserted_policy>(); |
|
439 local_test_safe_mode_with_rearrange<employee_set_randomly_policy>(); |
|
440 |
|
441 typedef multi_index_container< |
|
442 pair_of_ints, |
|
443 indexed_by< |
|
444 ordered_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,first)>, |
|
445 ordered_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,second)> > |
|
446 > bimap0_type; |
|
447 |
|
448 /* MSVC++ 6.0 chokes on test_integral_bimap without this |
|
449 * explicit instantiation |
|
450 */ |
|
451 bimap0_type bm0; |
|
452 test_integral_bimap<bimap0_type>(); |
|
453 |
|
454 typedef multi_index_container< |
|
455 pair_of_ints, |
|
456 indexed_by< |
|
457 ordered_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,first)>, |
|
458 hashed_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,second)> > |
|
459 > bimap1_type; |
|
460 |
|
461 bimap1_type bm1; |
|
462 test_integral_bimap<bimap1_type>(); |
|
463 |
|
464 typedef multi_index_container< |
|
465 pair_of_ints, |
|
466 indexed_by< |
|
467 hashed_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,first)>, |
|
468 ordered_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,second)> > |
|
469 > bimap2_type; |
|
470 |
|
471 bimap2_type bm2; |
|
472 test_integral_bimap<bimap2_type>(); |
|
473 |
|
474 typedef multi_index_container< |
|
475 pair_of_ints, |
|
476 indexed_by< |
|
477 hashed_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,first)>, |
|
478 hashed_unique<BOOST_MULTI_INDEX_MEMBER(pair_of_ints,int,second)> > |
|
479 > bimap3_type; |
|
480 |
|
481 bimap3_type bm3; |
|
482 test_integral_bimap<bimap3_type>(); |
|
483 } |