Chris@16
|
1 // Boost.Geometry Index
|
Chris@16
|
2 //
|
Chris@16
|
3 // R-tree R*-tree insert algorithm implementation
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
|
Chris@16
|
6 //
|
Chris@16
|
7 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
8 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
9 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
|
Chris@16
|
12 #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #include <boost/geometry/index/detail/algorithms/content.hpp>
|
Chris@16
|
15
|
Chris@16
|
16 namespace boost { namespace geometry { namespace index {
|
Chris@16
|
17
|
Chris@16
|
18 namespace detail { namespace rtree { namespace visitors {
|
Chris@16
|
19
|
Chris@16
|
20 namespace rstar {
|
Chris@16
|
21
|
Chris@16
|
22 template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
|
Chris@16
|
23 class remove_elements_to_reinsert
|
Chris@16
|
24 {
|
Chris@16
|
25 public:
|
Chris@16
|
26 typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
|
Chris@16
|
27 typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
|
Chris@16
|
28 typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
|
Chris@16
|
29
|
Chris@16
|
30 typedef typename Options::parameters_type parameters_type;
|
Chris@16
|
31
|
Chris@16
|
32 //typedef typename Allocators::internal_node_pointer internal_node_pointer;
|
Chris@16
|
33 typedef internal_node * internal_node_pointer;
|
Chris@16
|
34
|
Chris@16
|
35 template <typename ResultElements, typename Node>
|
Chris@16
|
36 static inline void apply(ResultElements & result_elements,
|
Chris@16
|
37 Node & n,
|
Chris@16
|
38 internal_node_pointer parent,
|
Chris@16
|
39 size_t current_child_index,
|
Chris@16
|
40 parameters_type const& parameters,
|
Chris@16
|
41 Translator const& translator,
|
Chris@16
|
42 Allocators & allocators)
|
Chris@16
|
43 {
|
Chris@16
|
44 typedef typename rtree::elements_type<Node>::type elements_type;
|
Chris@16
|
45 typedef typename elements_type::value_type element_type;
|
Chris@16
|
46 typedef typename geometry::point_type<Box>::type point_type;
|
Chris@16
|
47 // TODO: awulkiew - change second point_type to the point type of the Indexable?
|
Chris@101
|
48 typedef typename
|
Chris@101
|
49 geometry::default_comparable_distance_result<point_type>::type
|
Chris@101
|
50 comparable_distance_type;
|
Chris@16
|
51
|
Chris@16
|
52 elements_type & elements = rtree::elements(n);
|
Chris@16
|
53
|
Chris@16
|
54 const size_t elements_count = parameters.get_max_elements() + 1;
|
Chris@16
|
55 const size_t reinserted_elements_count = (::std::min)(parameters.get_reinserted_elements(), elements_count - parameters.get_min_elements());
|
Chris@16
|
56
|
Chris@16
|
57 BOOST_GEOMETRY_INDEX_ASSERT(parent, "node shouldn't be the root node");
|
Chris@16
|
58 BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected elements number");
|
Chris@16
|
59 BOOST_GEOMETRY_INDEX_ASSERT(0 < reinserted_elements_count, "wrong value of elements to reinsert");
|
Chris@16
|
60
|
Chris@16
|
61 // calculate current node's center
|
Chris@16
|
62 point_type node_center;
|
Chris@16
|
63 geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center);
|
Chris@16
|
64
|
Chris@16
|
65 // fill the container of centers' distances of children from current node's center
|
Chris@16
|
66 typedef typename index::detail::rtree::container_from_elements_type<
|
Chris@16
|
67 elements_type,
|
Chris@101
|
68 std::pair<comparable_distance_type, element_type>
|
Chris@16
|
69 >::type sorted_elements_type;
|
Chris@101
|
70
|
Chris@16
|
71 sorted_elements_type sorted_elements;
|
Chris@16
|
72 // If constructor is used instead of resize() MS implementation leaks here
|
Chris@16
|
73 sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
|
Chris@16
|
74
|
Chris@16
|
75 for ( typename elements_type::const_iterator it = elements.begin() ;
|
Chris@16
|
76 it != elements.end() ; ++it )
|
Chris@16
|
77 {
|
Chris@16
|
78 point_type element_center;
|
Chris@16
|
79 geometry::centroid( rtree::element_indexable(*it, translator), element_center);
|
Chris@16
|
80 sorted_elements.push_back(std::make_pair(
|
Chris@16
|
81 geometry::comparable_distance(node_center, element_center),
|
Chris@16
|
82 *it)); // MAY THROW (V, E: copy)
|
Chris@16
|
83 }
|
Chris@16
|
84
|
Chris@16
|
85 // sort elements by distances from center
|
Chris@16
|
86 std::partial_sort(
|
Chris@16
|
87 sorted_elements.begin(),
|
Chris@16
|
88 sorted_elements.begin() + reinserted_elements_count,
|
Chris@16
|
89 sorted_elements.end(),
|
Chris@101
|
90 distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
|
Chris@16
|
91
|
Chris@16
|
92 // copy elements which will be reinserted
|
Chris@16
|
93 result_elements.clear();
|
Chris@16
|
94 result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
|
Chris@16
|
95 for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
|
Chris@16
|
96 it != sorted_elements.begin() + reinserted_elements_count ; ++it )
|
Chris@16
|
97 {
|
Chris@16
|
98 result_elements.push_back(it->second); // MAY THROW (V, E: copy)
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 BOOST_TRY
|
Chris@16
|
102 {
|
Chris@16
|
103 // copy remaining elements to the current node
|
Chris@16
|
104 elements.clear();
|
Chris@16
|
105 elements.reserve(elements_count - reinserted_elements_count); // SHOULDN'T THROW (new_size <= old size)
|
Chris@16
|
106 for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() + reinserted_elements_count;
|
Chris@16
|
107 it != sorted_elements.end() ; ++it )
|
Chris@16
|
108 {
|
Chris@16
|
109 elements.push_back(it->second); // MAY THROW (V, E: copy)
|
Chris@16
|
110 }
|
Chris@16
|
111 }
|
Chris@16
|
112 BOOST_CATCH(...)
|
Chris@16
|
113 {
|
Chris@16
|
114 elements.clear();
|
Chris@16
|
115
|
Chris@16
|
116 for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ;
|
Chris@16
|
117 it != sorted_elements.end() ; ++it )
|
Chris@16
|
118 {
|
Chris@16
|
119 destroy_element<Value, Options, Translator, Box, Allocators>::apply(it->second, allocators);
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 BOOST_RETHROW // RETHROW
|
Chris@16
|
123 }
|
Chris@16
|
124 BOOST_CATCH_END
|
Chris@16
|
125
|
Chris@16
|
126 ::boost::ignore_unused_variable_warning(parameters);
|
Chris@16
|
127 }
|
Chris@16
|
128
|
Chris@16
|
129 private:
|
Chris@16
|
130 template <typename Distance, typename El>
|
Chris@16
|
131 static inline bool distances_asc(
|
Chris@16
|
132 std::pair<Distance, El> const& d1,
|
Chris@16
|
133 std::pair<Distance, El> const& d2)
|
Chris@16
|
134 {
|
Chris@16
|
135 return d1.first < d2.first;
|
Chris@16
|
136 }
|
Chris@16
|
137
|
Chris@16
|
138 template <typename Distance, typename El>
|
Chris@16
|
139 static inline bool distances_dsc(
|
Chris@16
|
140 std::pair<Distance, El> const& d1,
|
Chris@16
|
141 std::pair<Distance, El> const& d2)
|
Chris@16
|
142 {
|
Chris@16
|
143 return d1.first > d2.first;
|
Chris@16
|
144 }
|
Chris@16
|
145 };
|
Chris@16
|
146
|
Chris@16
|
147 template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Box, typename Allocators>
|
Chris@16
|
148 struct level_insert_elements_type
|
Chris@16
|
149 {
|
Chris@16
|
150 typedef typename rtree::elements_type<
|
Chris@16
|
151 typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type
|
Chris@16
|
152 >::type type;
|
Chris@16
|
153 };
|
Chris@16
|
154
|
Chris@16
|
155 template <typename Value, typename Options, typename Box, typename Allocators>
|
Chris@16
|
156 struct level_insert_elements_type<0, Value, Value, Options, Box, Allocators>
|
Chris@16
|
157 {
|
Chris@16
|
158 typedef typename rtree::elements_type<
|
Chris@16
|
159 typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type
|
Chris@16
|
160 >::type type;
|
Chris@16
|
161 };
|
Chris@16
|
162
|
Chris@16
|
163 template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
|
Chris@16
|
164 struct level_insert_base
|
Chris@16
|
165 : public detail::insert<Element, Value, Options, Translator, Box, Allocators>
|
Chris@16
|
166 {
|
Chris@16
|
167 typedef detail::insert<Element, Value, Options, Translator, Box, Allocators> base;
|
Chris@16
|
168 typedef typename base::node node;
|
Chris@16
|
169 typedef typename base::internal_node internal_node;
|
Chris@16
|
170 typedef typename base::leaf leaf;
|
Chris@16
|
171
|
Chris@16
|
172 typedef typename level_insert_elements_type<InsertIndex, Element, Value, Options, Box, Allocators>::type elements_type;
|
Chris@16
|
173 typedef typename index::detail::rtree::container_from_elements_type<
|
Chris@16
|
174 elements_type,
|
Chris@16
|
175 typename elements_type::value_type
|
Chris@16
|
176 >::type result_elements_type;
|
Chris@16
|
177
|
Chris@16
|
178 typedef typename Options::parameters_type parameters_type;
|
Chris@16
|
179
|
Chris@16
|
180 typedef typename Allocators::node_pointer node_pointer;
|
Chris@101
|
181 typedef typename Allocators::size_type size_type;
|
Chris@16
|
182
|
Chris@16
|
183 inline level_insert_base(node_pointer & root,
|
Chris@101
|
184 size_type & leafs_level,
|
Chris@16
|
185 Element const& element,
|
Chris@16
|
186 parameters_type const& parameters,
|
Chris@16
|
187 Translator const& translator,
|
Chris@16
|
188 Allocators & allocators,
|
Chris@101
|
189 size_type relative_level)
|
Chris@16
|
190 : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
|
Chris@16
|
191 , result_relative_level(0)
|
Chris@16
|
192 {}
|
Chris@16
|
193
|
Chris@16
|
194 template <typename Node>
|
Chris@16
|
195 inline void handle_possible_reinsert_or_split_of_root(Node &n)
|
Chris@16
|
196 {
|
Chris@16
|
197 BOOST_GEOMETRY_INDEX_ASSERT(result_elements.empty(), "reinsert should be handled only once for level");
|
Chris@16
|
198
|
Chris@16
|
199 result_relative_level = base::m_leafs_level - base::m_traverse_data.current_level;
|
Chris@16
|
200
|
Chris@16
|
201 // overflow
|
Chris@16
|
202 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
|
Chris@16
|
203 {
|
Chris@16
|
204 // node isn't root node
|
Chris@16
|
205 if ( !base::m_traverse_data.current_is_root() )
|
Chris@16
|
206 {
|
Chris@16
|
207 // NOTE: exception-safety
|
Chris@16
|
208 // After an exception result_elements may contain garbage, don't use it
|
Chris@16
|
209 rstar::remove_elements_to_reinsert<Value, Options, Translator, Box, Allocators>::apply(
|
Chris@16
|
210 result_elements, n,
|
Chris@16
|
211 base::m_traverse_data.parent, base::m_traverse_data.current_child_index,
|
Chris@16
|
212 base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW, BASIC (V, E: alloc, copy)
|
Chris@16
|
213 }
|
Chris@16
|
214 // node is root node
|
Chris@16
|
215 else
|
Chris@16
|
216 {
|
Chris@16
|
217 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*base::m_root_node), "node should be the root node");
|
Chris@16
|
218 base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
219 }
|
Chris@16
|
220 }
|
Chris@16
|
221 }
|
Chris@16
|
222
|
Chris@16
|
223 template <typename Node>
|
Chris@16
|
224 inline void handle_possible_split(Node &n) const
|
Chris@16
|
225 {
|
Chris@16
|
226 // overflow
|
Chris@16
|
227 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
|
Chris@16
|
228 {
|
Chris@16
|
229 base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
230 }
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 template <typename Node>
|
Chris@16
|
234 inline void recalculate_aabb_if_necessary(Node &n) const
|
Chris@16
|
235 {
|
Chris@16
|
236 if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() )
|
Chris@16
|
237 {
|
Chris@16
|
238 // calulate node's new box
|
Chris@16
|
239 base::m_traverse_data.current_element().first =
|
Chris@16
|
240 elements_box<Box>(rtree::elements(n).begin(), rtree::elements(n).end(), base::m_translator);
|
Chris@16
|
241 }
|
Chris@16
|
242 }
|
Chris@16
|
243
|
Chris@101
|
244 size_type result_relative_level;
|
Chris@16
|
245 result_elements_type result_elements;
|
Chris@16
|
246 };
|
Chris@16
|
247
|
Chris@16
|
248 template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
|
Chris@16
|
249 struct level_insert
|
Chris@16
|
250 : public level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators>
|
Chris@16
|
251 {
|
Chris@16
|
252 typedef level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators> base;
|
Chris@16
|
253 typedef typename base::node node;
|
Chris@16
|
254 typedef typename base::internal_node internal_node;
|
Chris@16
|
255 typedef typename base::leaf leaf;
|
Chris@16
|
256
|
Chris@16
|
257 typedef typename Options::parameters_type parameters_type;
|
Chris@16
|
258
|
Chris@16
|
259 typedef typename Allocators::node_pointer node_pointer;
|
Chris@101
|
260 typedef typename Allocators::size_type size_type;
|
Chris@16
|
261
|
Chris@16
|
262 inline level_insert(node_pointer & root,
|
Chris@101
|
263 size_type & leafs_level,
|
Chris@16
|
264 Element const& element,
|
Chris@16
|
265 parameters_type const& parameters,
|
Chris@16
|
266 Translator const& translator,
|
Chris@16
|
267 Allocators & allocators,
|
Chris@101
|
268 size_type relative_level)
|
Chris@16
|
269 : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
|
Chris@16
|
270 {}
|
Chris@16
|
271
|
Chris@16
|
272 inline void operator()(internal_node & n)
|
Chris@16
|
273 {
|
Chris@16
|
274 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
|
Chris@16
|
275
|
Chris@16
|
276 if ( base::m_traverse_data.current_level < base::m_level )
|
Chris@16
|
277 {
|
Chris@16
|
278 // next traversing step
|
Chris@16
|
279 base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc)
|
Chris@16
|
280
|
Chris@16
|
281 // further insert
|
Chris@16
|
282 if ( 0 < InsertIndex )
|
Chris@16
|
283 {
|
Chris@16
|
284 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
|
Chris@16
|
285
|
Chris@16
|
286 if ( base::m_traverse_data.current_level == base::m_level - 1 )
|
Chris@16
|
287 {
|
Chris@16
|
288 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
|
Chris@16
|
289 }
|
Chris@16
|
290 }
|
Chris@16
|
291 }
|
Chris@16
|
292 else
|
Chris@16
|
293 {
|
Chris@16
|
294 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
|
Chris@16
|
295
|
Chris@16
|
296 BOOST_TRY
|
Chris@16
|
297 {
|
Chris@16
|
298 // push new child node
|
Chris@16
|
299 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
|
Chris@16
|
300 }
|
Chris@16
|
301 BOOST_CATCH(...)
|
Chris@16
|
302 {
|
Chris@16
|
303 // NOTE: exception-safety
|
Chris@16
|
304 // if the insert fails above, the element won't be stored in the tree, so delete it
|
Chris@16
|
305
|
Chris@16
|
306 rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators);
|
Chris@16
|
307 rtree::apply_visitor(del_v, *base::m_element.second);
|
Chris@16
|
308
|
Chris@16
|
309 BOOST_RETHROW // RETHROW
|
Chris@16
|
310 }
|
Chris@16
|
311 BOOST_CATCH_END
|
Chris@16
|
312
|
Chris@16
|
313 // first insert
|
Chris@16
|
314 if ( 0 == InsertIndex )
|
Chris@16
|
315 {
|
Chris@16
|
316 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
|
Chris@16
|
317 }
|
Chris@16
|
318 // not the first insert
|
Chris@16
|
319 else
|
Chris@16
|
320 {
|
Chris@16
|
321 base::handle_possible_split(n); // MAY THROW (E: alloc, N: alloc)
|
Chris@16
|
322 }
|
Chris@16
|
323 }
|
Chris@16
|
324
|
Chris@16
|
325 base::recalculate_aabb_if_necessary(n);
|
Chris@16
|
326 }
|
Chris@16
|
327
|
Chris@16
|
328 inline void operator()(leaf &)
|
Chris@16
|
329 {
|
Chris@16
|
330 BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
|
Chris@16
|
331 }
|
Chris@16
|
332 };
|
Chris@16
|
333
|
Chris@16
|
334 template <size_t InsertIndex, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
|
Chris@16
|
335 struct level_insert<InsertIndex, Value, Value, Options, Translator, Box, Allocators>
|
Chris@16
|
336 : public level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators>
|
Chris@16
|
337 {
|
Chris@16
|
338 typedef level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators> base;
|
Chris@16
|
339 typedef typename base::node node;
|
Chris@16
|
340 typedef typename base::internal_node internal_node;
|
Chris@16
|
341 typedef typename base::leaf leaf;
|
Chris@16
|
342
|
Chris@16
|
343 typedef typename Options::parameters_type parameters_type;
|
Chris@16
|
344
|
Chris@16
|
345 typedef typename Allocators::node_pointer node_pointer;
|
Chris@101
|
346 typedef typename Allocators::size_type size_type;
|
Chris@16
|
347
|
Chris@16
|
348 inline level_insert(node_pointer & root,
|
Chris@101
|
349 size_type & leafs_level,
|
Chris@16
|
350 Value const& v,
|
Chris@16
|
351 parameters_type const& parameters,
|
Chris@16
|
352 Translator const& translator,
|
Chris@16
|
353 Allocators & allocators,
|
Chris@101
|
354 size_type relative_level)
|
Chris@16
|
355 : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
|
Chris@16
|
356 {}
|
Chris@16
|
357
|
Chris@16
|
358 inline void operator()(internal_node & n)
|
Chris@16
|
359 {
|
Chris@16
|
360 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
|
Chris@16
|
361 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
|
Chris@16
|
362
|
Chris@16
|
363 // next traversing step
|
Chris@16
|
364 base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
365
|
Chris@16
|
366 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
|
Chris@16
|
367
|
Chris@16
|
368 if ( base::m_traverse_data.current_level == base::m_level - 1 )
|
Chris@16
|
369 {
|
Chris@16
|
370 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
|
Chris@16
|
371 }
|
Chris@16
|
372
|
Chris@16
|
373 base::recalculate_aabb_if_necessary(n);
|
Chris@16
|
374 }
|
Chris@16
|
375
|
Chris@16
|
376 inline void operator()(leaf & n)
|
Chris@16
|
377 {
|
Chris@16
|
378 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
|
Chris@16
|
379 "unexpected level");
|
Chris@16
|
380 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
|
Chris@16
|
381 base::m_level == (std::numeric_limits<size_t>::max)(),
|
Chris@16
|
382 "unexpected level");
|
Chris@16
|
383
|
Chris@16
|
384 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
|
Chris@16
|
385
|
Chris@16
|
386 base::handle_possible_split(n); // MAY THROW (V: alloc, copy, N: alloc)
|
Chris@16
|
387 }
|
Chris@16
|
388 };
|
Chris@16
|
389
|
Chris@16
|
390 template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
|
Chris@16
|
391 struct level_insert<0, Value, Value, Options, Translator, Box, Allocators>
|
Chris@16
|
392 : public level_insert_base<0, Value, Value, Options, Translator, Box, Allocators>
|
Chris@16
|
393 {
|
Chris@16
|
394 typedef level_insert_base<0, Value, Value, Options, Translator, Box, Allocators> base;
|
Chris@16
|
395 typedef typename base::node node;
|
Chris@16
|
396 typedef typename base::internal_node internal_node;
|
Chris@16
|
397 typedef typename base::leaf leaf;
|
Chris@16
|
398
|
Chris@16
|
399 typedef typename Options::parameters_type parameters_type;
|
Chris@16
|
400
|
Chris@16
|
401 typedef typename Allocators::node_pointer node_pointer;
|
Chris@101
|
402 typedef typename Allocators::size_type size_type;
|
Chris@16
|
403
|
Chris@16
|
404 inline level_insert(node_pointer & root,
|
Chris@101
|
405 size_type & leafs_level,
|
Chris@16
|
406 Value const& v,
|
Chris@16
|
407 parameters_type const& parameters,
|
Chris@16
|
408 Translator const& translator,
|
Chris@16
|
409 Allocators & allocators,
|
Chris@101
|
410 size_type relative_level)
|
Chris@16
|
411 : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
|
Chris@16
|
412 {}
|
Chris@16
|
413
|
Chris@16
|
414 inline void operator()(internal_node & n)
|
Chris@16
|
415 {
|
Chris@16
|
416 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level,
|
Chris@16
|
417 "unexpected level");
|
Chris@16
|
418 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level,
|
Chris@16
|
419 "unexpected level");
|
Chris@16
|
420
|
Chris@16
|
421 // next traversing step
|
Chris@16
|
422 base::traverse(*this, n); // MAY THROW (V: alloc, copy, N: alloc)
|
Chris@16
|
423
|
Chris@16
|
424 base::recalculate_aabb_if_necessary(n);
|
Chris@16
|
425 }
|
Chris@16
|
426
|
Chris@16
|
427 inline void operator()(leaf & n)
|
Chris@16
|
428 {
|
Chris@16
|
429 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
|
Chris@16
|
430 "unexpected level");
|
Chris@16
|
431 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
|
Chris@16
|
432 base::m_level == (std::numeric_limits<size_t>::max)(),
|
Chris@16
|
433 "unexpected level");
|
Chris@16
|
434
|
Chris@16
|
435 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
|
Chris@16
|
436
|
Chris@16
|
437 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (V: alloc, copy, N: alloc)
|
Chris@16
|
438
|
Chris@16
|
439 base::recalculate_aabb_if_necessary(n);
|
Chris@16
|
440 }
|
Chris@16
|
441 };
|
Chris@16
|
442
|
Chris@16
|
443 } // namespace rstar
|
Chris@16
|
444
|
Chris@16
|
445 // R*-tree insert visitor
|
Chris@16
|
446 // After passing the Element to insert visitor the Element is managed by the tree
|
Chris@16
|
447 // I.e. one should not delete the node passed to the insert visitor after exception is thrown
|
Chris@16
|
448 // because this visitor may delete it
|
Chris@16
|
449 template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
|
Chris@16
|
450 class insert<Element, Value, Options, Translator, Box, Allocators, insert_reinsert_tag>
|
Chris@16
|
451 : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
|
Chris@16
|
452 {
|
Chris@16
|
453 typedef typename Options::parameters_type parameters_type;
|
Chris@16
|
454
|
Chris@16
|
455 typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
|
Chris@16
|
456 typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
|
Chris@16
|
457 typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
|
Chris@16
|
458
|
Chris@16
|
459 typedef typename Allocators::node_pointer node_pointer;
|
Chris@101
|
460 typedef typename Allocators::size_type size_type;
|
Chris@16
|
461
|
Chris@16
|
462 public:
|
Chris@16
|
463 inline insert(node_pointer & root,
|
Chris@101
|
464 size_type & leafs_level,
|
Chris@16
|
465 Element const& element,
|
Chris@16
|
466 parameters_type const& parameters,
|
Chris@16
|
467 Translator const& translator,
|
Chris@16
|
468 Allocators & allocators,
|
Chris@101
|
469 size_type relative_level = 0)
|
Chris@16
|
470 : m_root(root), m_leafs_level(leafs_level), m_element(element)
|
Chris@16
|
471 , m_parameters(parameters), m_translator(translator)
|
Chris@16
|
472 , m_relative_level(relative_level), m_allocators(allocators)
|
Chris@16
|
473 {}
|
Chris@16
|
474
|
Chris@101
|
475 inline void operator()(internal_node & n)
|
Chris@16
|
476 {
|
Chris@101
|
477 boost::ignore_unused(n);
|
Chris@16
|
478 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root), "current node should be the root");
|
Chris@16
|
479
|
Chris@16
|
480 // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
|
Chris@16
|
481 if ( m_parameters.get_reinserted_elements() > 0 )
|
Chris@16
|
482 {
|
Chris@16
|
483 rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v(
|
Chris@16
|
484 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
Chris@16
|
485
|
Chris@16
|
486 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
487
|
Chris@16
|
488 if ( !lins_v.result_elements.empty() )
|
Chris@16
|
489 {
|
Chris@16
|
490 recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
491 }
|
Chris@16
|
492 }
|
Chris@16
|
493 else
|
Chris@16
|
494 {
|
Chris@16
|
495 visitors::insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> ins_v(
|
Chris@16
|
496 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
Chris@16
|
497
|
Chris@16
|
498 rtree::apply_visitor(ins_v, *m_root);
|
Chris@16
|
499 }
|
Chris@16
|
500 }
|
Chris@16
|
501
|
Chris@101
|
502 inline void operator()(leaf & n)
|
Chris@16
|
503 {
|
Chris@101
|
504 boost::ignore_unused(n);
|
Chris@16
|
505 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<leaf>(*m_root), "current node should be the root");
|
Chris@16
|
506
|
Chris@16
|
507 // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
|
Chris@16
|
508 if ( m_parameters.get_reinserted_elements() > 0 )
|
Chris@16
|
509 {
|
Chris@16
|
510 rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v(
|
Chris@16
|
511 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
Chris@16
|
512
|
Chris@16
|
513 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
514
|
Chris@16
|
515 // we're in the root, so root should be split and there should be no elements to reinsert
|
Chris@16
|
516 BOOST_GEOMETRY_INDEX_ASSERT(lins_v.result_elements.empty(), "unexpected state");
|
Chris@16
|
517 }
|
Chris@16
|
518 else
|
Chris@16
|
519 {
|
Chris@16
|
520 visitors::insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> ins_v(
|
Chris@16
|
521 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
Chris@16
|
522
|
Chris@16
|
523 rtree::apply_visitor(ins_v, *m_root);
|
Chris@16
|
524 }
|
Chris@16
|
525 }
|
Chris@16
|
526
|
Chris@16
|
527 private:
|
Chris@16
|
528 template <typename Elements>
|
Chris@16
|
529 inline void recursive_reinsert(Elements & elements, size_t relative_level)
|
Chris@16
|
530 {
|
Chris@16
|
531 typedef typename Elements::value_type element_type;
|
Chris@16
|
532
|
Chris@16
|
533 // reinsert children starting from the minimum distance
|
Chris@16
|
534 typename Elements::reverse_iterator it = elements.rbegin();
|
Chris@16
|
535 for ( ; it != elements.rend() ; ++it)
|
Chris@16
|
536 {
|
Chris@16
|
537 rstar::level_insert<1, element_type, Value, Options, Translator, Box, Allocators> lins_v(
|
Chris@16
|
538 m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level);
|
Chris@16
|
539
|
Chris@16
|
540 BOOST_TRY
|
Chris@16
|
541 {
|
Chris@16
|
542 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
543 }
|
Chris@16
|
544 BOOST_CATCH(...)
|
Chris@16
|
545 {
|
Chris@16
|
546 ++it;
|
Chris@16
|
547 for ( ; it != elements.rend() ; ++it)
|
Chris@16
|
548 rtree::destroy_element<Value, Options, Translator, Box, Allocators>::apply(*it, m_allocators);
|
Chris@16
|
549 BOOST_RETHROW // RETHROW
|
Chris@16
|
550 }
|
Chris@16
|
551 BOOST_CATCH_END
|
Chris@16
|
552
|
Chris@16
|
553 BOOST_GEOMETRY_INDEX_ASSERT(relative_level + 1 == lins_v.result_relative_level, "unexpected level");
|
Chris@16
|
554
|
Chris@16
|
555 // non-root relative level
|
Chris@16
|
556 if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty())
|
Chris@16
|
557 {
|
Chris@16
|
558 recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
|
Chris@16
|
559 }
|
Chris@16
|
560 }
|
Chris@16
|
561 }
|
Chris@16
|
562
|
Chris@16
|
563 node_pointer & m_root;
|
Chris@101
|
564 size_type & m_leafs_level;
|
Chris@16
|
565 Element const& m_element;
|
Chris@16
|
566
|
Chris@16
|
567 parameters_type const& m_parameters;
|
Chris@16
|
568 Translator const& m_translator;
|
Chris@16
|
569
|
Chris@101
|
570 size_type m_relative_level;
|
Chris@16
|
571
|
Chris@16
|
572 Allocators & m_allocators;
|
Chris@16
|
573 };
|
Chris@16
|
574
|
Chris@16
|
575 }}} // namespace detail::rtree::visitors
|
Chris@16
|
576
|
Chris@16
|
577 }}} // namespace boost::geometry::index
|
Chris@16
|
578
|
Chris@16
|
579 #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
|