1 /* Multiply indexed container.
2  *
3  * Copyright 2003-2005 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 #ifndef BOOST_MULTI_INDEX_HPP
12 #define BOOST_MULTI_INDEX_HPP
13 
14 #if defined(_MSC_VER)&&(_MSC_VER>=1200)
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 <boost/detail/allocator_utilities.hpp>
21 #include <boost/detail/no_exceptions_support.hpp>
22 #include <boost/detail/workaround.hpp>
23 #include <boost/mpl/at.hpp>
24 #include <boost/mpl/contains.hpp>
25 #include <boost/mpl/find_if.hpp>
26 #include <boost/mpl/identity.hpp>
27 #include <boost/mpl/int.hpp>
28 #include <boost/mpl/size.hpp>
29 #include <boost/mpl/deref.hpp>
30 #include <boost/multi_index_container_fwd.hpp>
31 #include <boost/multi_index/detail/access_specifier.hpp>
32 #include <boost/multi_index/detail/base_type.hpp>
33 #include <boost/multi_index/detail/converter.hpp>
34 #include <boost/multi_index/detail/def_ctor_tuple_cons.hpp>
35 #include <boost/multi_index/detail/header_holder.hpp>
36 #include <boost/multi_index/detail/has_tag.hpp>
37 #include <boost/multi_index/detail/no_duplicate_tags.hpp>
38 #include <boost/multi_index/detail/prevent_eti.hpp>
39 #include <boost/multi_index/detail/safe_mode.hpp>
40 #include <boost/multi_index/detail/scope_guard.hpp>
41 #include <boost/static_assert.hpp>
42 #include <boost/type_traits/is_same.hpp>
43 #include <boost/utility/base_from_member.hpp>
44 
45 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
46 #include <boost/multi_index/detail/archive_constructed.hpp>
47 #include <boost/serialization/nvp.hpp>
48 #include <boost/serialization/split_member.hpp>
49 #include <boost/throw_exception.hpp>
50 #endif
51 
52 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
53 #include <boost/multi_index/detail/invariant_assert.hpp>
54 #define BOOST_MULTI_INDEX_CHECK_INVARIANT                                    \
55   detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)=                 \
56     detail::make_obj_guard(*this,&multi_index_container::check_invariant_);  \
57   BOOST_JOIN(check_invariant_,__LINE__).touch();
58 #else
59 #define BOOST_MULTI_INDEX_CHECK_INVARIANT
60 #endif
61 
62 namespace boost{
63 
64 namespace multi_index{
65 
66 template<typename Value,typename IndexSpecifierList,typename Allocator>
67 class multi_index_container:
68   private ::boost::base_from_member<
69     typename boost::detail::allocator::rebind_to<
70       Allocator,
71       typename detail::multi_index_node_type<
72         Value,IndexSpecifierList,Allocator>::type
73     >::type>,
74   BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS detail::header_holder<
75     typename detail::multi_index_node_type<
76       Value,IndexSpecifierList,Allocator>::type,
77     multi_index_container<Value,IndexSpecifierList,Allocator> >,
78   public detail::multi_index_base_type<
79     Value,IndexSpecifierList,Allocator>::type
80 {
81 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
82     BOOST_WORKAROUND(__MWERKS__,<=0x3003)
83 /* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
84  * lifetime of const references bound to temporaries --precisely what
85  * scopeguards are.
86  */
87 
88 #pragma parse_mfunc_templ off
89 #endif
90 
91 private:
92 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
93   template <typename,typename,typename> friend class  detail::index_base;
94   template <typename,typename>          friend class  detail::header_holder;
95   template <typename,typename>          friend class  detail::converter;
96 #endif
97 
98   typedef typename detail::multi_index_base_type<
99       Value,IndexSpecifierList,Allocator>::type   super;
100   typedef ::boost::base_from_member<
101     typename boost::detail::allocator::rebind_to<
102       Allocator,
103       typename super::node_type
104     >::type>                                      bfm_allocator;
105   typedef detail::header_holder<
106     typename super::node_type,
107     multi_index_container>                        bfm_header;
108 
109 public:
110   /* All types are inherited from super, a few are explicitly
111    * brought forward here to save us some typename's.
112    */
113 
114 #if defined(BOOST_MSVC)
115   typedef
116     detail::default_constructible_tuple_cons<
117       typename super::ctor_args_list>              ctor_args_list;
118 #else
119   typedef typename super::ctor_args_list           ctor_args_list;
120 #endif
121 
122   typedef IndexSpecifierList                       index_specifier_type_list;
123   typedef typename super::index_type_list          index_type_list;
124   typedef typename super::iterator_type_list       iterator_type_list;
125   typedef typename super::const_iterator_type_list const_iterator_type_list;
126   typedef typename super::value_type               value_type;
127   typedef typename super::final_allocator_type     allocator_type;
128   typedef typename super::iterator                 iterator;
129   typedef typename super::const_iterator           const_iterator;
130 
131   BOOST_STATIC_ASSERT(
132     detail::no_duplicate_tags_in_index_list<index_type_list>::value);
133 
134   /* global project() needs to see this publicly */
135 
136   typedef typename super::node_type node_type;
137 
138   /* construct/copy/destroy */
139 
multi_index_container(const ctor_args_list & args_list=typename mpl::identity<multi_index_container>::type::ctor_args_list (),const allocator_type & al=typename mpl::identity<multi_index_container>::type::allocator_type ())140   explicit multi_index_container(
141 
142 #if BOOST_WORKAROUND(__IBMCPP__,<=600)
143     /* VisualAge seems to have an ETI issue with the default values
144      * for arguments args_list and al.
145      */
146 
147     const ctor_args_list& args_list=
148       typename mpl::identity<multi_index_container>::type::
149         ctor_args_list(),
150     const allocator_type& al=
151       typename mpl::identity<multi_index_container>::type::
152         allocator_type()):
153 #else
154     const ctor_args_list& args_list=ctor_args_list(),
155     const allocator_type& al=allocator_type()):
156 #endif
157 
158     bfm_allocator(al),
159     super(args_list,bfm_allocator::member),
160     node_count(0)
161   {
162     BOOST_MULTI_INDEX_CHECK_INVARIANT;
163   }
164 
165   template<typename InputIterator>
multi_index_container(InputIterator first,InputIterator last,const ctor_args_list & args_list=typename mpl::identity<multi_index_container>::type::ctor_args_list (),const allocator_type & al=typename mpl::identity<multi_index_container>::type::allocator_type ())166   multi_index_container(
167     InputIterator first,InputIterator last,
168 
169 #if BOOST_WORKAROUND(__IBMCPP__,<=600)
170     /* VisualAge seems to have an ETI issue with the default values
171      * for arguments args_list and al.
172      */
173 
174     const ctor_args_list& args_list=
175       typename mpl::identity<multi_index_container>::type::
176         ctor_args_list(),
177     const allocator_type& al=
178       typename mpl::identity<multi_index_container>::type::
179         allocator_type()):
180 #else
181     const ctor_args_list& args_list=ctor_args_list(),
182     const allocator_type& al=allocator_type()):
183 #endif
184 
185     bfm_allocator(al),
186     super(args_list,bfm_allocator::member),
187     node_count(0)
188   {
189     BOOST_MULTI_INDEX_CHECK_INVARIANT;
190     BOOST_TRY{
191       iterator hint=super::end();
192       for(;first!=last;++first){
193         hint=super::make_iterator(insert_(*first,hint.get_node()).first);
194       }
195     }
196     BOOST_CATCH(...){
197       clear_();
198       BOOST_RETHROW;
199     }
200     BOOST_CATCH_END
201   }
202 
multi_index_container(const multi_index_container<Value,IndexSpecifierList,Allocator> & x)203   multi_index_container(
204     const multi_index_container<Value,IndexSpecifierList,Allocator>& x):
205     bfm_allocator(x.bfm_allocator::member),
206     super(x),
207     node_count(0)
208   {
209     copy_map_type map(bfm_allocator::member,x.size(),x.header(),header());
210     for(const_iterator it=x.begin(),it_end=x.end();it!=it_end;++it){
211       map.clone(it.get_node());
212     }
213     super::copy_(x,map);
214     map.release();
215     node_count=x.size();
216 
217     /* Not until this point are the indices required to be consistent,
218      * hence the position of the invariant checker.
219      */
220 
221     BOOST_MULTI_INDEX_CHECK_INVARIANT;
222   }
223 
~multi_index_container()224   ~multi_index_container()
225   {
226     delete_all_nodes_();
227   }
228 
operator =(const multi_index_container<Value,IndexSpecifierList,Allocator> & x)229   multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
230     const multi_index_container<Value,IndexSpecifierList,Allocator>& x)
231   {
232     BOOST_MULTI_INDEX_CHECK_INVARIANT;
233     multi_index_container<Value,IndexSpecifierList,Allocator> tmp(x);
234     this->swap(tmp);
235     return *this;
236   }
237 
get_allocator() const238   allocator_type get_allocator()const
239   {
240     return allocator_type(bfm_allocator::member);
241   }
242 
243   /* retrieval of indices by number */
244 
245 #if !defined(BOOST_NO_MEMBER_TEMPLATES)
246   template<int N>
247   struct nth_index
248   {
249     BOOST_STATIC_ASSERT(N>=0&&N<mpl::size<index_type_list>::type::value);
250     typedef typename mpl::at_c<index_type_list,N>::type type;
251   };
252 
253   template<int N>
get(BOOST_EXPLICIT_TEMPLATE_NON_TYPE (int,N))254   typename nth_index<N>::type& get(BOOST_EXPLICIT_TEMPLATE_NON_TYPE(int,N))
255   {
256     BOOST_STATIC_ASSERT(N>=0&&N<mpl::size<index_type_list>::type::value);
257     return *this;
258   }
259 
260   template<int N>
get(BOOST_EXPLICIT_TEMPLATE_NON_TYPE (int,N)) const261   const typename nth_index<N>::type& get(
262     BOOST_EXPLICIT_TEMPLATE_NON_TYPE(int,N))const
263   {
264     BOOST_STATIC_ASSERT(N>=0&&N<mpl::size<index_type_list>::type::value);
265     return *this;
266   }
267 #endif
268 
269   /* retrieval of indices by tag */
270 
271 #if !defined(BOOST_NO_MEMBER_TEMPLATES)
272   template<typename Tag>
273   struct index
274   {
275     typedef typename mpl::find_if<
276       index_type_list,
277       detail::has_tag<Tag>
278     >::type                                    iter;
279 
280     BOOST_STATIC_CONSTANT(
281       bool,index_found=!(is_same<iter,typename mpl::end<index_type_list>::type >::value));
282     BOOST_STATIC_ASSERT(index_found);
283 
284     typedef typename mpl::deref<iter>::type    type;
285   };
286 
287   template<typename Tag>
get(BOOST_EXPLICIT_TEMPLATE_TYPE (Tag))288   typename index<Tag>::type& get(BOOST_EXPLICIT_TEMPLATE_TYPE(Tag))
289   {
290     return *this;
291   }
292 
293   template<typename Tag>
get(BOOST_EXPLICIT_TEMPLATE_TYPE (Tag)) const294   const typename index<Tag>::type& get(
295     BOOST_EXPLICIT_TEMPLATE_TYPE(Tag))const
296   {
297     return *this;
298   }
299 #endif
300 
301   /* projection of iterators by number */
302 
303 #if !defined(BOOST_NO_MEMBER_TEMPLATES)
304   template<int N>
305   struct nth_index_iterator
306   {
307     typedef typename nth_index<N>::type::iterator type;
308   };
309 
310   template<int N>
311   struct nth_index_const_iterator
312   {
313     typedef typename nth_index<N>::type::const_iterator type;
314   };
315 
316   template<int N,typename IteratorType>
project(IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE (int,N))317   typename nth_index_iterator<N>::type project(
318     IteratorType it
319     BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))
320   {
321     typedef typename nth_index<N>::type index;
322 
323     BOOST_STATIC_ASSERT(
324       (mpl::contains<iterator_type_list,IteratorType>::value));
325 
326     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
327     BOOST_MULTI_INDEX_CHECK_IS_OWNER(
328       it,static_cast<typename IteratorType::container_type&>(*this));
329 
330     return index::make_iterator(static_cast<node_type*>(it.get_node()));
331   }
332 
333   template<int N,typename IteratorType>
project(IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE (int,N)) const334   typename nth_index_const_iterator<N>::type project(
335     IteratorType it
336     BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))const
337   {
338     typedef typename nth_index<N>::type index;
339 
340     BOOST_STATIC_ASSERT((
341       mpl::contains<iterator_type_list,IteratorType>::value||
342       mpl::contains<const_iterator_type_list,IteratorType>::value));
343 
344     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
345     BOOST_MULTI_INDEX_CHECK_IS_OWNER(
346       it,static_cast<const typename IteratorType::container_type&>(*this));
347     return index::make_iterator(static_cast<node_type*>(it.get_node()));
348   }
349 #endif
350 
351   /* projection of iterators by tag */
352 
353 #if !defined(BOOST_NO_MEMBER_TEMPLATES)
354   template<typename Tag>
355   struct index_iterator
356   {
357     typedef typename index<Tag>::type::iterator type;
358   };
359 
360   template<typename Tag>
361   struct index_const_iterator
362   {
363     typedef typename index<Tag>::type::const_iterator type;
364   };
365 
366   template<typename Tag,typename IteratorType>
project(IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE (Tag))367   typename index_iterator<Tag>::type project(
368     IteratorType it
369     BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))
370   {
371     typedef typename index<Tag>::type index;
372 
373     BOOST_STATIC_ASSERT(
374       (mpl::contains<iterator_type_list,IteratorType>::value));
375 
376     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
377     BOOST_MULTI_INDEX_CHECK_IS_OWNER(
378       it,static_cast<typename IteratorType::container_type&>(*this));
379     return index::make_iterator(static_cast<node_type*>(it.get_node()));
380   }
381 
382   template<typename Tag,typename IteratorType>
project(IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE (Tag)) const383   typename index_const_iterator<Tag>::type project(
384     IteratorType it
385     BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))const
386   {
387     typedef typename index<Tag>::type index;
388 
389     BOOST_STATIC_ASSERT((
390       mpl::contains<iterator_type_list,IteratorType>::value||
391       mpl::contains<const_iterator_type_list,IteratorType>::value));
392 
393     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
394     BOOST_MULTI_INDEX_CHECK_IS_OWNER(
395       it,static_cast<const typename IteratorType::container_type&>(*this));
396     return index::make_iterator(static_cast<node_type*>(it.get_node()));
397   }
398 #endif
399 
400 BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
401   typedef typename super::copy_map_type copy_map_type;
402 
header() const403   node_type* header()const
404   {
405     return bfm_header::member;
406   }
407 
allocate_node()408   node_type* allocate_node()
409   {
410     return bfm_allocator::member.allocate(1);
411   }
412 
deallocate_node(node_type * x)413   void deallocate_node(node_type* x)
414   {
415     bfm_allocator::member.deallocate(x,1);
416   }
417 
empty_() const418   bool empty_()const
419   {
420     return node_count==0;
421   }
422 
size_() const423   std::size_t size_()const
424   {
425     return node_count;
426   }
427 
max_size_() const428   std::size_t max_size_()const
429   {
430     return static_cast<std::size_t >(-1);
431   }
432 
insert_(const Value & v)433   std::pair<node_type*,bool> insert_(const Value& v)
434   {
435     node_type* x=allocate_node();
436     BOOST_TRY{
437       node_type* res=super::insert_(v,x);
438       if(res==x){
439         ++node_count;
440         return std::pair<node_type*,bool>(res,true);
441       }
442       else{
443         deallocate_node(x);
444         return std::pair<node_type*,bool>(res,false);
445       }
446     }
447     BOOST_CATCH(...){
448       deallocate_node(x);
449       BOOST_RETHROW;
450     }
451     BOOST_CATCH_END
452   }
453 
insert_(const Value & v,node_type * position)454   std::pair<node_type*,bool> insert_(const Value& v,node_type* position)
455   {
456     node_type* x=allocate_node();
457     BOOST_TRY{
458       node_type* res=super::insert_(v,position,x);
459       if(res==x){
460         ++node_count;
461         return std::pair<node_type*,bool>(res,true);
462       }
463       else{
464         deallocate_node(x);
465         return std::pair<node_type*,bool>(res,false);
466       }
467     }
468     BOOST_CATCH(...){
469       deallocate_node(x);
470       BOOST_RETHROW;
471     }
472     BOOST_CATCH_END
473   }
474 
erase_(node_type * x)475   void erase_(node_type* x)
476   {
477     super::erase_(x);
478     deallocate_node(x);
479     --node_count;
480   }
481 
delete_node_(node_type * x)482   void delete_node_(node_type* x)
483   {
484     super::delete_node_(x);
485     deallocate_node(x);
486   }
487 
delete_all_nodes_()488   void delete_all_nodes_()
489   {
490     super::delete_all_nodes_();
491   }
492 
clear_()493   void clear_()
494   {
495     delete_all_nodes_();
496     super::clear_();
497     node_count=0;
498   }
499 
swap_(multi_index_container<Value,IndexSpecifierList,Allocator> & x)500   void swap_(multi_index_container<Value,IndexSpecifierList,Allocator>& x)
501   {
502     std::swap(bfm_header::member,x.bfm_header::member);
503     super::swap_(x);
504     std::swap(node_count,x.node_count);
505   }
506 
replace_(const Value & k,node_type * x)507   bool replace_(const Value& k,node_type* x)
508   {
509     return super::replace_(k,x);
510   }
511 
512   template<typename Modifier>
modify_(Modifier mod,node_type * x)513   bool modify_(Modifier mod,node_type* x)
514   {
515     mod(const_cast<value_type&>(x->value));
516 
517     BOOST_TRY{
518       if(!super::modify_(x)){
519         deallocate_node(x);
520         --node_count;
521         return false;
522       }
523       else return true;
524     }
525     BOOST_CATCH(...){
526       deallocate_node(x);
527       --node_count;
528       BOOST_RETHROW;
529     }
530     BOOST_CATCH_END
531   }
532 
533 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
534   /* serialization */
535 
536   friend class boost::serialization::access;
537 
538   BOOST_SERIALIZATION_SPLIT_MEMBER()
539 
540   typedef typename super::index_saver_type        index_saver_type;
541   typedef typename super::index_loader_type       index_loader_type;
542 
543   template<class Archive>
save(Archive & ar,const unsigned int version) const544   void save(Archive& ar,const unsigned int version)const
545   {
546     const std::size_t s=size_();
547     ar<<serialization::make_nvp("count",s);
548     index_saver_type sm(bfm_allocator::member,s);
549 
550     for(iterator it=super::begin(),it_end=super::end();it!=it_end;++it){
551       ar<<serialization::make_nvp("item",*it);
552       sm.add(it.get_node(),ar,version);
553     }
554     sm.add_track(header(),ar,version);
555 
556     super::save_(ar,version,sm);
557   }
558 
559   template<class Archive>
load(Archive & ar,const unsigned int version)560   void load(Archive& ar,const unsigned int version)
561   {
562     BOOST_MULTI_INDEX_CHECK_INVARIANT;
563 
564     clear_();
565 
566     std::size_t s;
567     ar>>serialization::make_nvp("count",s);
568     index_loader_type lm(bfm_allocator::member,s);
569 
570     for(std::size_t n=0;n<s;++n){
571       detail::archive_constructed<Value> value("item",ar,version);
572       std::pair<node_type*,bool> p=insert_(
573         value.get(),super::end().get_node());
574       if(!p.second)throw_exception(
575         archive::archive_exception(
576           archive::archive_exception::other_exception));
577       ar.reset_object_address(&p.first->value,&value.get());
578       lm.add(p.first,ar,version);
579     }
580     lm.add_track(header(),ar,version);
581 
582     super::load_(ar,version,lm);
583   }
584 #endif
585 
586 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
587   /* invariant stuff */
588 
invariant_() const589   bool invariant_()const
590   {
591     return super::invariant_();
592   }
593 
check_invariant_() const594   void check_invariant_()const
595   {
596     BOOST_MULTI_INDEX_INVARIANT_ASSERT(invariant_());
597   }
598 #endif
599 
600 private:
601   std::size_t node_count;
602 
603 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
604     BOOST_WORKAROUND(__MWERKS__,<=0x3003)
605 #pragma parse_mfunc_templ reset
606 #endif
607 };
608 
609 /* retrieval of indices by number */
610 
611 template<typename MultiIndexContainer,int N>
612 struct nth_index
613 {
614   BOOST_STATIC_CONSTANT(
615     int,
616     M=mpl::size<typename MultiIndexContainer::index_type_list>::type::value);
617   BOOST_STATIC_ASSERT(N>=0&&N<M);
618   typedef typename mpl::at_c<
619     typename MultiIndexContainer::index_type_list,N>::type type;
620 };
621 
622 template<int N,typename Value,typename IndexSpecifierList,typename Allocator>
623 typename nth_index<
624   multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type&
get(multi_index_container<Value,IndexSpecifierList,Allocator> & m BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE (int,N))625 get(
626   multi_index_container<Value,IndexSpecifierList,Allocator>& m
627   BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))
628 {
629   typedef multi_index_container<
630     Value,IndexSpecifierList,Allocator>    multi_index_type;
631   typedef typename nth_index<
632     multi_index_container<
633       Value,IndexSpecifierList,Allocator>,
634     N
635   >::type                                  index;
636 
637   BOOST_STATIC_ASSERT(N>=0&&
638     N<
639     mpl::size<
640       BOOST_DEDUCED_TYPENAME multi_index_type::index_type_list
641     >::type::value);
642 
643   return detail::converter<multi_index_type,index>::index(m);
644 }
645 
646 template<int N,typename Value,typename IndexSpecifierList,typename Allocator>
647 const typename nth_index<
648   multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type&
get(const multi_index_container<Value,IndexSpecifierList,Allocator> & m BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE (int,N))649 get(
650   const multi_index_container<Value,IndexSpecifierList,Allocator>& m
651   BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))
652 {
653   typedef multi_index_container<
654     Value,IndexSpecifierList,Allocator>    multi_index_type;
655   typedef typename nth_index<
656     multi_index_container<
657       Value,IndexSpecifierList,Allocator>,
658     N
659   >::type                                  index;
660 
661   BOOST_STATIC_ASSERT(N>=0&&
662     N<
663     mpl::size<
664       BOOST_DEDUCED_TYPENAME multi_index_type::index_type_list
665     >::type::value);
666 
667   return detail::converter<multi_index_type,index>::index(m);
668 }
669 
670 /* retrieval of indices by tag */
671 
672 template<typename MultiIndexContainer,typename Tag>
673 struct index
674 {
675   typedef typename MultiIndexContainer::index_type_list index_type_list;
676 
677   typedef typename mpl::find_if<
678     index_type_list,
679     detail::has_tag<Tag>
680   >::type                                      iter;
681 
682   BOOST_STATIC_CONSTANT(
683     bool,index_found=!(is_same<iter,typename mpl::end<index_type_list>::type >::value));
684   BOOST_STATIC_ASSERT(index_found);
685 
686   typedef typename mpl::deref<iter>::type       type;
687 };
688 
689 template<
690   typename Tag,typename Value,typename IndexSpecifierList,typename Allocator
691 >
692 typename ::boost::multi_index::index<
693   multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type&
get(multi_index_container<Value,IndexSpecifierList,Allocator> & m BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE (Tag))694 get(
695   multi_index_container<Value,IndexSpecifierList,Allocator>& m
696   BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))
697 {
698   typedef multi_index_container<
699     Value,IndexSpecifierList,Allocator>         multi_index_type;
700   typedef typename ::boost::multi_index::index<
701     multi_index_container<
702       Value,IndexSpecifierList,Allocator>,
703     Tag
704   >::type                                       index;
705 
706   return detail::converter<multi_index_type,index>::index(m);
707 }
708 
709 template<
710   typename Tag,typename Value,typename IndexSpecifierList,typename Allocator
711 >
712 const typename ::boost::multi_index::index<
713   multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type&
get(const multi_index_container<Value,IndexSpecifierList,Allocator> & m BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE (Tag))714 get(
715   const multi_index_container<Value,IndexSpecifierList,Allocator>& m
716   BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))
717 {
718   typedef multi_index_container<
719     Value,IndexSpecifierList,Allocator>         multi_index_type;
720   typedef typename ::boost::multi_index::index<
721     multi_index_container<
722       Value,IndexSpecifierList,Allocator>,
723     Tag
724   >::type                                       index;
725 
726   return detail::converter<multi_index_type,index>::index(m);
727 }
728 
729 /* projection of iterators by number */
730 
731 template<typename MultiIndexContainer,int N>
732 struct nth_index_iterator
733 {
734   typedef typename detail::prevent_eti<
735     nth_index<MultiIndexContainer,N>,
736     typename nth_index<MultiIndexContainer,N>::type>::type::iterator type;
737 };
738 
739 template<typename MultiIndexContainer,int N>
740 struct nth_index_const_iterator
741 {
742   typedef typename detail::prevent_eti<
743     nth_index<MultiIndexContainer,N>,
744     typename nth_index<MultiIndexContainer,N>::type
745   >::type::const_iterator type;
746 };
747 
748 template<
749   int N,typename IteratorType,
750   typename Value,typename IndexSpecifierList,typename Allocator>
751 typename nth_index_iterator<
752   multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type
project(multi_index_container<Value,IndexSpecifierList,Allocator> & m,IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE (int,N))753 project(
754   multi_index_container<Value,IndexSpecifierList,Allocator>& m,
755   IteratorType it
756   BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))
757 {
758   typedef multi_index_container<
759     Value,IndexSpecifierList,Allocator>                multi_index_type;
760   typedef typename nth_index<multi_index_type,N>::type index;
761 
762 #if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */
763   BOOST_STATIC_ASSERT((
764     mpl::contains<
765       BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
766       IteratorType>::value));
767 #endif
768 
769   BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
770 
771 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
772   typedef detail::converter<
773     multi_index_type,
774     BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
775   BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
776 #endif
777 
778   return detail::converter<multi_index_type,index>::iterator(
779     m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
780 }
781 
782 template<
783   int N,typename IteratorType,
784   typename Value,typename IndexSpecifierList,typename Allocator>
785 typename nth_index_const_iterator<
786   multi_index_container<Value,IndexSpecifierList,Allocator>,N>::type
project(const multi_index_container<Value,IndexSpecifierList,Allocator> & m,IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE (int,N))787 project(
788   const multi_index_container<Value,IndexSpecifierList,Allocator>& m,
789   IteratorType it
790   BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(int,N))
791 {
792   typedef multi_index_container<
793     Value,IndexSpecifierList,Allocator>                multi_index_type;
794   typedef typename nth_index<multi_index_type,N>::type index;
795 
796 #if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */
797   BOOST_STATIC_ASSERT((
798     mpl::contains<
799       BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
800       IteratorType>::value||
801     mpl::contains<
802       BOOST_DEDUCED_TYPENAME multi_index_type::const_iterator_type_list,
803       IteratorType>::value));
804 #endif
805 
806   BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
807 
808 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
809   typedef detail::converter<
810     multi_index_type,
811     BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
812   BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
813 #endif
814 
815   return detail::converter<multi_index_type,index>::const_iterator(
816     m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
817 }
818 
819 /* projection of iterators by tag */
820 
821 template<typename MultiIndexContainer,typename Tag>
822 struct index_iterator
823 {
824   typedef typename ::boost::multi_index::index<
825     MultiIndexContainer,Tag>::type::iterator    type;
826 };
827 
828 template<typename MultiIndexContainer,typename Tag>
829 struct index_const_iterator
830 {
831   typedef typename ::boost::multi_index::index<
832     MultiIndexContainer,Tag>::type::const_iterator type;
833 };
834 
835 template<
836   typename Tag,typename IteratorType,
837   typename Value,typename IndexSpecifierList,typename Allocator>
838 typename index_iterator<
839   multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type
project(multi_index_container<Value,IndexSpecifierList,Allocator> & m,IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE (Tag))840 project(
841   multi_index_container<Value,IndexSpecifierList,Allocator>& m,
842   IteratorType it
843   BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))
844 {
845   typedef multi_index_container<
846     Value,IndexSpecifierList,Allocator>         multi_index_type;
847   typedef typename ::boost::multi_index::index<
848     multi_index_type,Tag>::type                 index;
849 
850 #if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */
851   BOOST_STATIC_ASSERT((
852     mpl::contains<
853       BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
854       IteratorType>::value));
855 #endif
856 
857   BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
858 
859 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
860   typedef detail::converter<
861     multi_index_type,
862     BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
863   BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
864 #endif
865 
866   return detail::converter<multi_index_type,index>::iterator(
867     m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
868 }
869 
870 template<
871   typename Tag,typename IteratorType,
872   typename Value,typename IndexSpecifierList,typename Allocator>
873 typename index_const_iterator<
874   multi_index_container<Value,IndexSpecifierList,Allocator>,Tag>::type
project(const multi_index_container<Value,IndexSpecifierList,Allocator> & m,IteratorType it BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE (Tag))875 project(
876   const multi_index_container<Value,IndexSpecifierList,Allocator>& m,
877   IteratorType it
878   BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Tag))
879 {
880   typedef multi_index_container<
881     Value,IndexSpecifierList,Allocator>         multi_index_type;
882   typedef typename ::boost::multi_index::index<
883     multi_index_type,Tag>::type                 index;
884 
885 #if !defined(BOOST_MSVC)||!(BOOST_MSVC<1300) /* this ain't work in MSVC++ 6.0 */
886   BOOST_STATIC_ASSERT((
887     mpl::contains<
888       BOOST_DEDUCED_TYPENAME multi_index_type::iterator_type_list,
889       IteratorType>::value||
890     mpl::contains<
891       BOOST_DEDUCED_TYPENAME multi_index_type::const_iterator_type_list,
892       IteratorType>::value));
893 #endif
894 
895   BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
896 
897 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
898   typedef detail::converter<
899     multi_index_type,
900     BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
901   BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
902 #endif
903 
904   return detail::converter<multi_index_type,index>::const_iterator(
905     m,static_cast<typename multi_index_type::node_type*>(it.get_node()));
906 }
907 
908 /* Comparison. Simple forward to first index. */
909 
910 template<
911   typename Value1,typename IndexSpecifierList1,typename Allocator1,
912   typename Value2,typename IndexSpecifierList2,typename Allocator2
913 >
operator ==(const multi_index_container<Value1,IndexSpecifierList1,Allocator1> & x,const multi_index_container<Value2,IndexSpecifierList2,Allocator2> & y)914 bool operator==(
915   const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
916   const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
917 {
918   return get<0>(x)==get<0>(y);
919 }
920 
921 template<
922   typename Value1,typename IndexSpecifierList1,typename Allocator1,
923   typename Value2,typename IndexSpecifierList2,typename Allocator2
924 >
operator <(const multi_index_container<Value1,IndexSpecifierList1,Allocator1> & x,const multi_index_container<Value2,IndexSpecifierList2,Allocator2> & y)925 bool operator<(
926   const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
927   const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
928 {
929   return get<0>(x)<get<0>(y);
930 }
931 
932 template<
933   typename Value1,typename IndexSpecifierList1,typename Allocator1,
934   typename Value2,typename IndexSpecifierList2,typename Allocator2
935 >
operator !=(const multi_index_container<Value1,IndexSpecifierList1,Allocator1> & x,const multi_index_container<Value2,IndexSpecifierList2,Allocator2> & y)936 bool operator!=(
937   const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
938   const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
939 {
940   return get<0>(x)!=get<0>(y);
941 }
942 
943 template<
944   typename Value1,typename IndexSpecifierList1,typename Allocator1,
945   typename Value2,typename IndexSpecifierList2,typename Allocator2
946 >
operator >(const multi_index_container<Value1,IndexSpecifierList1,Allocator1> & x,const multi_index_container<Value2,IndexSpecifierList2,Allocator2> & y)947 bool operator>(
948   const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
949   const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
950 {
951   return get<0>(x)>get<0>(y);
952 }
953 
954 template<
955   typename Value1,typename IndexSpecifierList1,typename Allocator1,
956   typename Value2,typename IndexSpecifierList2,typename Allocator2
957 >
operator >=(const multi_index_container<Value1,IndexSpecifierList1,Allocator1> & x,const multi_index_container<Value2,IndexSpecifierList2,Allocator2> & y)958 bool operator>=(
959   const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
960   const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
961 {
962   return get<0>(x)>=get<0>(y);
963 }
964 
965 template<
966   typename Value1,typename IndexSpecifierList1,typename Allocator1,
967   typename Value2,typename IndexSpecifierList2,typename Allocator2
968 >
operator <=(const multi_index_container<Value1,IndexSpecifierList1,Allocator1> & x,const multi_index_container<Value2,IndexSpecifierList2,Allocator2> & y)969 bool operator<=(
970   const multi_index_container<Value1,IndexSpecifierList1,Allocator1>& x,
971   const multi_index_container<Value2,IndexSpecifierList2,Allocator2>& y)
972 {
973   return get<0>(x)<=get<0>(y);
974 }
975 
976 /*  specialized algorithms */
977 
978 template<typename Value,typename IndexSpecifierList,typename Allocator>
swap(multi_index_container<Value,IndexSpecifierList,Allocator> & x,multi_index_container<Value,IndexSpecifierList,Allocator> & y)979 void swap(
980   multi_index_container<Value,IndexSpecifierList,Allocator>& x,
981   multi_index_container<Value,IndexSpecifierList,Allocator>& y)
982 {
983   x.swap(y);
984 }
985 
986 } /* namespace multi_index */
987 
988 /* Associated global functions are promoted to namespace boost, except
989  * comparison operators and swap, which are meant to be Koenig looked-up.
990  */
991 
992 using multi_index::get;
993 using multi_index::project;
994 
995 } /* namespace boost */
996 
997 #undef BOOST_MULTI_INDEX_CHECK_INVARIANT
998 
999 #endif
1000