1 /* Boost.MultiIndex test for modifier memfuns.
3 * Copyright 2003-2018 Joaquin M Lopez Munoz.
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)
8 * See http://www.boost.org/libs/multi_index for library home page.
11 #include "test_modifiers.hpp"
13 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
14 #include <boost/detail/lightweight_test.hpp>
15 #include <boost/enable_shared_from_this.hpp>
16 #include <boost/iterator/iterator_facade.hpp>
17 #include <boost/move/core.hpp>
18 #include <boost/move/utility_core.hpp>
19 #include <boost/next_prior.hpp>
20 #include <boost/shared_ptr.hpp>
23 #include "pre_multi_index.hpp"
24 #include "employee.hpp"
26 using namespace boost::multi_index
;
28 struct non_copyable_int
30 explicit non_copyable_int(int n_
):n(n_
){}
31 non_copyable_int(BOOST_RV_REF(non_copyable_int
) x
):n(x
.n
){x
.n
=0;}
32 non_copyable_int
& operator=(BOOST_RV_REF(non_copyable_int
) x
)
41 BOOST_MOVABLE_BUT_NOT_COPYABLE(non_copyable_int
)
50 int get()const{return n
;}
56 inline bool operator==(const always_one
& x
,const always_one
& y
)
58 return x
.get()==y
.get();
61 #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
65 inline std::size_t hash_value(const always_one
& x
)
67 return static_cast<std::size_t>(x
.get());
70 #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
71 } /* namespace boost */
76 struct impl
:boost::enable_shared_from_this
<impl
>
78 typedef boost::shared_ptr
<const impl
> ptr
;
80 impl(int n_
,ptr next_
=ptr()):n(n_
),next(next_
){}
86 typedef multi_index_container
<
90 #if BOOST_WORKAROUND(__IBMCPP__,BOOST_TESTED_AT(1010))
91 ordered_unique
<member
<impl
,int,&linked_object::impl::n
> >,
92 hashed_non_unique
<member
<impl
,int,&linked_object::impl::n
> >,
94 ordered_unique
<member
<impl
,int,&impl::n
> >,
95 hashed_non_unique
<member
<impl
,int,&impl::n
> >,
103 static impl_repository_t impl_repository
;
106 linked_object(int n
):pimpl(init(impl(n
))){}
107 linked_object(int n
,const linked_object
& x
):pimpl(init(impl(n
,x
.pimpl
))){}
110 impl::ptr
init(const impl
& x
)
112 std::pair
<impl_repository_t::iterator
,bool> p
=impl_repository
.insert(x
);
113 if(p
.second
)return impl::ptr(&*p
.first
,&erase_impl
);
114 else return p
.first
->shared_from_this();
117 static void erase_impl(const impl
* p
)
119 impl_repository
.erase(p
->n
);
125 linked_object::impl_repository_t
linked_object::impl_repository
;
127 struct tempvalue_iterator
:
128 boost::iterator_facade
<
129 tempvalue_iterator
,int,boost::forward_traversal_tag
,int>
131 tempvalue_iterator(int n_
):n(n_
){}
133 void increment(){++n
;}
134 bool equal(const tempvalue_iterator
& x
)const{return n
==x
.n
;}
135 int dereference()const{return n
;}
142 change_int(int n
):n(n
){}
144 void operator()(int& x
)const{x
=n
;}
149 #if !(defined BOOST_NO_EXCEPTIONS)
150 struct change_int_and_throw
152 change_int_and_throw(int n
):n(n
){}
154 void operator()(int& x
)const{x
=n
;throw 0;}
160 void test_modifiers()
163 employee_set_by_name
& i1
=get
<name
>(es
);
164 employee_set_by_age
& i2
=get
<age
>(es
);
165 employee_set_as_inserted
& i3
=get
<as_inserted
>(es
);
166 employee_set_by_ssn
& i4
=get
<ssn
>(es
);
167 employee_set_randomly
& i5
=get
<randomly
>(es
);
169 es
.insert(employee(0,"Joe",31,1123));
170 BOOST_TEST(es
.emplace(0,"Joe",31,1123).second
==false);
171 BOOST_TEST(i1
.insert(employee(0,"Joe Jr.",5,2563)).second
==false);
172 BOOST_TEST(i2
.emplace_hint(i2
.end(),1,"Victor",5,1123)->name
!="Victor");
173 BOOST_TEST(i3
.insert(i3
.begin(),employee(1,"Victor",5,1123)).second
175 BOOST_TEST(i3
.push_front(employee(0,"Joe Jr.",5,2563)).second
==false);
176 BOOST_TEST(i3
.push_back(employee(0,"Joe Jr.",5,2563)).second
==false);
177 BOOST_TEST(i5
.emplace_front(1,"Victor",5,1123).second
==false);
178 BOOST_TEST(i5
.emplace_back(1,"Victor",5,1123).second
==false);
180 employee_set_by_name::iterator it1
=i1
.find("Joe");
181 i1
.insert(it1
,employee(1,"Joe Jr.",5,2563));
182 BOOST_TEST(es
.size()==2);
184 employee_set_by_age::iterator it2
=i2
.find(31);
185 i2
.insert(it2
,employee(2,"Grandda Joe",64,7881));
186 BOOST_TEST(es
.size()==3);
188 employee_set_as_inserted::iterator it3
=i3
.begin();
189 i3
.insert(it3
,100,employee(3,"Judy",39,6201));
190 BOOST_TEST((--it3
)->ssn
==6201);
191 BOOST_TEST(es
.size()==4);
193 employee_set_randomly::iterator it5
=i5
.begin();
194 i5
.insert(it5
,100,employee(4,"Jill",52,3379));
195 BOOST_TEST(i5
.begin()->age
==52);
196 BOOST_TEST(es
.size()==5);
198 es
.erase(employee(1,"Joe Jr.",5,2563));
199 BOOST_TEST(i3
.size()==4&&i5
.size()==4);
201 BOOST_TEST(i1
.erase("Judy")==1);
202 BOOST_TEST(es
.size()==3&&i2
.size()==3);
204 BOOST_TEST(i2
.erase(it2
)->age
==52);
205 BOOST_TEST(i3
.size()==2&&i4
.size()==2);
208 BOOST_TEST(i1
.size()==1&&i2
.size()==1);
210 i5
.erase(i5
.begin(),i5
.end());
211 BOOST_TEST(es
.size()==0&&i3
.size()==0);
213 i5
.emplace(i5
.end(),0,"Joe",31,1123);
214 BOOST_TEST(i1
.erase(i1
.begin())==i1
.end());
215 BOOST_TEST(i1
.size()==0);
217 i1
.emplace(0,"Joe",31,1123);
218 i3
.emplace(i3
.begin(),1,"Jack",31,5032);
219 i4
.emplace_hint(i4
.end(),2,"James",31,3847);
220 BOOST_TEST(i2
.erase(31)==3);
221 BOOST_TEST(i2
.size()==0);
223 i3
.emplace_front(1,"Jack",31,5032);
224 i3
.emplace_back(0,"Joe",31,1123);
225 BOOST_TEST(i3
.front()==employee(1,"Jack",31,5032));
226 BOOST_TEST(i3
.back()==employee(0,"Joe",31,1123));
229 BOOST_TEST(i3
.back()==employee(1,"Jack",31,5032));
230 BOOST_TEST(es
.size()==1);
233 BOOST_TEST(es
.size()==0);
235 i5
.push_back(employee(1,"Jack",31,5032));
236 i5
.push_front(employee(0,"Joe",31,1123));
237 i5
.insert(i5
.end()-1,employee(2,"Grandda Joe",64,7881));
238 BOOST_TEST(i5
.back()==employee(1,"Jack",31,5032));
239 BOOST_TEST(i5
.front()==employee(0,"Joe",31,1123));
240 BOOST_TEST(i5
[0]==i5
.front()&&i5
.at(0)==i5
.front());
241 BOOST_TEST(i5
[i5
.size()-1]==i5
.back()&&i5
.at(i5
.size()-1)==i5
.back());
244 BOOST_TEST(i5
.back()==employee(1,"Jack",31,5032));
245 BOOST_TEST(i5
.front()==employee(2,"Grandda Joe",64,7881));
246 BOOST_TEST(es
.size()==2);
249 BOOST_TEST(i5
.back()==employee(2,"Grandda Joe",64,7881));
250 BOOST_TEST(i5
.front()==i5
.front());
251 BOOST_TEST(es
.size()==1);
253 i5
.erase(i5
.begin());
254 BOOST_TEST(es
.size()==0);
256 std::vector
<employee
> ve
;
257 ve
.push_back(employee(3,"Anna",31,5388));
258 ve
.push_back(employee(1,"Rachel",27,9012));
259 ve
.push_back(employee(2,"Agatha",40,1520));
261 i1
.insert(ve
.begin(),ve
.end());
262 BOOST_TEST(i2
.size()==3);
264 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
265 i1
.insert({{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
266 BOOST_TEST(i2
.size()==5);
269 BOOST_TEST(i2
.erase(i2
.begin(),i2
.end())==i2
.end());
270 BOOST_TEST(es
.size()==0);
272 i2
.insert(ve
.begin(),ve
.end());
273 BOOST_TEST(i3
.size()==3);
275 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
276 i2
.insert({{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
277 BOOST_TEST(i3
.size()==5);
280 BOOST_TEST(*(i3
.erase(i3
.begin()))==employee(1,"Rachel",27,9012));
281 BOOST_TEST(i3
.erase(i3
.begin(),i3
.end())==i3
.end());
282 BOOST_TEST(es
.size()==0);
284 i3
.insert(i3
.end(),ve
.begin(),ve
.end());
285 BOOST_TEST(es
.size()==3);
287 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
288 i3
.insert(i3
.begin(),{{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
289 BOOST_TEST(i3
.front().name
=="Vanessa");
290 BOOST_TEST(i4
.size()==5);
293 BOOST_TEST(i4
.erase(9012)==1);
294 i4
.erase(i4
.begin());
295 BOOST_TEST(i4
.erase(i4
.begin(),i4
.end())==i4
.end());
297 i4
.insert(ve
.begin(),ve
.end());
298 BOOST_TEST(i5
.size()==3);
300 BOOST_TEST(i5
.erase(i5
.begin(),i5
.end())==i5
.end());
301 BOOST_TEST(es
.size()==0);
303 i5
.insert(i5
.begin(),ve
.begin(),ve
.end());
304 BOOST_TEST(i1
.size()==3);
306 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
307 i5
.insert(i5
.end(),{{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
308 BOOST_TEST(i5
.back().name
=="Penelope");
309 BOOST_TEST(i1
.size()==5);
312 BOOST_TEST(es
.erase(es
.begin(),es
.end())==es
.end());
313 BOOST_TEST(i2
.size()==0);
315 es
.insert(employee(0,"Joe",31,1123));
316 es
.insert(employee(1,"Robert",27,5601));
317 es
.insert(employee(2,"John",40,7889));
318 es
.insert(employee(3,"Albert",20,9012));
319 es
.insert(employee(4,"John",57,1002));
321 employee_set
es_backup(es
);
324 es2
.insert(employee(3,"Anna",31,5388));
325 es2
.insert(employee(1,"Rachel",27,9012));
326 es2
.insert(employee(2,"Agatha",40,1520));
328 employee_set
es2_backup(es2
);
330 i1
.swap(get
<1>(es2
));
331 BOOST_TEST(es
==es2_backup
&&es2
==es_backup
);
333 i2
.swap(get
<2>(es2
));
334 BOOST_TEST(es
==es_backup
&&es2
==es2_backup
);
336 i3
.swap(get
<3>(es2
));
337 BOOST_TEST(es
==es2_backup
&&es2
==es_backup
);
339 i4
.swap(get
<4>(es2
));
340 BOOST_TEST(es
==es_backup
&&es2
==es2_backup
);
342 i5
.swap(get
<5>(es2
));
343 BOOST_TEST(es
==es2_backup
&&es2
==es_backup
);
345 #if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
346 ::boost::multi_index::detail::swap(i1
,get
<1>(es2
));
349 swap(i1
,get
<1>(es2
));
352 BOOST_TEST(es
==es_backup
&&es2
==es2_backup
);
354 #if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
355 ::boost::multi_index::detail::swap(i2
,get
<2>(es2
));
358 swap(i2
,get
<2>(es2
));
361 BOOST_TEST(es
==es2_backup
&&es2
==es_backup
);
363 #if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
364 ::boost::multi_index::detail::swap(i3
,get
<3>(es2
));
367 swap(i3
,get
<3>(es2
));
370 BOOST_TEST(es
==es_backup
&&es2
==es2_backup
);
372 #if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
373 ::boost::multi_index::detail::swap(i4
,get
<4>(es2
));
376 swap(i4
,get
<4>(es2
));
379 BOOST_TEST(es
==es2_backup
&&es2
==es_backup
);
381 #if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
382 ::boost::multi_index::detail::swap(i5
,get
<5>(es2
));
385 swap(i5
,get
<5>(es2
));
388 BOOST_TEST(es
==es_backup
&&es2
==es2_backup
);
391 BOOST_TEST(i3
.size()==0);
395 BOOST_TEST(i4
.size()==0);
399 BOOST_TEST(i5
.size()==0);
402 BOOST_TEST(es2
.size()==0);
404 /* non-copyable elements */
406 multi_index_container
<
409 ordered_non_unique
<member
<non_copyable_int
,int,&non_copyable_int::n
> >,
410 hashed_non_unique
<member
<non_copyable_int
,int,&non_copyable_int::n
> >,
417 get
<1>(ncic
).emplace(1);
418 get
<2>(ncic
).emplace_back(1);
419 get
<3>(ncic
).emplace_back(1);
421 non_copyable_int
nci(1);
422 ncic
.insert(boost::move(nci
));
423 BOOST_TEST(nci
.n
==0);
426 get
<1>(ncic
).insert(boost::move(nci
));
427 BOOST_TEST(nci
.n
==0);
430 get
<2>(ncic
).push_back(boost::move(nci
));
431 BOOST_TEST(nci
.n
==0);
434 get
<3>(ncic
).push_back(boost::move(nci
));
435 BOOST_TEST(nci
.n
==0);
437 std::vector
<int> vi(4,1);
438 const std::vector
<int>& cvi
=vi
;
439 ncic
.insert(vi
.begin(),vi
.end());
440 ncic
.insert(cvi
.begin(),cvi
.end());
441 get
<2>(ncic
).insert(get
<2>(ncic
).begin(),vi
.begin(),vi
.end());
442 get
<2>(ncic
).insert(get
<2>(ncic
).begin(),cvi
.begin(),cvi
.end());
444 BOOST_TEST(ncic
.count(1)==24);
447 BOOST_TEST(ncic
.empty());
448 BOOST_TEST(ncic2
.count(1)==24);
450 /* testcase for problem reported at
451 * http://lists.boost.org/boost-users/2006/12/24215.php
454 multi_index_container
<
457 hashed_non_unique
<identity
<always_one
> >
461 aoc
.insert(always_one());
462 aoc
.insert(always_one());
463 aoc
.erase(*(aoc
.begin()));
464 BOOST_TEST(aoc
.empty());
466 /* Testcases for compliance with "as close to hint as possible"
467 * proposed behavior for associative containers:
468 * http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#233
469 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1780.html
472 typedef multi_index_container
<
475 ordered_non_unique
<identity
<int> >
477 > int_non_unique_container
;
479 int_non_unique_container c
;
480 c
.insert(0);c
.insert(0);
481 c
.insert(1);c
.insert(1);
482 c
.insert(2);c
.insert(2);
484 BOOST_TEST(std::distance(c
.begin(),c
.insert(c
.begin(),1))==2);
485 BOOST_TEST(std::distance(c
.begin(),c
.insert(boost::next(c
.begin()),1))==2);
486 BOOST_TEST(std::distance(c
.begin(),c
.insert(c
.lower_bound(1),1))==2);
488 std::distance(c
.begin(),c
.insert(boost::next(c
.lower_bound(1)),1))==3);
489 BOOST_TEST(std::distance(c
.begin(),c
.insert(c
.upper_bound(1),1))==8);
490 BOOST_TEST(std::distance(c
.begin(),c
.insert(boost::prior(c
.end()),1))==9);
491 BOOST_TEST(std::distance(c
.begin(),c
.insert(c
.end(),1))==10);
493 /* testcase for erase() reentrancy */
496 linked_object
o2(2,o1
);
500 /* testcases for bug reported at
501 * https://svn.boost.org/trac/boost/ticket/9665
505 multi_index_container
<
507 indexed_by
<hashed_unique
<identity
<int> > >
509 hc
.insert(tempvalue_iterator(0),tempvalue_iterator(10));
510 BOOST_TEST(hc
.size()==10);
512 multi_index_container
<
514 indexed_by
<ordered_unique
<identity
<int> > >
516 oc
.insert(tempvalue_iterator(0),tempvalue_iterator(10));
517 BOOST_TEST(oc
.size()==10);
520 /* testcases for https://svn.boost.org/trac10/ticket/12542 */
523 multi_index_container
<
526 ordered_unique
<identity
<int> >,
527 hashed_unique
<identity
<int> >
531 #if !(defined BOOST_NO_EXCEPTIONS)
536 ohc
.modify_key(ohc
.begin(),change_int_and_throw(1));
539 BOOST_TEST(ohc
.size()==1);
546 ohc
.modify_key(ohc
.begin(),change_int_and_throw(1),change_int(0));
549 BOOST_TEST(ohc
.size()==1);
557 ohc
.begin(),change_int_and_throw(1),change_int_and_throw(0));
560 BOOST_TEST(ohc
.size()==1);
567 ohc
.modify_key(ohc
.begin(),change_int(1),change_int_and_throw(0));
570 BOOST_TEST(ohc
.size()==1);
577 ohc
.modify_key(ohc
.begin(),change_int(1),change_int(1));
578 BOOST_TEST(ohc
.size()==1);