blob: b50bdbc90a69755c2b795ac92546d0b616abca99 [file] [log] [blame]
Brian Silverman3cbbaca2018-08-04 23:38:07 -07001/* Multiply indexed container.
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#ifndef BOOST_MULTI_INDEX_HPP
12#define BOOST_MULTI_INDEX_HPP
13
14#if defined(_MSC_VER)
15#pragma once
16#endif
17
18#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
19#include <algorithm>
20#include <memory>
21#include <boost/core/addressof.hpp>
22#include <boost/detail/allocator_utilities.hpp>
23#include <boost/detail/no_exceptions_support.hpp>
24#include <boost/detail/workaround.hpp>
25#include <boost/move/core.hpp>
26#include <boost/mpl/at.hpp>
27#include <boost/mpl/contains.hpp>
28#include <boost/mpl/find_if.hpp>
29#include <boost/mpl/identity.hpp>
30#include <boost/mpl/int.hpp>
31#include <boost/mpl/size.hpp>
32#include <boost/mpl/deref.hpp>
33#include <boost/multi_index_container_fwd.hpp>
34#include <boost/multi_index/detail/access_specifier.hpp>
35#include <boost/multi_index/detail/adl_swap.hpp>
36#include <boost/multi_index/detail/base_type.hpp>
37#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
38#include <boost/multi_index/detail/converter.hpp>
39#include <boost/multi_index/detail/header_holder.hpp>
40#include <boost/multi_index/detail/has_tag.hpp>
41#include <boost/multi_index/detail/no_duplicate_tags.hpp>
42#include <boost/multi_index/detail/safe_mode.hpp>
43#include <boost/multi_index/detail/scope_guard.hpp>
44#include <boost/multi_index/detail/vartempl_support.hpp>
45#include <boost/static_assert.hpp>
46#include <boost/type_traits/is_same.hpp>
47#include <boost/utility/base_from_member.hpp>
48
49#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
50#include <initializer_list>
51#endif
52
53#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
54#include <boost/multi_index/detail/archive_constructed.hpp>
55#include <boost/multi_index/detail/serialization_version.hpp>
56#include <boost/serialization/collection_size_type.hpp>
57#include <boost/serialization/nvp.hpp>
58#include <boost/serialization/split_member.hpp>
59#include <boost/serialization/version.hpp>
60#include <boost/throw_exception.hpp>
61#endif
62
63#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
64#include <boost/multi_index/detail/invariant_assert.hpp>
65#define BOOST_MULTI_INDEX_CHECK_INVARIANT_OF(x) \
66 detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \
67 detail::make_obj_guard(x,&multi_index_container::check_invariant_); \
68 BOOST_JOIN(check_invariant_,__LINE__).touch();
69#define BOOST_MULTI_INDEX_CHECK_INVARIANT \
70 BOOST_MULTI_INDEX_CHECK_INVARIANT_OF(*this)
71#else
72#define BOOST_MULTI_INDEX_CHECK_INVARIANT_OF(x)
73#define BOOST_MULTI_INDEX_CHECK_INVARIANT
74#endif
75
76namespace boost{
77
78namespace multi_index{
79
80#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
81#pragma warning(push)
82#pragma warning(disable:4522) /* spurious warning on multiple operator=()'s */
83#endif
84
85template<typename Value,typename IndexSpecifierList,typename Allocator>
86class multi_index_container:
87 private ::boost::base_from_member<
88 typename boost::detail::allocator::rebind_to<
89 Allocator,
90 typename detail::multi_index_node_type<
91 Value,IndexSpecifierList,Allocator>::type
92 >::type>,
93 BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS detail::header_holder<
94#ifndef BOOST_NO_CXX11_ALLOCATOR
95 typename std::allocator_traits<
96#endif
97 typename boost::detail::allocator::rebind_to<
98 Allocator,
99 typename detail::multi_index_node_type<
100 Value,IndexSpecifierList,Allocator>::type
101 >::type
102#ifdef BOOST_NO_CXX11_ALLOCATOR
103 ::pointer,
104#else
105 >::pointer,
106#endif
107 multi_index_container<Value,IndexSpecifierList,Allocator> >,
108 public detail::multi_index_base_type<
109 Value,IndexSpecifierList,Allocator>::type
110{
111#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
112 BOOST_WORKAROUND(__MWERKS__,<=0x3003)
113/* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
114 * lifetime of const references bound to temporaries --precisely what
115 * scopeguards are.
116 */
117
118#pragma parse_mfunc_templ off
119#endif
120
121private:
122 BOOST_COPYABLE_AND_MOVABLE(multi_index_container)
123
124#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
125 template <typename,typename,typename> friend class detail::index_base;
126 template <typename,typename> friend struct detail::header_holder;
127 template <typename,typename> friend struct detail::converter;
128#endif
129
130 typedef typename detail::multi_index_base_type<
131 Value,IndexSpecifierList,Allocator>::type super;
132 typedef typename
133 boost::detail::allocator::rebind_to<
134 Allocator,
135 typename super::node_type
136 >::type node_allocator;
137#ifdef BOOST_NO_CXX11_ALLOCATOR
138 typedef typename node_allocator::pointer node_pointer;
139#else
140 typedef std::allocator_traits<node_allocator> node_allocator_traits;
141 typedef typename node_allocator_traits::pointer node_pointer;
142#endif
143 typedef ::boost::base_from_member<
144 node_allocator> bfm_allocator;
145 typedef detail::header_holder<
146 node_pointer,
147 multi_index_container> bfm_header;
148
149public:
150 /* All types are inherited from super, a few are explicitly
151 * brought forward here to save us some typename's.
152 */
153
154 typedef typename super::ctor_args_list ctor_args_list;
155 typedef IndexSpecifierList index_specifier_type_list;
156
157 typedef typename super::index_type_list index_type_list;
158
159 typedef typename super::iterator_type_list iterator_type_list;
160 typedef typename super::const_iterator_type_list const_iterator_type_list;
161 typedef typename super::value_type value_type;
162 typedef typename super::final_allocator_type allocator_type;
163 typedef typename super::iterator iterator;
164 typedef typename super::const_iterator const_iterator;
165
166 BOOST_STATIC_ASSERT(
167 detail::no_duplicate_tags_in_index_list<index_type_list>::value);
168
169 /* global project() needs to see this publicly */
170
171 typedef typename super::node_type node_type;
172
173 /* construct/copy/destroy */
174
175 multi_index_container():
176 bfm_allocator(allocator_type()),
177 super(ctor_args_list(),bfm_allocator::member),
178 node_count(0)
179 {
180 BOOST_MULTI_INDEX_CHECK_INVARIANT;
181 }
182
183 explicit multi_index_container(
184 const ctor_args_list& args_list,
185
186#if BOOST_WORKAROUND(__IBMCPP__,<=600)
187 /* VisualAge seems to have an ETI issue with the default value for
188 * argument al.
189 */
190
191 const allocator_type& al=
192 typename mpl::identity<multi_index_container>::type::
193 allocator_type()):
194#else
195 const allocator_type& al=allocator_type()):
196#endif
197
198 bfm_allocator(al),
199 super(args_list,bfm_allocator::member),
200 node_count(0)
201 {
202 BOOST_MULTI_INDEX_CHECK_INVARIANT;
203 }
204
205 explicit multi_index_container(const allocator_type& al):
206 bfm_allocator(al),
207 super(ctor_args_list(),bfm_allocator::member),
208 node_count(0)
209 {
210 BOOST_MULTI_INDEX_CHECK_INVARIANT;
211 }
212
213 template<typename InputIterator>
214 multi_index_container(
215 InputIterator first,InputIterator last,
216
217#if BOOST_WORKAROUND(__IBMCPP__,<=600)
218 /* VisualAge seems to have an ETI issue with the default values
219 * for arguments args_list and al.
220 */
221
222 const ctor_args_list& args_list=
223 typename mpl::identity<multi_index_container>::type::
224 ctor_args_list(),
225 const allocator_type& al=
226 typename mpl::identity<multi_index_container>::type::
227 allocator_type()):
228#else
229 const ctor_args_list& args_list=ctor_args_list(),
230 const allocator_type& al=allocator_type()):
231#endif
232
233 bfm_allocator(al),
234 super(args_list,bfm_allocator::member),
235 node_count(0)
236 {
237 BOOST_MULTI_INDEX_CHECK_INVARIANT;
238 BOOST_TRY{
239 iterator hint=super::end();
240 for(;first!=last;++first){
241 hint=super::make_iterator(
242 insert_ref_(*first,hint.get_node()).first);
243 ++hint;
244 }
245 }
246 BOOST_CATCH(...){
247 clear_();
248 BOOST_RETHROW;
249 }
250 BOOST_CATCH_END
251 }
252
253#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
254 multi_index_container(
255 std::initializer_list<Value> list,
256 const ctor_args_list& args_list=ctor_args_list(),
257 const allocator_type& al=allocator_type()):
258 bfm_allocator(al),
259 super(args_list,bfm_allocator::member),
260 node_count(0)
261 {
262 BOOST_MULTI_INDEX_CHECK_INVARIANT;
263 BOOST_TRY{
264 typedef const Value* init_iterator;
265
266 iterator hint=super::end();
267 for(init_iterator first=list.begin(),last=list.end();
268 first!=last;++first){
269 hint=super::make_iterator(insert_(*first,hint.get_node()).first);
270 ++hint;
271 }
272 }
273 BOOST_CATCH(...){
274 clear_();
275 BOOST_RETHROW;
276 }
277 BOOST_CATCH_END
278 }
279#endif
280
281 multi_index_container(
282 const multi_index_container<Value,IndexSpecifierList,Allocator>& x):
283 bfm_allocator(x.bfm_allocator::member),
284 bfm_header(),
285 super(x),
286 node_count(0)
287 {
288 copy_map_type map(bfm_allocator::member,x.size(),x.header(),header());
289 for(const_iterator it=x.begin(),it_end=x.end();it!=it_end;++it){
290 map.clone(it.get_node());
291 }
292 super::copy_(x,map);
293 map.release();
294 node_count=x.size();
295
296 /* Not until this point are the indices required to be consistent,
297 * hence the position of the invariant checker.
298 */
299
300 BOOST_MULTI_INDEX_CHECK_INVARIANT;
301 }
302
303 multi_index_container(BOOST_RV_REF(multi_index_container) x):
304 bfm_allocator(x.bfm_allocator::member),
305 bfm_header(),
306 super(x,detail::do_not_copy_elements_tag()),
307 node_count(0)
308 {
309 BOOST_MULTI_INDEX_CHECK_INVARIANT;
310 BOOST_MULTI_INDEX_CHECK_INVARIANT_OF(x);
311 swap_elements_(x);
312 }
313
314 ~multi_index_container()
315 {
316 delete_all_nodes_();
317 }
318
319#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
320 /* As per http://www.boost.org/doc/html/move/emulation_limitations.html
321 * #move.emulation_limitations.assignment_operator
322 */
323
324 multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
325 const multi_index_container<Value,IndexSpecifierList,Allocator>& x)
326 {
327 multi_index_container y(x);
328 this->swap(y);
329 return *this;
330 }
331#endif
332
333 multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
334 BOOST_COPY_ASSIGN_REF(multi_index_container) x)
335 {
336 multi_index_container y(x);
337 this->swap(y);
338 return *this;
339 }
340
341 multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
342 BOOST_RV_REF(multi_index_container) x)
343 {
344 this->swap(x);
345 return *this;
346 }
347
348#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
349 multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
350 std::initializer_list<Value> list)
351 {
352 BOOST_MULTI_INDEX_CHECK_INVARIANT;
353 typedef const Value* init_iterator;
354
355 multi_index_container x(*this,detail::do_not_copy_elements_tag());
356 iterator hint=x.end();
357 for(init_iterator first=list.begin(),last=list.end();
358 first!=last;++first){
359 hint=x.make_iterator(x.insert_(*first,hint.get_node()).first);
360 ++hint;
361 }
362 x.swap_elements_(*this);
363 return*this;
364 }
365#endif
366
367 allocator_type get_allocator()const BOOST_NOEXCEPT
368 {
369 return allocator_type(bfm_allocator::member);
370 }
371
372 /* retrieval of indices by number */
373
374#if !defined(BOOST_NO_MEMBER_TEMPLATES)
375 template<int N>
376 struct nth_index
377 {
378 BOOST_STATIC_ASSERT(N>=0&&N<mpl::size<index_type_list>::type::value);
379 typedef typename mpl::at_c<index_type_list,N>::type type;
380 };
381
382 template<int N>
383 typename nth_index<N>::type& get()BOOST_NOEXCEPT
384 {
385 BOOST_STATIC_ASSERT(N>=0&&N<mpl::size<index_type_list>::type::value);
386 return *this;
387 }
388
389 template<int N>
390 const typename nth_index<N>::type& get()const BOOST_NOEXCEPT
391 {
392 BOOST_STATIC_ASSERT(N>=0&&N<mpl::size<index_type_list>::type::value);
393 return *this;
394 }
395#endif
396
397 /* retrieval of indices by tag */
398
399#if !defined(BOOST_NO_MEMBER_TEMPLATES)
400 template<typename Tag>
401 struct index
402 {
403 typedef typename mpl::find_if<
404 index_type_list,
405 detail::has_tag<Tag>
406 >::type iter;
407
408 BOOST_STATIC_CONSTANT(
409 bool,index_found=!(is_same<iter,typename mpl::end<index_type_list>::type >::value));
410 BOOST_STATIC_ASSERT(index_found);
411
412 typedef typename mpl::deref<iter>::type type;
413 };
414
415 template<typename Tag>
416 typename index<Tag>::type& get()BOOST_NOEXCEPT
417 {
418 return *this;
419 }
420
421 template<typename Tag>
422 const typename index<Tag>::type& get()const BOOST_NOEXCEPT
423 {
424 return *this;
425 }
426#endif
427
428 /* projection of iterators by number */
429
430#if !defined(BOOST_NO_MEMBER_TEMPLATES)
431 template<int N>
432 struct nth_index_iterator
433 {
434 typedef typename nth_index<N>::type::iterator type;
435 };
436
437 template<int N>
438 struct nth_index_const_iterator
439 {
440 typedef typename nth_index<N>::type::const_iterator type;
441 };
442
443 template<int N,typename IteratorType>
444 typename nth_index_iterator<N>::type project(IteratorType it)
445 {
446 typedef typename nth_index<N>::type index_type;
447
448#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* fails in Sun C++ 5.7 */
449 BOOST_STATIC_ASSERT(
450 (mpl::contains<iterator_type_list,IteratorType>::value));
451#endif
452
453 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
454 BOOST_MULTI_INDEX_CHECK_IS_OWNER(
455 it,static_cast<typename IteratorType::container_type&>(*this));
456
457 return index_type::make_iterator(static_cast<node_type*>(it.get_node()));
458 }
459
460 template<int N,typename IteratorType>
461 typename nth_index_const_iterator<N>::type project(IteratorType it)const
462 {
463 typedef typename nth_index<N>::type index_type;
464
465#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* fails in Sun C++ 5.7 */
466 BOOST_STATIC_ASSERT((
467 mpl::contains<iterator_type_list,IteratorType>::value||
468 mpl::contains<const_iterator_type_list,IteratorType>::value));
469#endif
470
471 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
472 BOOST_MULTI_INDEX_CHECK_IS_OWNER(
473 it,static_cast<const typename IteratorType::container_type&>(*this));
474 return index_type::make_iterator(static_cast<node_type*>(it.get_node()));
475 }
476#endif
477
478 /* projection of iterators by tag */
479
480#if !defined(BOOST_NO_MEMBER_TEMPLATES)
481 template<typename Tag>
482 struct index_iterator
483 {
484 typedef typename index<Tag>::type::iterator type;
485 };
486
487 template<typename Tag>
488 struct index_const_iterator
489 {
490 typedef typename index<Tag>::type::const_iterator type;
491 };
492
493 template<typename Tag,typename IteratorType>
494 typename index_iterator<Tag>::type project(IteratorType it)
495 {
496 typedef typename index<Tag>::type index_type;
497
498#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* fails in Sun C++ 5.7 */
499 BOOST_STATIC_ASSERT(
500 (mpl::contains<iterator_type_list,IteratorType>::value));
501#endif
502
503 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
504 BOOST_MULTI_INDEX_CHECK_IS_OWNER(
505 it,static_cast<typename IteratorType::container_type&>(*this));
506 return index_type::make_iterator(static_cast<node_type*>(it.get_node()));
507 }
508
509 template<typename Tag,typename IteratorType>
510 typename index_const_iterator<Tag>::type project(IteratorType it)const
511 {
512 typedef typename index<Tag>::type index_type;
513
514#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* fails in Sun C++ 5.7 */
515 BOOST_STATIC_ASSERT((
516 mpl::contains<iterator_type_list,IteratorType>::value||
517 mpl::contains<const_iterator_type_list,IteratorType>::value));
518#endif
519
520 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
521 BOOST_MULTI_INDEX_CHECK_IS_OWNER(
522 it,static_cast<const typename IteratorType::container_type&>(*this));
523 return index_type::make_iterator(static_cast<node_type*>(it.get_node()));
524 }
525#endif
526
527BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
528 typedef typename super::copy_map_type copy_map_type;
529
530#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
531 multi_index_container(
532 const multi_index_container<Value,IndexSpecifierList,Allocator>& x,
533 detail::do_not_copy_elements_tag):
534 bfm_allocator(x.bfm_allocator::member),
535 bfm_header(),
536 super(x,detail::do_not_copy_elements_tag()),
537 node_count(0)
538 {
539 BOOST_MULTI_INDEX_CHECK_INVARIANT;
540 }
541#endif
542
543 node_type* header()const
544 {
545 return &*bfm_header::member;
546 }
547
548 node_type* allocate_node()
549 {
550#ifdef BOOST_NO_CXX11_ALLOCATOR
551 return &*bfm_allocator::member.allocate(1);
552#else
553 return &*node_allocator_traits::allocate(bfm_allocator::member,1);
554#endif
555 }
556
557 void deallocate_node(node_type* x)
558 {
559#ifdef BOOST_NO_CXX11_ALLOCATOR
560 bfm_allocator::member.deallocate(static_cast<node_pointer>(x),1);
561#else
562 node_allocator_traits::deallocate(bfm_allocator::member,static_cast<node_pointer>(x),1);
563#endif
564 }
565
566 bool empty_()const
567 {
568 return node_count==0;
569 }
570
571 std::size_t size_()const
572 {
573 return node_count;
574 }
575
576 std::size_t max_size_()const
577 {
578 return static_cast<std::size_t >(-1);
579 }
580
581 template<typename Variant>
582 std::pair<node_type*,bool> insert_(const Value& v,Variant variant)
583 {
584 node_type* x=0;
585 node_type* res=super::insert_(v,x,variant);
586 if(res==x){
587 ++node_count;
588 return std::pair<node_type*,bool>(res,true);
589 }
590 else{
591 return std::pair<node_type*,bool>(res,false);
592 }
593 }
594
595 std::pair<node_type*,bool> insert_(const Value& v)
596 {
597 return insert_(v,detail::lvalue_tag());
598 }
599
600 std::pair<node_type*,bool> insert_rv_(const Value& v)
601 {
602 return insert_(v,detail::rvalue_tag());
603 }
604
605 template<typename T>
606 std::pair<node_type*,bool> insert_ref_(T& t)
607 {
608 node_type* x=allocate_node();
609 BOOST_TRY{
610 new(boost::addressof(x->value())) value_type(t);
611 BOOST_TRY{
612 node_type* res=super::insert_(x->value(),x,detail::emplaced_tag());
613 if(res==x){
614 ++node_count;
615 return std::pair<node_type*,bool>(res,true);
616 }
617 else{
618 boost::detail::allocator::destroy(boost::addressof(x->value()));
619 deallocate_node(x);
620 return std::pair<node_type*,bool>(res,false);
621 }
622 }
623 BOOST_CATCH(...){
624 boost::detail::allocator::destroy(boost::addressof(x->value()));
625 BOOST_RETHROW;
626 }
627 BOOST_CATCH_END
628 }
629 BOOST_CATCH(...){
630 deallocate_node(x);
631 BOOST_RETHROW;
632 }
633 BOOST_CATCH_END
634 }
635
636 std::pair<node_type*,bool> insert_ref_(const value_type& x)
637 {
638 return insert_(x);
639 }
640
641 std::pair<node_type*,bool> insert_ref_(value_type& x)
642 {
643 return insert_(x);
644 }
645
646 template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
647 std::pair<node_type*,bool> emplace_(
648 BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
649 {
650 node_type* x=allocate_node();
651 BOOST_TRY{
652 detail::vartempl_placement_new(
653 boost::addressof(x->value()),BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
654 BOOST_TRY{
655 node_type* res=super::insert_(x->value(),x,detail::emplaced_tag());
656 if(res==x){
657 ++node_count;
658 return std::pair<node_type*,bool>(res,true);
659 }
660 else{
661 boost::detail::allocator::destroy(boost::addressof(x->value()));
662 deallocate_node(x);
663 return std::pair<node_type*,bool>(res,false);
664 }
665 }
666 BOOST_CATCH(...){
667 boost::detail::allocator::destroy(boost::addressof(x->value()));
668 BOOST_RETHROW;
669 }
670 BOOST_CATCH_END
671 }
672 BOOST_CATCH(...){
673 deallocate_node(x);
674 BOOST_RETHROW;
675 }
676 BOOST_CATCH_END
677 }
678
679 template<typename Variant>
680 std::pair<node_type*,bool> insert_(
681 const Value& v,node_type* position,Variant variant)
682 {
683 node_type* x=0;
684 node_type* res=super::insert_(v,position,x,variant);
685 if(res==x){
686 ++node_count;
687 return std::pair<node_type*,bool>(res,true);
688 }
689 else{
690 return std::pair<node_type*,bool>(res,false);
691 }
692 }
693
694 std::pair<node_type*,bool> insert_(const Value& v,node_type* position)
695 {
696 return insert_(v,position,detail::lvalue_tag());
697 }
698
699 std::pair<node_type*,bool> insert_rv_(const Value& v,node_type* position)
700 {
701 return insert_(v,position,detail::rvalue_tag());
702 }
703
704 template<typename T>
705 std::pair<node_type*,bool> insert_ref_(
706 T& t,node_type* position)
707 {
708 node_type* x=allocate_node();
709 BOOST_TRY{
710 new(boost::addressof(x->value())) value_type(t);
711 BOOST_TRY{
712 node_type* res=super::insert_(
713 x->value(),position,x,detail::emplaced_tag());
714 if(res==x){
715 ++node_count;
716 return std::pair<node_type*,bool>(res,true);
717 }
718 else{
719 boost::detail::allocator::destroy(boost::addressof(x->value()));
720 deallocate_node(x);
721 return std::pair<node_type*,bool>(res,false);
722 }
723 }
724 BOOST_CATCH(...){
725 boost::detail::allocator::destroy(boost::addressof(x->value()));
726 BOOST_RETHROW;
727 }
728 BOOST_CATCH_END
729 }
730 BOOST_CATCH(...){
731 deallocate_node(x);
732 BOOST_RETHROW;
733 }
734 BOOST_CATCH_END
735 }
736
737 std::pair<node_type*,bool> insert_ref_(
738 const value_type& x,node_type* position)
739 {
740 return insert_(x,position);
741 }
742
743 std::pair<node_type*,bool> insert_ref_(
744 value_type& x,node_type* position)
745 {
746 return insert_(x,position);
747 }
748
749 template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
750 std::pair<node_type*,bool> emplace_hint_(
751 node_type* position,
752 BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
753 {
754 node_type* x=allocate_node();
755 BOOST_TRY{
756 detail::vartempl_placement_new(
757 boost::addressof(x->value()),BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
758 BOOST_TRY{
759 node_type* res=super::insert_(
760 x->value(),position,x,detail::emplaced_tag());
761 if(res==x){
762 ++node_count;
763 return std::pair<node_type*,bool>(res,true);
764 }
765 else{
766 boost::detail::allocator::destroy(boost::addressof(x->value()));
767 deallocate_node(x);
768 return std::pair<node_type*,bool>(res,false);
769 }
770 }
771 BOOST_CATCH(...){
772 boost::detail::allocator::destroy(boost::addressof(x->value()));
773 BOOST_RETHROW;
774 }
775 BOOST_CATCH_END
776 }
777 BOOST_CATCH(...){
778 deallocate_node(x);
779 BOOST_RETHROW;
780 }
781 BOOST_CATCH_END
782 }
783
784 void erase_(node_type* x)
785 {
786 --node_count;
787 super::erase_(x);
788 deallocate_node(x);
789 }
790
791 void delete_node_(node_type* x)
792 {
793 super::delete_node_(x);
794 deallocate_node(x);
795 }
796
797 void delete_all_nodes_()
798 {
799 super::delete_all_nodes_();
800 }
801
802 void clear_()
803 {
804 delete_all_nodes_();
805 super::clear_();
806 node_count=0;
807 }
808
809 void swap_(multi_index_container<Value,IndexSpecifierList,Allocator>& x)
810 {
811 if(bfm_allocator::member!=x.bfm_allocator::member){
812 detail::adl_swap(bfm_allocator::member,x.bfm_allocator::member);
813 }
814 std::swap(bfm_header::member,x.bfm_header::member);
815 super::swap_(x);
816 std::swap(node_count,x.node_count);
817 }
818
819 void swap_elements_(
820 multi_index_container<Value,IndexSpecifierList,Allocator>& x)
821 {
822 std::swap(bfm_header::member,x.bfm_header::member);
823 super::swap_elements_(x);
824 std::swap(node_count,x.node_count);
825 }
826
827 bool replace_(const Value& k,node_type* x)
828 {
829 return super::replace_(k,x,detail::lvalue_tag());
830 }
831
832 bool replace_rv_(const Value& k,node_type* x)
833 {
834 return super::replace_(k,x,detail::rvalue_tag());
835 }
836
837 template<typename Modifier>
838 bool modify_(Modifier& mod,node_type* x)
839 {
840 BOOST_TRY{
841 mod(const_cast<value_type&>(x->value()));
842 }
843 BOOST_CATCH(...){
844 this->erase_(x);
845 BOOST_RETHROW;
846 }
847 BOOST_CATCH_END
848
849 BOOST_TRY{
850 if(!super::modify_(x)){
851 deallocate_node(x);
852 --node_count;
853 return false;
854 }
855 else return true;
856 }
857 BOOST_CATCH(...){
858 deallocate_node(x);
859 --node_count;
860 BOOST_RETHROW;
861 }
862 BOOST_CATCH_END
863 }
864
865 template<typename Modifier,typename Rollback>
866 bool modify_(Modifier& mod,Rollback& back_,node_type* x)
867 {
868 BOOST_TRY{
869 mod(const_cast<value_type&>(x->value()));
870 }
871 BOOST_CATCH(...){
872 this->erase_(x);
873 BOOST_RETHROW;
874 }
875 BOOST_CATCH_END
876
877 bool b;
878 BOOST_TRY{
879 b=super::modify_rollback_(x);
880 }
881 BOOST_CATCH(...){
882 BOOST_TRY{
883 back_(const_cast<value_type&>(x->value()));
884 if(!super::check_rollback_(x))this->erase_(x);
885 BOOST_RETHROW;
886 }
887 BOOST_CATCH(...){
888 this->erase_(x);
889 BOOST_RETHROW;
890 }
891 BOOST_CATCH_END
892 }
893 BOOST_CATCH_END
894
895 BOOST_TRY{
896 if(!b){
897 back_(const_cast<value_type&>(x->value()));
898 if(!super::check_rollback_(x))this->erase_(x);
899 return false;
900 }
901 else return true;
902 }
903 BOOST_CATCH(...){
904 this->erase_(x);
905 BOOST_RETHROW;
906 }
907 BOOST_CATCH_END
908 }
909
910#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
911 /* serialization */
912
913 friend class boost::serialization::access;
914
915 BOOST_SERIALIZATION_SPLIT_MEMBER()
916
917 typedef typename super::index_saver_type index_saver_type;
918 typedef typename super::index_loader_type index_loader_type;
919
920 template<class Archive>
921 void save(Archive& ar,const unsigned int version)const
922 {
923 const serialization::collection_size_type s(size_());
924 const detail::serialization_version<value_type> value_version;
925 ar<<serialization::make_nvp("count",s);
926 ar<<serialization::make_nvp("value_version",value_version);
927
928 index_saver_type sm(bfm_allocator::member,s);
929
930 for(iterator it=super::begin(),it_end=super::end();it!=it_end;++it){
931 serialization::save_construct_data_adl(
932 ar,boost::addressof(*it),value_version);
933 ar<<serialization::make_nvp("item",*it);
934 sm.add(it.get_node(),ar,version);
935 }
936 sm.add_track(header(),ar,version);
937
938 super::save_(ar,version,sm);
939 }
940
941 template<class Archive>
942 void load(Archive& ar,const unsigned int version)
943 {
944 BOOST_MULTI_INDEX_CHECK_INVARIANT;
945
946 clear_();
947 serialization::collection_size_type s;
948 detail::serialization_version<value_type> value_version;
949 if(version<1){
950 std::size_t sz;
951 ar>>serialization::make_nvp("count",sz);
952 s=static_cast<serialization::collection_size_type>(sz);
953 }
954 else{
955 ar>>serialization::make_nvp("count",s);
956 }
957 if(version<2){
958 value_version=0;
959 }
960 else{
961 ar>>serialization::make_nvp("value_version",value_version);
962 }
963
964 index_loader_type lm(bfm_allocator::member,s);
965
966 for(std::size_t n=0;n<s;++n){
967 detail::archive_constructed<Value> value("item",ar,value_version);
968 std::pair<node_type*,bool> p=insert_rv_(
969 value.get(),super::end().get_node());
970 if(!p.second)throw_exception(
971 archive::archive_exception(
972 archive::archive_exception::other_exception));
973 ar.reset_object_address(
974 boost::addressof(p.first->value()),boost::addressof(value.get()));
975 lm.add(p.first,ar,version);
976 }
977 lm.add_track(header(),ar,version);
978
979 super::load_(ar,version,lm);
980 }
981#endif
982
983#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
984 /* invariant stuff */
985
986 bool invariant_()const
987 {
988 return super::invariant_();
989 }
990
991 void check_invariant_()const
992 {
993 BOOST_MULTI_INDEX_INVARIANT_ASSERT(invariant_());
994 }
995#endif
996
997private:
998 std::size_t node_count;
999
1000#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
1001 BOOST_WORKAROUND(__MWERKS__,<=0x3003)
1002#pragma parse_mfunc_templ reset
1003#endif
1004};
1005
1006#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
1007#pragma warning(pop) /* C4522 */
1008#endif
1009
1010/* retrieval of indices by number */
1011
1012template<typename MultiIndexContainer,int N>
1013struct nth_index
1014{
1015 BOOST_STATIC_CONSTANT(
1016 int,
1017 M=mpl::size<typename MultiIndexContainer::index_type_list>::type::value);
1018 BOOST_STATIC_ASSERT(N>=0&&N<M);
1019 typedef typename mpl::at_c<
1020 typename MultiIndexContainer::index_type_list,N>::type type;
1021};
1022
1023template<int N,typename Value,typename IndexSpecifierList,typename Allocator>
1024typename nth_index<
1025 multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type&
1026get(
1027 multi_index_container<Value,IndexSpecifierList,Allocator>& m)BOOST_NOEXCEPT
1028{
1029 typedef multi_index_container<
1030 Value,IndexSpecifierList,Allocator> multi_index_type;
1031 typedef typename nth_index<
1032 multi_index_container<
1033 Value,IndexSpecifierList,Allocator>,
1034 N
1035 >::type index_type;
1036
1037 BOOST_STATIC_ASSERT(N>=0&&
1038 N<
1039 mpl::size<
1040 BOOST_DEDUCED_TYPENAME multi_index_type::index_type_list
1041 >::type::value);
1042
1043 return detail::converter<multi_index_type,index_type>::index(m);
1044}
1045
1046template<int N,typename Value,typename IndexSpecifierList,typename Allocator>
1047const typename nth_index<
1048 multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type&
1049get(
1050 const multi_index_container<Value,IndexSpecifierList,Allocator>& m
1051)BOOST_NOEXCEPT
1052{
1053 typedef multi_index_container<
1054 Value,IndexSpecifierList,Allocator> multi_index_type;
1055 typedef typename nth_index<
1056 multi_index_container<
1057 Value,IndexSpecifierList,Allocator>,
1058 N
1059 >::type index_type;
1060
1061 BOOST_STATIC_ASSERT(N>=0&&
1062 N<
1063 mpl::size<
1064 BOOST_DEDUCED_TYPENAME multi_index_type::index_type_list
1065 >::type::value);
1066
1067 return detail::converter<multi_index_type,index_type>::index(m);
1068}
1069
1070/* retrieval of indices by tag */
1071
1072template<typename MultiIndexContainer,typename Tag>
1073struct index
1074{
1075 typedef typename MultiIndexContainer::index_type_list index_type_list;
1076
1077 typedef typename mpl::find_if<
1078 index_type_list,
1079 detail::has_tag<Tag>
1080 >::type iter;
1081
1082 BOOST_STATIC_CONSTANT(
1083 bool,index_found=!(is_same<iter,typename mpl::end<index_type_list>::type >::value));
1084 BOOST_STATIC_ASSERT(index_found);
1085
1086 typedef typename mpl::deref<iter>::type type;
1087};
1088
1089template<
1090 typename Tag,typename Value,typename IndexSpecifierList,typename Allocator
1091>
1092typename ::boost::multi_index::index<
1093 multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type&
1094get(
1095 multi_index_container<Value,IndexSpecifierList,Allocator>& m)BOOST_NOEXCEPT
1096{
1097 typedef multi_index_container<
1098 Value,IndexSpecifierList,Allocator> multi_index_type;
1099 typedef typename ::boost::multi_index::index<
1100 multi_index_container<
1101 Value,IndexSpecifierList,Allocator>,
1102 Tag
1103 >::type index_type;
1104
1105 return detail::converter<multi_index_type,index_type>::index(m);
1106}
1107
1108template<
1109 typename Tag,typename Value,typename IndexSpecifierList,typename Allocator
1110>
1111const typename ::boost::multi_index::index<
1112 multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type&
1113get(
1114 const multi_index_container<Value,IndexSpecifierList,Allocator>& m
1115)BOOST_NOEXCEPT
1116{
1117 typedef multi_index_container<
1118 Value,IndexSpecifierList,Allocator> multi_index_type;
1119 typedef typename ::boost::multi_index::index<
1120 multi_index_container<
1121 Value,IndexSpecifierList,Allocator>,
1122 Tag
1123 >::type index_type;
1124
1125 return detail::converter<multi_index_type,index_type>::index(m);
1126}
1127
1128/* projection of iterators by number */
1129
1130template<typename MultiIndexContainer,int N>
1131struct nth_index_iterator
1132{
1133 typedef typename nth_index<MultiIndexContainer,N>::type::iterator type;
1134};
1135
1136template<typename MultiIndexContainer,int N>
1137struct nth_index_const_iterator
1138{
1139 typedef typename nth_index<MultiIndexContainer,N>::type::const_iterator type;
1140};
1141
1142template<
1143 int N,typename IteratorType,
1144 typename Value,typename IndexSpecifierList,typename Allocator>
1145typename nth_index_iterator<
1146 multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type
1147project(
1148 multi_index_container<Value,IndexSpecifierList,Allocator>& m,
1149 IteratorType it)
1150{
1151 typedef multi_index_container<
1152 Value,IndexSpecifierList,Allocator> multi_index_type;
1153 typedef typename nth_index<multi_index_type,N>::type index_type;
1154
1155#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* Sun C++ 5.7 fails */
1156 BOOST_STATIC_ASSERT((
1157 mpl::contains<
1158 BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
1159 IteratorType>::value));
1160#endif
1161
1162 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
1163
1164#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1165 typedef detail::converter<
1166 multi_index_type,
1167 BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
1168 BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
1169#endif
1170
1171 return detail::converter<multi_index_type,index_type>::iterator(
1172 m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
1173}
1174
1175template<
1176 int N,typename IteratorType,
1177 typename Value,typename IndexSpecifierList,typename Allocator>
1178typename nth_index_const_iterator<
1179 multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type
1180project(
1181 const multi_index_container<Value,IndexSpecifierList,Allocator>& m,
1182 IteratorType it)
1183{
1184 typedef multi_index_container<
1185 Value,IndexSpecifierList,Allocator> multi_index_type;
1186 typedef typename nth_index<multi_index_type,N>::type index_type;
1187
1188#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* Sun C++ 5.7 fails */
1189 BOOST_STATIC_ASSERT((
1190 mpl::contains<
1191 BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
1192 IteratorType>::value||
1193 mpl::contains<
1194 BOOST_DEDUCED_TYPENAME multi_index_type::const_iterator_type_list,
1195 IteratorType>::value));
1196#endif
1197
1198 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
1199
1200#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1201 typedef detail::converter<
1202 multi_index_type,
1203 BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
1204 BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
1205#endif
1206
1207 return detail::converter<multi_index_type,index_type>::const_iterator(
1208 m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
1209}
1210
1211/* projection of iterators by tag */
1212
1213template<typename MultiIndexContainer,typename Tag>
1214struct index_iterator
1215{
1216 typedef typename ::boost::multi_index::index<
1217 MultiIndexContainer,Tag>::type::iterator type;
1218};
1219
1220template<typename MultiIndexContainer,typename Tag>
1221struct index_const_iterator
1222{
1223 typedef typename ::boost::multi_index::index<
1224 MultiIndexContainer,Tag>::type::const_iterator type;
1225};
1226
1227template<
1228 typename Tag,typename IteratorType,
1229 typename Value,typename IndexSpecifierList,typename Allocator>
1230typename index_iterator<
1231 multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type
1232project(
1233 multi_index_container<Value,IndexSpecifierList,Allocator>& m,
1234 IteratorType it)
1235{
1236 typedef multi_index_container<
1237 Value,IndexSpecifierList,Allocator> multi_index_type;
1238 typedef typename ::boost::multi_index::index<
1239 multi_index_type,Tag>::type index_type;
1240
1241#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* Sun C++ 5.7 fails */
1242 BOOST_STATIC_ASSERT((
1243 mpl::contains<
1244 BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
1245 IteratorType>::value));
1246#endif
1247
1248 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
1249
1250#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1251 typedef detail::converter<
1252 multi_index_type,
1253 BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
1254 BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
1255#endif
1256
1257 return detail::converter<multi_index_type,index_type>::iterator(
1258 m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
1259}
1260
1261template<
1262 typename Tag,typename IteratorType,
1263 typename Value,typename IndexSpecifierList,typename Allocator>
1264typename index_const_iterator<
1265 multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type
1266project(
1267 const multi_index_container<Value,IndexSpecifierList,Allocator>& m,
1268 IteratorType it)
1269{
1270 typedef multi_index_container<
1271 Value,IndexSpecifierList,Allocator> multi_index_type;
1272 typedef typename ::boost::multi_index::index<
1273 multi_index_type,Tag>::type index_type;
1274
1275#if !defined(__SUNPRO_CC)||!(__SUNPRO_CC<0x580) /* Sun C++ 5.7 fails */
1276 BOOST_STATIC_ASSERT((
1277 mpl::contains<
1278 BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
1279 IteratorType>::value||
1280 mpl::contains<
1281 BOOST_DEDUCED_TYPENAME multi_index_type::const_iterator_type_list,
1282 IteratorType>::value));
1283#endif
1284
1285 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
1286
1287#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1288 typedef detail::converter<
1289 multi_index_type,
1290 BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
1291 BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
1292#endif
1293
1294 return detail::converter<multi_index_type,index_type>::const_iterator(
1295 m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
1296}
1297
1298/* Comparison. Simple forward to first index. */
1299
1300template<
1301 typename Value1,typename IndexSpecifierList1,typename Allocator1,
1302 typename Value2,typename IndexSpecifierList2,typename Allocator2
1303>
1304bool operator==(
1305 const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
1306 const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
1307{
1308 return get<0>(x)==get<0>(y);
1309}
1310
1311template<
1312 typename Value1,typename IndexSpecifierList1,typename Allocator1,
1313 typename Value2,typename IndexSpecifierList2,typename Allocator2
1314>
1315bool operator<(
1316 const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
1317 const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
1318{
1319 return get<0>(x)<get<0>(y);
1320}
1321
1322template<
1323 typename Value1,typename IndexSpecifierList1,typename Allocator1,
1324 typename Value2,typename IndexSpecifierList2,typename Allocator2
1325>
1326bool operator!=(
1327 const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
1328 const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
1329{
1330 return get<0>(x)!=get<0>(y);
1331}
1332
1333template<
1334 typename Value1,typename IndexSpecifierList1,typename Allocator1,
1335 typename Value2,typename IndexSpecifierList2,typename Allocator2
1336>
1337bool operator>(
1338 const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
1339 const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
1340{
1341 return get<0>(x)>get<0>(y);
1342}
1343
1344template<
1345 typename Value1,typename IndexSpecifierList1,typename Allocator1,
1346 typename Value2,typename IndexSpecifierList2,typename Allocator2
1347>
1348bool operator>=(
1349 const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
1350 const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
1351{
1352 return get<0>(x)>=get<0>(y);
1353}
1354
1355template<
1356 typename Value1,typename IndexSpecifierList1,typename Allocator1,
1357 typename Value2,typename IndexSpecifierList2,typename Allocator2
1358>
1359bool operator<=(
1360 const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
1361 const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
1362{
1363 return get<0>(x)<=get<0>(y);
1364}
1365
1366/* specialized algorithms */
1367
1368template<typename Value,typename IndexSpecifierList,typename Allocator>
1369void swap(
1370 multi_index_container<Value,IndexSpecifierList,Allocator>& x,
1371 multi_index_container<Value,IndexSpecifierList,Allocator>& y)
1372{
1373 x.swap(y);
1374}
1375
1376} /* namespace multi_index */
1377
1378#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
1379/* class version = 1 : we now serialize the size through
1380 * boost::serialization::collection_size_type.
1381 * class version = 2 : proper use of {save|load}_construct_data.
1382 */
1383
1384namespace serialization {
1385template<typename Value,typename IndexSpecifierList,typename Allocator>
1386struct version<
1387 boost::multi_index_container<Value,IndexSpecifierList,Allocator>
1388>
1389{
1390 BOOST_STATIC_CONSTANT(int,value=2);
1391};
1392} /* namespace serialization */
1393#endif
1394
1395/* Associated global functions are promoted to namespace boost, except
1396 * comparison operators and swap, which are meant to be Koenig looked-up.
1397 */
1398
1399using multi_index::get;
1400using multi_index::project;
1401
1402} /* namespace boost */
1403
1404#undef BOOST_MULTI_INDEX_CHECK_INVARIANT
1405#undef BOOST_MULTI_INDEX_CHECK_INVARIANT_OF
1406
1407#endif