1 // Boost.Geometry Index
3 // R-tree R*-tree insert algorithm implementation
5 // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
7 // This file was modified by Oracle on 2019-2021.
8 // Modifications copyright (c) 2019-2021 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
15 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
16 #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
18 #include <type_traits>
20 #include <boost/core/ignore_unused.hpp>
22 #include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp>
24 #include <boost/geometry/index/detail/algorithms/content.hpp>
25 #include <boost/geometry/index/detail/rtree/node/concept.hpp>
26 #include <boost/geometry/index/detail/rtree/node/node_elements.hpp>
27 #include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
29 namespace boost { namespace geometry { namespace index {
31 namespace detail { namespace rtree { namespace visitors {
35 // Utility to distinguish between default and non-default index strategy
36 template <typename Point1, typename Point2, typename Strategy>
37 struct comparable_distance
39 typedef typename geometry::comparable_distance_result
41 Point1, Point2, Strategy
44 static inline result_type call(Point1 const& p1, Point2 const& p2, Strategy const& s)
46 return geometry::comparable_distance(p1, p2, s);
50 template <typename Point1, typename Point2>
51 struct comparable_distance<Point1, Point2, default_strategy>
53 typedef typename geometry::default_comparable_distance_result
58 static inline result_type call(Point1 const& p1, Point2 const& p2, default_strategy const& )
60 return geometry::comparable_distance(p1, p2);
64 template <typename MembersHolder>
65 class remove_elements_to_reinsert
68 typedef typename MembersHolder::box_type box_type;
69 typedef typename MembersHolder::parameters_type parameters_type;
70 typedef typename MembersHolder::translator_type translator_type;
71 typedef typename MembersHolder::allocators_type allocators_type;
73 typedef typename MembersHolder::node node;
74 typedef typename MembersHolder::internal_node internal_node;
75 typedef typename MembersHolder::leaf leaf;
77 //typedef typename Allocators::internal_node_pointer internal_node_pointer;
78 typedef internal_node * internal_node_pointer;
80 template <typename ResultElements, typename Node>
81 static inline void apply(ResultElements & result_elements,
83 internal_node_pointer parent,
84 size_t current_child_index,
85 parameters_type const& parameters,
86 translator_type const& translator,
87 allocators_type & allocators)
89 typedef typename rtree::elements_type<Node>::type elements_type;
90 typedef typename elements_type::value_type element_type;
91 typedef typename geometry::point_type<box_type>::type point_type;
92 typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
93 // TODO: awulkiew - change second point_type to the point type of the Indexable?
94 typedef rstar::comparable_distance
96 point_type, point_type, strategy_type
97 > comparable_distance_pp;
98 typedef typename comparable_distance_pp::result_type comparable_distance_type;
100 elements_type & elements = rtree::elements(n);
102 const size_t elements_count = parameters.get_max_elements() + 1;
103 const size_t reinserted_elements_count = (::std::min)(parameters.get_reinserted_elements(), elements_count - parameters.get_min_elements());
105 BOOST_GEOMETRY_INDEX_ASSERT(parent, "node shouldn't be the root node");
106 BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected elements number");
107 BOOST_GEOMETRY_INDEX_ASSERT(0 < reinserted_elements_count, "wrong value of elements to reinsert");
109 auto const& strategy = index::detail::get_strategy(parameters);
111 // calculate current node's center
112 point_type node_center;
113 geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center,
116 // fill the container of centers' distances of children from current node's center
117 typedef typename index::detail::rtree::container_from_elements_type<
119 std::pair<comparable_distance_type, element_type>
120 >::type sorted_elements_type;
122 sorted_elements_type sorted_elements;
123 // If constructor is used instead of resize() MS implementation leaks here
124 sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
126 for ( typename elements_type::const_iterator it = elements.begin() ;
127 it != elements.end() ; ++it )
129 point_type element_center;
130 geometry::centroid(rtree::element_indexable(*it, translator), element_center,
132 sorted_elements.push_back(std::make_pair(
133 comparable_distance_pp::call(node_center, element_center, strategy),
134 *it)); // MAY THROW (V, E: copy)
137 // sort elements by distances from center
139 sorted_elements.begin(),
140 sorted_elements.begin() + reinserted_elements_count,
141 sorted_elements.end(),
142 distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
144 // copy elements which will be reinserted
145 result_elements.clear();
146 result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
147 for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
148 it != sorted_elements.begin() + reinserted_elements_count ; ++it )
150 result_elements.push_back(it->second); // MAY THROW (V, E: copy)
155 // copy remaining elements to the current node
157 elements.reserve(elements_count - reinserted_elements_count); // SHOULDN'T THROW (new_size <= old size)
158 for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() + reinserted_elements_count;
159 it != sorted_elements.end() ; ++it )
161 elements.push_back(it->second); // MAY THROW (V, E: copy)
168 for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ;
169 it != sorted_elements.end() ; ++it )
171 destroy_element<MembersHolder>::apply(it->second, allocators);
174 BOOST_RETHROW // RETHROW
178 ::boost::ignore_unused(parameters);
182 template <typename Distance, typename El>
183 static inline bool distances_asc(
184 std::pair<Distance, El> const& d1,
185 std::pair<Distance, El> const& d2)
187 return d1.first < d2.first;
190 template <typename Distance, typename El>
191 static inline bool distances_dsc(
192 std::pair<Distance, El> const& d1,
193 std::pair<Distance, El> const& d2)
195 return d1.first > d2.first;
203 typename MembersHolder,
204 bool IsValue = std::is_same<Element, typename MembersHolder::value_type>::value
206 struct level_insert_elements_type
208 typedef typename rtree::elements_type<
209 typename rtree::internal_node<
210 typename MembersHolder::value_type,
211 typename MembersHolder::parameters_type,
212 typename MembersHolder::box_type,
213 typename MembersHolder::allocators_type,
214 typename MembersHolder::node_tag
219 template <typename Value, typename MembersHolder>
220 struct level_insert_elements_type<0, Value, MembersHolder, true>
222 typedef typename rtree::elements_type<
223 typename rtree::leaf<
224 typename MembersHolder::value_type,
225 typename MembersHolder::parameters_type,
226 typename MembersHolder::box_type,
227 typename MembersHolder::allocators_type,
228 typename MembersHolder::node_tag
233 template <size_t InsertIndex, typename Element, typename MembersHolder>
234 struct level_insert_base
235 : public detail::insert<Element, MembersHolder>
237 typedef detail::insert<Element, MembersHolder> base;
238 typedef typename base::node node;
239 typedef typename base::internal_node internal_node;
240 typedef typename base::leaf leaf;
242 typedef typename level_insert_elements_type<InsertIndex, Element, MembersHolder>::type elements_type;
243 typedef typename index::detail::rtree::container_from_elements_type<
245 typename elements_type::value_type
246 >::type result_elements_type;
248 typedef typename MembersHolder::box_type box_type;
249 typedef typename MembersHolder::parameters_type parameters_type;
250 typedef typename MembersHolder::translator_type translator_type;
251 typedef typename MembersHolder::allocators_type allocators_type;
253 typedef typename allocators_type::node_pointer node_pointer;
254 typedef typename allocators_type::size_type size_type;
256 inline level_insert_base(node_pointer & root,
257 size_type & leafs_level,
258 Element const& element,
259 parameters_type const& parameters,
260 translator_type const& translator,
261 allocators_type & allocators,
262 size_type relative_level)
263 : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
264 , result_relative_level(0)
267 template <typename Node>
268 inline void handle_possible_reinsert_or_split_of_root(Node &n)
270 BOOST_GEOMETRY_INDEX_ASSERT(result_elements.empty(), "reinsert should be handled only once for level");
272 result_relative_level = base::m_leafs_level - base::m_traverse_data.current_level;
275 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
277 // node isn't root node
278 if ( !base::m_traverse_data.current_is_root() )
280 // NOTE: exception-safety
281 // After an exception result_elements may contain garbage, don't use it
282 rstar::remove_elements_to_reinsert<MembersHolder>::apply(
284 base::m_traverse_data.parent, base::m_traverse_data.current_child_index,
285 base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW, BASIC (V, E: alloc, copy)
290 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*base::m_root_node), "node should be the root node");
291 base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
296 template <typename Node>
297 inline void handle_possible_split(Node &n) const
300 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
302 base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
306 template <typename Node>
307 inline void recalculate_aabb_if_necessary(Node const& n) const
309 if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() )
311 // calulate node's new box
316 template <typename Node>
317 inline void recalculate_aabb(Node const& n) const
319 base::m_traverse_data.current_element().first =
320 elements_box<box_type>(rtree::elements(n).begin(), rtree::elements(n).end(),
322 index::detail::get_strategy(base::m_parameters));
325 inline void recalculate_aabb(leaf const& n) const
327 base::m_traverse_data.current_element().first =
328 values_box<box_type>(rtree::elements(n).begin(), rtree::elements(n).end(),
330 index::detail::get_strategy(base::m_parameters));
333 size_type result_relative_level;
334 result_elements_type result_elements;
341 typename MembersHolder,
342 bool IsValue = std::is_same<Element, typename MembersHolder::value_type>::value
345 : public level_insert_base<InsertIndex, Element, MembersHolder>
347 typedef level_insert_base<InsertIndex, Element, MembersHolder> base;
348 typedef typename base::node node;
349 typedef typename base::internal_node internal_node;
350 typedef typename base::leaf leaf;
352 typedef typename base::parameters_type parameters_type;
353 typedef typename base::translator_type translator_type;
354 typedef typename base::allocators_type allocators_type;
356 typedef typename base::node_pointer node_pointer;
357 typedef typename base::size_type size_type;
359 inline level_insert(node_pointer & root,
360 size_type & leafs_level,
361 Element const& element,
362 parameters_type const& parameters,
363 translator_type const& translator,
364 allocators_type & allocators,
365 size_type relative_level)
366 : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
369 inline void operator()(internal_node & n)
371 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
373 if ( base::m_traverse_data.current_level < base::m_level )
375 // next traversing step
376 base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc)
379 if ( 0 < InsertIndex )
381 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
383 if ( base::m_traverse_data.current_level == base::m_level - 1 )
385 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
391 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
395 // push new child node
396 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
400 // NOTE: exception-safety
401 // if the insert fails above, the element won't be stored in the tree, so delete it
403 rtree::visitors::destroy<MembersHolder>::apply(base::m_element.second, base::m_allocators);
405 BOOST_RETHROW // RETHROW
410 if ( 0 == InsertIndex )
412 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
414 // not the first insert
417 base::handle_possible_split(n); // MAY THROW (E: alloc, N: alloc)
421 base::recalculate_aabb_if_necessary(n);
424 inline void operator()(leaf &)
426 BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
430 template <size_t InsertIndex, typename Value, typename MembersHolder>
431 struct level_insert<InsertIndex, Value, MembersHolder, true>
432 : public level_insert_base<InsertIndex, typename MembersHolder::value_type, MembersHolder>
434 typedef level_insert_base<InsertIndex, typename MembersHolder::value_type, MembersHolder> base;
435 typedef typename base::node node;
436 typedef typename base::internal_node internal_node;
437 typedef typename base::leaf leaf;
439 typedef typename MembersHolder::value_type value_type;
440 typedef typename base::parameters_type parameters_type;
441 typedef typename base::translator_type translator_type;
442 typedef typename base::allocators_type allocators_type;
444 typedef typename base::node_pointer node_pointer;
445 typedef typename base::size_type size_type;
447 inline level_insert(node_pointer & root,
448 size_type & leafs_level,
450 parameters_type const& parameters,
451 translator_type const& translator,
452 allocators_type & allocators,
453 size_type relative_level)
454 : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
457 inline void operator()(internal_node & n)
459 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
460 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
462 // next traversing step
463 base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc)
465 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
467 if ( base::m_traverse_data.current_level == base::m_level - 1 )
469 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
472 base::recalculate_aabb_if_necessary(n);
475 inline void operator()(leaf & n)
477 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
479 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
480 base::m_level == (std::numeric_limits<size_t>::max)(),
483 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
485 base::handle_possible_split(n); // MAY THROW (V: alloc, copy, N: alloc)
489 template <typename Value, typename MembersHolder>
490 struct level_insert<0, Value, MembersHolder, true>
491 : public level_insert_base<0, typename MembersHolder::value_type, MembersHolder>
493 typedef level_insert_base<0, typename MembersHolder::value_type, MembersHolder> base;
494 typedef typename base::node node;
495 typedef typename base::internal_node internal_node;
496 typedef typename base::leaf leaf;
498 typedef typename MembersHolder::value_type value_type;
499 typedef typename base::parameters_type parameters_type;
500 typedef typename base::translator_type translator_type;
501 typedef typename base::allocators_type allocators_type;
503 typedef typename base::node_pointer node_pointer;
504 typedef typename base::size_type size_type;
506 inline level_insert(node_pointer & root,
507 size_type & leafs_level,
509 parameters_type const& parameters,
510 translator_type const& translator,
511 allocators_type & allocators,
512 size_type relative_level)
513 : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
516 inline void operator()(internal_node & n)
518 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level,
520 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level,
523 // next traversing step
524 base::traverse(*this, n); // MAY THROW (V: alloc, copy, N: alloc)
526 base::recalculate_aabb_if_necessary(n);
529 inline void operator()(leaf & n)
531 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
533 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
534 base::m_level == (std::numeric_limits<size_t>::max)(),
537 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
539 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (V: alloc, copy, N: alloc)
541 base::recalculate_aabb_if_necessary(n);
547 // R*-tree insert visitor
548 // After passing the Element to insert visitor the Element is managed by the tree
549 // I.e. one should not delete the node passed to the insert visitor after exception is thrown
550 // because this visitor may delete it
551 template <typename Element, typename MembersHolder>
552 class insert<Element, MembersHolder, insert_reinsert_tag>
553 : public MembersHolder::visitor
555 typedef typename MembersHolder::parameters_type parameters_type;
556 typedef typename MembersHolder::translator_type translator_type;
557 typedef typename MembersHolder::allocators_type allocators_type;
559 typedef typename MembersHolder::node node;
560 typedef typename MembersHolder::internal_node internal_node;
561 typedef typename MembersHolder::leaf leaf;
563 typedef typename allocators_type::node_pointer node_pointer;
564 typedef typename allocators_type::size_type size_type;
567 inline insert(node_pointer & root,
568 size_type & leafs_level,
569 Element const& element,
570 parameters_type const& parameters,
571 translator_type const& translator,
572 allocators_type & allocators,
573 size_type relative_level = 0)
574 : m_root(root), m_leafs_level(leafs_level), m_element(element)
575 , m_parameters(parameters), m_translator(translator)
576 , m_relative_level(relative_level), m_allocators(allocators)
579 inline void operator()(internal_node & n)
581 boost::ignore_unused(n);
582 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root), "current node should be the root");
584 // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
585 if ( m_parameters.get_reinserted_elements() > 0 )
587 rstar::level_insert<0, Element, MembersHolder> lins_v(
588 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
590 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
592 if ( !lins_v.result_elements.empty() )
594 recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
599 visitors::insert<Element, MembersHolder, insert_default_tag> ins_v(
600 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
602 rtree::apply_visitor(ins_v, *m_root);
606 inline void operator()(leaf & n)
608 boost::ignore_unused(n);
609 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<leaf>(*m_root), "current node should be the root");
611 // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
612 if ( m_parameters.get_reinserted_elements() > 0 )
614 rstar::level_insert<0, Element, MembersHolder> lins_v(
615 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
617 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
619 // we're in the root, so root should be split and there should be no elements to reinsert
620 BOOST_GEOMETRY_INDEX_ASSERT(lins_v.result_elements.empty(), "unexpected state");
624 visitors::insert<Element, MembersHolder, insert_default_tag> ins_v(
625 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
627 rtree::apply_visitor(ins_v, *m_root);
632 template <typename Elements>
633 inline void recursive_reinsert(Elements & elements, size_t relative_level)
635 typedef typename Elements::value_type element_type;
637 // reinsert children starting from the minimum distance
638 typename Elements::reverse_iterator it = elements.rbegin();
639 for ( ; it != elements.rend() ; ++it)
641 rstar::level_insert<1, element_type, MembersHolder> lins_v(
642 m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level);
646 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
651 for ( ; it != elements.rend() ; ++it)
652 rtree::destroy_element<MembersHolder>::apply(*it, m_allocators);
653 BOOST_RETHROW // RETHROW
657 BOOST_GEOMETRY_INDEX_ASSERT(relative_level + 1 == lins_v.result_relative_level, "unexpected level");
659 // non-root relative level
660 if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty())
662 recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
667 node_pointer & m_root;
668 size_type & m_leafs_level;
669 Element const& m_element;
671 parameters_type const& m_parameters;
672 translator_type const& m_translator;
674 size_type m_relative_level;
676 allocators_type & m_allocators;
679 }}} // namespace detail::rtree::visitors
681 }}} // namespace boost::geometry::index
683 #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP