1/* Boost.MultiIndex test for modifier memfuns.
2 *
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)
7 *
8 * See http://www.boost.org/libs/multi_index for library home page.
9 */
10
11#include "test_modifiers.hpp"
12
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>
21#include <iterator>
22#include <vector>
23#include "pre_multi_index.hpp"
24#include "employee.hpp"
25
26using namespace boost::multi_index;
27
28struct non_copyable_int
29{
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)
33 {
34 n=x.n;
35 x.n=0;
36 return *this;
37 }
38
39 int n;
40private:
41 BOOST_MOVABLE_BUT_NOT_COPYABLE(non_copyable_int)
42};
43
44class always_one
45{
46public:
47 always_one():n(1){}
48 ~always_one(){n=0;}
49
50 int get()const{return n;}
51
52private:
53 int n;
54};
55
56inline bool operator==(const always_one& x,const always_one& y)
57{
58 return x.get()==y.get();
59}
60
61#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
62namespace boost{
63#endif
64
65inline std::size_t hash_value(const always_one& x)
66{
67 return static_cast<std::size_t>(x.get());
68}
69
70#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
71} /* namespace boost */
72#endif
73
74class linked_object
75{
76 struct impl:boost::enable_shared_from_this<impl>
77 {
78 typedef boost::shared_ptr<const impl> ptr;
79
80 impl(int n_,ptr next_=ptr()):n(n_),next(next_){}
81
82 int n;
83 ptr next;
84 };
85
86 typedef multi_index_container<
87 impl,
88 indexed_by<
89
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> >,
93#else
94 ordered_unique<member<impl,int,&impl::n> >,
95 hashed_non_unique<member<impl,int,&impl::n> >,
96#endif
97
98 sequenced<>,
99 random_access<>
100 >
101 > impl_repository_t;
102
103 static impl_repository_t impl_repository;
104
105public:
106 linked_object(int n):pimpl(init(x: impl(n))){}
107 linked_object(int n,const linked_object& x):pimpl(init(x: impl(n,x.pimpl))){}
108
109private:
110 impl::ptr init(const impl& x)
111 {
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();
115 }
116
117 static void erase_impl(const impl* p)
118 {
119 impl_repository.erase(x: p->n);
120 }
121
122 impl::ptr pimpl;
123};
124
125linked_object::impl_repository_t linked_object::impl_repository;
126
127struct tempvalue_iterator:
128 boost::iterator_facade<
129 tempvalue_iterator,int,boost::forward_traversal_tag,int>
130{
131 tempvalue_iterator(int n_):n(n_){}
132
133 void increment(){++n;}
134 bool equal(const tempvalue_iterator& x)const{return n==x.n;}
135 int dereference()const{return n;}
136
137 int n;
138};
139
140struct change_int
141{
142 change_int(int n):n(n){}
143
144 void operator()(int& x)const{x=n;}
145
146 int n;
147};
148
149#if !(defined BOOST_NO_EXCEPTIONS)
150struct change_int_and_throw
151{
152 change_int_and_throw(int n):n(n){}
153
154 void operator()(int& x)const{x=n;throw 0;}
155
156 int n;
157};
158#endif
159
160void test_modifiers()
161{
162 employee_set es;
163 employee_set_by_name& i1=get<name>(m&: es);
164 employee_set_by_age& i2=get<age>(m&: es);
165 employee_set_as_inserted& i3=get<as_inserted>(m&: es);
166 employee_set_by_ssn& i4=get<ssn>(m&: es);
167 employee_set_randomly& i5=get<randomly>(m&: es);
168
169 es.insert(x: 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
174 ==false);
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);
179
180 employee_set_by_name::iterator it1=i1.find(k: "Joe");
181 i1.insert(position: it1,x: employee(1,"Joe Jr.",5,2563));
182 BOOST_TEST(es.size()==2);
183
184 employee_set_by_age::iterator it2=i2.find(x: 31);
185 i2.insert(position: it2,x: employee(2,"Grandda Joe",64,7881));
186 BOOST_TEST(es.size()==3);
187
188 employee_set_as_inserted::iterator it3=i3.begin();
189 i3.insert(position: it3,n: 100,x: employee(3,"Judy",39,6201));
190 BOOST_TEST((--it3)->ssn==6201);
191 BOOST_TEST(es.size()==4);
192
193 employee_set_randomly::iterator it5=i5.begin();
194 i5.insert(position: it5,n: 100,x: employee(4,"Jill",52,3379));
195 BOOST_TEST(i5.begin()->age==52);
196 BOOST_TEST(es.size()==5);
197
198 es.erase(x: employee(1,"Joe Jr.",5,2563));
199 BOOST_TEST(i3.size()==4&&i5.size()==4);
200
201 BOOST_TEST(i1.erase("Judy")==1);
202 BOOST_TEST(es.size()==3&&i2.size()==3);
203
204 BOOST_TEST(i2.erase(it2)->age==52);
205 BOOST_TEST(i3.size()==2&&i4.size()==2);
206
207 i3.pop_front();
208 BOOST_TEST(i1.size()==1&&i2.size()==1);
209
210 i5.erase(first: i5.begin(),last: i5.end());
211 BOOST_TEST(es.size()==0&&i3.size()==0);
212
213 i5.emplace(position: i5.end(),args: 0,args: "Joe",args: 31,args: 1123);
214 BOOST_TEST(i1.erase(i1.begin())==i1.end());
215 BOOST_TEST(i1.size()==0);
216
217 i1.emplace(args: 0,args: "Joe",args: 31,args: 1123);
218 i3.emplace(position: i3.begin(),args: 1,args: "Jack",args: 31,args: 5032);
219 i4.emplace_hint(position: i4.end(),args: 2,args: "James",args: 31,args: 3847);
220 BOOST_TEST(i2.erase(31)==3);
221 BOOST_TEST(i2.size()==0);
222
223 i3.emplace_front(args: 1,args: "Jack",args: 31,args: 5032);
224 i3.emplace_back(args: 0,args: "Joe",args: 31,args: 1123);
225 BOOST_TEST(i3.front()==employee(1,"Jack",31,5032));
226 BOOST_TEST(i3.back()==employee(0,"Joe",31,1123));
227
228 i3.pop_back();
229 BOOST_TEST(i3.back()==employee(1,"Jack",31,5032));
230 BOOST_TEST(es.size()==1);
231
232 i3.pop_front();
233 BOOST_TEST(es.size()==0);
234
235 i5.push_back(x: employee(1,"Jack",31,5032));
236 i5.push_front(x: employee(0,"Joe",31,1123));
237 i5.insert(position: i5.end()-1,x: 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());
242
243 i5.pop_front();
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);
247
248 i5.pop_back();
249 BOOST_TEST(i5.back()==employee(2,"Grandda Joe",64,7881));
250 BOOST_TEST(i5.front()==i5.front());
251 BOOST_TEST(es.size()==1);
252
253 i5.erase(position: i5.begin());
254 BOOST_TEST(es.size()==0);
255
256 std::vector<employee> ve;
257 ve.push_back(x: employee(3,"Anna",31,5388));
258 ve.push_back(x: employee(1,"Rachel",27,9012));
259 ve.push_back(x: employee(2,"Agatha",40,1520));
260
261 i1.insert(first: ve.begin(),last: ve.end());
262 BOOST_TEST(i2.size()==3);
263
264#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
265 i1.insert(list: {{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
266 BOOST_TEST(i2.size()==5);
267#endif
268
269 BOOST_TEST(i2.erase(i2.begin(),i2.end())==i2.end());
270 BOOST_TEST(es.size()==0);
271
272 i2.insert(first: ve.begin(),last: ve.end());
273 BOOST_TEST(i3.size()==3);
274
275#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
276 i2.insert(list: {{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
277 BOOST_TEST(i3.size()==5);
278#endif
279
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);
283
284 i3.insert(position: i3.end(),first: ve.begin(),last: ve.end());
285 BOOST_TEST(es.size()==3);
286
287#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
288 i3.insert(position: i3.begin(),list: {{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
289 BOOST_TEST(i3.front().name=="Vanessa");
290 BOOST_TEST(i4.size()==5);
291#endif
292
293 BOOST_TEST(i4.erase(9012)==1);
294 i4.erase(position: i4.begin());
295 BOOST_TEST(i4.erase(i4.begin(),i4.end())==i4.end());
296
297 i4.insert(first: ve.begin(),last: ve.end());
298 BOOST_TEST(i5.size()==3);
299
300 BOOST_TEST(i5.erase(i5.begin(),i5.end())==i5.end());
301 BOOST_TEST(es.size()==0);
302
303 i5.insert(position: i5.begin(),first: ve.begin(),last: ve.end());
304 BOOST_TEST(i1.size()==3);
305
306#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
307 i5.insert(position: i5.end(),list: {{4,"Vanessa",20,9236},{5,"Penelope",55,2358}});
308 BOOST_TEST(i5.back().name=="Penelope");
309 BOOST_TEST(i1.size()==5);
310#endif
311
312 BOOST_TEST(es.erase(es.begin(),es.end())==es.end());
313 BOOST_TEST(i2.size()==0);
314
315 es.insert(x: employee(0,"Joe",31,1123));
316 es.insert(x: employee(1,"Robert",27,5601));
317 es.insert(x: employee(2,"John",40,7889));
318 es.insert(x: employee(3,"Albert",20,9012));
319 es.insert(x: employee(4,"John",57,1002));
320
321 employee_set es_backup(es);
322
323 employee_set es2;
324 es2.insert(x: employee(3,"Anna",31,5388));
325 es2.insert(x: employee(1,"Rachel",27,9012));
326 es2.insert(x: employee(2,"Agatha",40,1520));
327
328 employee_set es2_backup(es2);
329
330 i1.swap(x&: get<1>(m&: es2));
331 BOOST_TEST(es==es2_backup&&es2==es_backup);
332
333 i2.swap(x&: get<2>(m&: es2));
334 BOOST_TEST(es==es_backup&&es2==es2_backup);
335
336 i3.swap(x&: get<3>(m&: es2));
337 BOOST_TEST(es==es2_backup&&es2==es_backup);
338
339 i4.swap(x&: get<4>(m&: es2));
340 BOOST_TEST(es==es_backup&&es2==es2_backup);
341
342 i5.swap(x&: get<5>(m&: es2));
343 BOOST_TEST(es==es2_backup&&es2==es_backup);
344
345#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
346 ::boost::multi_index::detail::swap(i1,get<1>(es2));
347#else
348 using std::swap;
349 swap(x&: i1,y&: get<1>(m&: es2));
350#endif
351
352 BOOST_TEST(es==es_backup&&es2==es2_backup);
353
354#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
355 ::boost::multi_index::detail::swap(i2,get<2>(es2));
356#else
357 using std::swap;
358 swap(x&: i2,y&: get<2>(m&: es2));
359#endif
360
361 BOOST_TEST(es==es2_backup&&es2==es_backup);
362
363#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
364 ::boost::multi_index::detail::swap(i3,get<3>(es2));
365#else
366 using std::swap;
367 swap(x&: i3,y&: get<3>(m&: es2));
368#endif
369
370 BOOST_TEST(es==es_backup&&es2==es2_backup);
371
372#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
373 ::boost::multi_index::detail::swap(i4,get<4>(es2));
374#else
375 using std::swap;
376 swap(x&: i4,y&: get<4>(m&: es2));
377#endif
378
379 BOOST_TEST(es==es2_backup&&es2==es_backup);
380
381#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL)
382 ::boost::multi_index::detail::swap(i5,get<5>(es2));
383#else
384 using std::swap;
385 swap(x&: i5,y&: get<5>(m&: es2));
386#endif
387
388 BOOST_TEST(es==es_backup&&es2==es2_backup);
389
390 i3.clear();
391 BOOST_TEST(i3.size()==0);
392
393 es=es2;
394 i4.clear();
395 BOOST_TEST(i4.size()==0);
396
397 es=es2;
398 i5.clear();
399 BOOST_TEST(i5.size()==0);
400
401 es2.clear();
402 BOOST_TEST(es2.size()==0);
403
404 /* non-copyable elements */
405
406 multi_index_container<
407 non_copyable_int,
408 indexed_by<
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> >,
411 sequenced<>,
412 random_access<>
413 >
414 > ncic,ncic2;
415
416 ncic.emplace(args: 1);
417 get<1>(m&: ncic).emplace(args: 1);
418 get<2>(m&: ncic).emplace_back(args: 1);
419 get<3>(m&: ncic).emplace_back(args: 1);
420
421 non_copyable_int nci(1);
422 ncic.insert(x: boost::move(t&: nci));
423 BOOST_TEST(nci.n==0);
424
425 nci.n=1;
426 get<1>(m&: ncic).insert(x: boost::move(t&: nci));
427 BOOST_TEST(nci.n==0);
428
429 nci.n=1;
430 get<2>(m&: ncic).push_back(x: boost::move(t&: nci));
431 BOOST_TEST(nci.n==0);
432
433 nci.n=1;
434 get<3>(m&: ncic).push_back(x: boost::move(t&: nci));
435 BOOST_TEST(nci.n==0);
436
437 std::vector<int> vi(4,1);
438 const std::vector<int>& cvi=vi;
439 ncic.insert(first: vi.begin(),last: vi.end());
440 ncic.insert(first: cvi.begin(),last: cvi.end());
441 get<2>(m&: ncic).insert(position: get<2>(m&: ncic).begin(),first: vi.begin(),last: vi.end());
442 get<2>(m&: ncic).insert(position: get<2>(m&: ncic).begin(),first: cvi.begin(),last: cvi.end());
443
444 BOOST_TEST(ncic.count(1)==24);
445
446 ncic.swap(x&: ncic2);
447 BOOST_TEST(ncic.empty());
448 BOOST_TEST(ncic2.count(1)==24);
449
450 /* testcase for problem reported at
451 * http://lists.boost.org/boost-users/2006/12/24215.php
452 */
453
454 multi_index_container<
455 always_one,
456 indexed_by<
457 hashed_non_unique<identity<always_one> >
458 >
459 > aoc;
460
461 aoc.insert(x: always_one());
462 aoc.insert(x: always_one());
463 aoc.erase(k: *(aoc.begin()));
464 BOOST_TEST(aoc.empty());
465
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
470 */
471
472 typedef multi_index_container<
473 int,
474 indexed_by<
475 ordered_non_unique<identity<int> >
476 >
477 > int_non_unique_container;
478
479 int_non_unique_container c;
480 c.insert(x: 0);c.insert(x: 0);
481 c.insert(x: 1);c.insert(x: 1);
482 c.insert(x: 2);c.insert(x: 2);
483
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);
487 BOOST_TEST(
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);
492
493 /* testcase for erase() reentrancy */
494 {
495 linked_object o1(1);
496 linked_object o2(2,o1);
497 o1=o2;
498 }
499
500 /* testcases for bug reported at
501 * https://svn.boost.org/trac/boost/ticket/9665
502 */
503
504 {
505 multi_index_container<
506 int,
507 indexed_by<hashed_unique<identity<int> > >
508 > hc;
509 hc.insert(first: tempvalue_iterator(0),last: tempvalue_iterator(10));
510 BOOST_TEST(hc.size()==10);
511
512 multi_index_container<
513 int,
514 indexed_by<ordered_unique<identity<int> > >
515 > oc;
516 oc.insert(first: tempvalue_iterator(0),last: tempvalue_iterator(10));
517 BOOST_TEST(oc.size()==10);
518 }
519
520 /* testcases for https://svn.boost.org/trac10/ticket/12542 */
521
522 {
523 multi_index_container<
524 int,
525 indexed_by<
526 ordered_unique<identity<int> >,
527 hashed_unique<identity<int> >
528 >
529 > ohc;
530
531#if !(defined BOOST_NO_EXCEPTIONS)
532 ohc.insert(x: 0);
533 ohc.insert(x: 1);
534
535 try{
536 ohc.modify_key(position: ohc.begin(),mod: change_int_and_throw(1));
537 }
538 catch(int){}
539 BOOST_TEST(ohc.size()==1);
540 ohc.clear();
541
542 ohc.insert(x: 0);
543 ohc.insert(x: 1);
544
545 try{
546 ohc.modify_key(position: ohc.begin(),mod: change_int_and_throw(1),back_: change_int(0));
547 }
548 catch(int){}
549 BOOST_TEST(ohc.size()==1);
550 ohc.clear();
551
552 ohc.insert(x: 0);
553 ohc.insert(x: 1);
554
555 try{
556 ohc.modify_key(
557 position: ohc.begin(),mod: change_int_and_throw(1),back_: change_int_and_throw(0));
558 }
559 catch(int){}
560 BOOST_TEST(ohc.size()==1);
561 ohc.clear();
562
563 ohc.insert(x: 0);
564 ohc.insert(x: 1);
565
566 try{
567 ohc.modify_key(position: ohc.begin(),mod: change_int(1),back_: change_int_and_throw(0));
568 }
569 catch(int){}
570 BOOST_TEST(ohc.size()==1);
571 ohc.clear();
572#endif
573
574 ohc.insert(x: 0);
575 ohc.insert(x: 1);
576
577 ohc.modify_key(position: ohc.begin(),mod: change_int(1),back_: change_int(1));
578 BOOST_TEST(ohc.size()==1);
579 ohc.clear();
580 }
581}
582

source code of boost/libs/multi_index/test/test_modifiers.cpp