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