1 | /* Copyright 2003-2013 Joaquin M Lopez Munoz. |
2 | * Distributed under the Boost Software License, Version 1.0. |
3 | * (See accompanying file LICENSE_1_0.txt or copy at |
4 | * http://www.boost.org/LICENSE_1_0.txt) |
5 | * |
6 | * See http://www.boost.org/libs/multi_index for library home page. |
7 | */ |
8 | |
9 | #ifndef BOOST_MULTI_INDEX_DETAIL_INDEX_LOADER_HPP |
10 | #define BOOST_MULTI_INDEX_DETAIL_INDEX_LOADER_HPP |
11 | |
12 | #if defined(_MSC_VER) |
13 | #pragma once |
14 | #endif |
15 | |
16 | #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ |
17 | #include <algorithm> |
18 | #include <boost/archive/archive_exception.hpp> |
19 | #include <boost/noncopyable.hpp> |
20 | #include <boost/multi_index/detail/auto_space.hpp> |
21 | #include <boost/serialization/nvp.hpp> |
22 | #include <boost/throw_exception.hpp> |
23 | #include <cstddef> |
24 | |
25 | namespace boost{ |
26 | |
27 | namespace multi_index{ |
28 | |
29 | namespace detail{ |
30 | |
31 | /* Counterpart of index_saver (check index_saver.hpp for serialization |
32 | * details.)* multi_index_container is in charge of supplying the info about |
33 | * the base sequence, and each index can subsequently load itself using the |
34 | * const interface of index_loader. |
35 | */ |
36 | |
37 | template<typename Node,typename FinalNode,typename Allocator> |
38 | class index_loader:private noncopyable |
39 | { |
40 | public: |
41 | index_loader(const Allocator& al,std::size_t size): |
42 | spc(al,size),size_(size),n(0),sorted(false) |
43 | { |
44 | } |
45 | |
46 | template<class Archive> |
47 | void add(Node* node,Archive& ar,const unsigned int) |
48 | { |
49 | ar>>serialization::make_nvp("position" ,*node); |
50 | entries()[n++]=node; |
51 | } |
52 | |
53 | template<class Archive> |
54 | void add_track(Node* node,Archive& ar,const unsigned int) |
55 | { |
56 | ar>>serialization::make_nvp("position" ,*node); |
57 | } |
58 | |
59 | /* A rearranger is passed two nodes, and is expected to |
60 | * reposition the second after the first. |
61 | * If the first node is 0, then the second should be moved |
62 | * to the beginning of the sequence. |
63 | */ |
64 | |
65 | template<typename Rearranger,class Archive> |
66 | void load(Rearranger r,Archive& ar,const unsigned int)const |
67 | { |
68 | FinalNode* prev=unchecked_load_node(ar); |
69 | if(!prev)return; |
70 | |
71 | if(!sorted){ |
72 | std::sort(entries(),entries()+size_); |
73 | sorted=true; |
74 | } |
75 | |
76 | check_node(prev); |
77 | |
78 | for(;;){ |
79 | for(;;){ |
80 | FinalNode* node=load_node(ar); |
81 | if(!node)break; |
82 | |
83 | if(node==prev)prev=0; |
84 | r(prev,node); |
85 | |
86 | prev=node; |
87 | } |
88 | prev=load_node(ar); |
89 | if(!prev)break; |
90 | } |
91 | } |
92 | |
93 | private: |
94 | Node** entries()const{return &*spc.data();} |
95 | |
96 | /* We try to delay sorting as much as possible just in case it |
97 | * is not necessary, hence this version of load_node. |
98 | */ |
99 | |
100 | template<class Archive> |
101 | FinalNode* unchecked_load_node(Archive& ar)const |
102 | { |
103 | Node* node=0; |
104 | ar>>serialization::make_nvp("pointer" ,node); |
105 | return static_cast<FinalNode*>(node); |
106 | } |
107 | |
108 | template<class Archive> |
109 | FinalNode* load_node(Archive& ar)const |
110 | { |
111 | Node* node=0; |
112 | ar>>serialization::make_nvp("pointer" ,node); |
113 | check_node(node); |
114 | return static_cast<FinalNode*>(node); |
115 | } |
116 | |
117 | void check_node(Node* node)const |
118 | { |
119 | if(node!=0&&!std::binary_search(entries(),entries()+size_,node)){ |
120 | throw_exception( |
121 | archive::archive_exception( |
122 | archive::archive_exception::other_exception)); |
123 | } |
124 | } |
125 | |
126 | auto_space<Node*,Allocator> spc; |
127 | std::size_t size_; |
128 | std::size_t n; |
129 | mutable bool sorted; |
130 | }; |
131 | |
132 | } /* namespace multi_index::detail */ |
133 | |
134 | } /* namespace multi_index */ |
135 | |
136 | } /* namespace boost */ |
137 | |
138 | #endif |
139 | |