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