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-2020.
8 // Modifications copyright (c) 2019-2020 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/index/detail/algorithms/content.hpp>
24 namespace boost { namespace geometry { namespace index {
26 namespace detail { namespace rtree { namespace visitors {
30 // Utility to distinguish between default and non-default index strategy
31 template <typename Point1, typename Point2, typename Strategy>
32 struct comparable_distance_point_point
34 typedef typename Strategy::comparable_distance_point_point_strategy_type strategy_type;
35 typedef typename geometry::comparable_distance_result
37 Point1, Point2, strategy_type
40 static inline strategy_type get_strategy(Strategy const& strategy)
42 return strategy.get_comparable_distance_point_point_strategy();
46 template <typename Point1, typename Point2>
47 struct comparable_distance_point_point<Point1, Point2, default_strategy>
49 typedef default_strategy strategy_type;
50 typedef typename geometry::default_comparable_distance_result
55 static inline strategy_type get_strategy(default_strategy const& )
57 return strategy_type();
61 template <typename MembersHolder>
62 class remove_elements_to_reinsert
65 typedef typename MembersHolder::box_type box_type;
66 typedef typename MembersHolder::parameters_type parameters_type;
67 typedef typename MembersHolder::translator_type translator_type;
68 typedef typename MembersHolder::allocators_type allocators_type;
70 typedef typename MembersHolder::node node;
71 typedef typename MembersHolder::internal_node internal_node;
72 typedef typename MembersHolder::leaf leaf;
74 //typedef typename Allocators::internal_node_pointer internal_node_pointer;
75 typedef internal_node * internal_node_pointer;
77 template <typename ResultElements, typename Node>
78 static inline void apply(ResultElements & result_elements,
80 internal_node_pointer parent,
81 size_t current_child_index,
82 parameters_type const& parameters,
83 translator_type const& translator,
84 allocators_type & allocators)
86 typedef typename rtree::elements_type<Node>::type elements_type;
87 typedef typename elements_type::value_type element_type;
88 typedef typename geometry::point_type<box_type>::type point_type;
89 typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
90 // TODO: awulkiew - change second point_type to the point type of the Indexable?
91 typedef rstar::comparable_distance_point_point
93 point_type, point_type, strategy_type
94 > comparable_distance_pp;
95 typedef typename comparable_distance_pp::result_type comparable_distance_type;
97 elements_type & elements = rtree::elements(n);
99 const size_t elements_count = parameters.get_max_elements() + 1;
100 const size_t reinserted_elements_count = (::std::min)(parameters.get_reinserted_elements(), elements_count - parameters.get_min_elements());
102 BOOST_GEOMETRY_INDEX_ASSERT(parent, "node shouldn't be the root node");
103 BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected elements number");
104 BOOST_GEOMETRY_INDEX_ASSERT(0 < reinserted_elements_count, "wrong value of elements to reinsert");
106 // calculate current node's center
107 point_type node_center;
108 geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center);
110 // fill the container of centers' distances of children from current node's center
111 typedef typename index::detail::rtree::container_from_elements_type<
113 std::pair<comparable_distance_type, element_type>
114 >::type sorted_elements_type;
116 sorted_elements_type sorted_elements;
117 // If constructor is used instead of resize() MS implementation leaks here
118 sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
120 typename comparable_distance_pp::strategy_type
121 cdist_strategy = comparable_distance_pp::get_strategy(index::detail::get_strategy(parameters));
123 for ( typename elements_type::const_iterator it = elements.begin() ;
124 it != elements.end() ; ++it )
126 point_type element_center;
127 geometry::centroid( rtree::element_indexable(*it, translator), element_center);
128 sorted_elements.push_back(std::make_pair(
129 geometry::comparable_distance(node_center, element_center, cdist_strategy),
130 *it)); // MAY THROW (V, E: copy)
133 // sort elements by distances from center
135 sorted_elements.begin(),
136 sorted_elements.begin() + reinserted_elements_count,
137 sorted_elements.end(),
138 distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
140 // copy elements which will be reinserted
141 result_elements.clear();
142 result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
143 for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
144 it != sorted_elements.begin() + reinserted_elements_count ; ++it )
146 result_elements.push_back(it->second); // MAY THROW (V, E: copy)
151 // copy remaining elements to the current node
153 elements.reserve(elements_count - reinserted_elements_count); // SHOULDN'T THROW (new_size <= old size)
154 for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() + reinserted_elements_count;
155 it != sorted_elements.end() ; ++it )
157 elements.push_back(it->second); // MAY THROW (V, E: copy)
164 for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ;
165 it != sorted_elements.end() ; ++it )
167 destroy_element<MembersHolder>::apply(it->second, allocators);
170 BOOST_RETHROW // RETHROW
174 ::boost::ignore_unused(parameters);
178 template <typename Distance, typename El>
179 static inline bool distances_asc(
180 std::pair<Distance, El> const& d1,
181 std::pair<Distance, El> const& d2)
183 return d1.first < d2.first;
186 template <typename Distance, typename El>
187 static inline bool distances_dsc(
188 std::pair<Distance, El> const& d1,
189 std::pair<Distance, El> const& d2)
191 return d1.first > d2.first;
199 typename MembersHolder,
200 bool IsValue = std::is_same<Element, typename MembersHolder::value_type>::value
202 struct level_insert_elements_type
204 typedef typename rtree::elements_type<
205 typename rtree::internal_node<
206 typename MembersHolder::value_type,
207 typename MembersHolder::parameters_type,
208 typename MembersHolder::box_type,
209 typename MembersHolder::allocators_type,
210 typename MembersHolder::node_tag
215 template <typename Value, typename MembersHolder>
216 struct level_insert_elements_type<0, Value, MembersHolder, true>
218 typedef typename rtree::elements_type<
219 typename rtree::leaf<
220 typename MembersHolder::value_type,
221 typename MembersHolder::parameters_type,
222 typename MembersHolder::box_type,
223 typename MembersHolder::allocators_type,
224 typename MembersHolder::node_tag
229 template <size_t InsertIndex, typename Element, typename MembersHolder>
230 struct level_insert_base
231 : public detail::insert<Element, MembersHolder>
233 typedef detail::insert<Element, MembersHolder> base;
234 typedef typename base::node node;
235 typedef typename base::internal_node internal_node;
236 typedef typename base::leaf leaf;
238 typedef typename level_insert_elements_type<InsertIndex, Element, MembersHolder>::type elements_type;
239 typedef typename index::detail::rtree::container_from_elements_type<
241 typename elements_type::value_type
242 >::type result_elements_type;
244 typedef typename MembersHolder::box_type box_type;
245 typedef typename MembersHolder::parameters_type parameters_type;
246 typedef typename MembersHolder::translator_type translator_type;
247 typedef typename MembersHolder::allocators_type allocators_type;
249 typedef typename allocators_type::node_pointer node_pointer;
250 typedef typename allocators_type::size_type size_type;
252 inline level_insert_base(node_pointer & root,
253 size_type & leafs_level,
254 Element const& element,
255 parameters_type const& parameters,
256 translator_type const& translator,
257 allocators_type & allocators,
258 size_type relative_level)
259 : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
260 , result_relative_level(0)
263 template <typename Node>
264 inline void handle_possible_reinsert_or_split_of_root(Node &n)
266 BOOST_GEOMETRY_INDEX_ASSERT(result_elements.empty(), "reinsert should be handled only once for level");
268 result_relative_level = base::m_leafs_level - base::m_traverse_data.current_level;
271 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
273 // node isn't root node
274 if ( !base::m_traverse_data.current_is_root() )
276 // NOTE: exception-safety
277 // After an exception result_elements may contain garbage, don't use it
278 rstar::remove_elements_to_reinsert<MembersHolder>::apply(
280 base::m_traverse_data.parent, base::m_traverse_data.current_child_index,
281 base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW, BASIC (V, E: alloc, copy)
286 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*base::m_root_node), "node should be the root node");
287 base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
292 template <typename Node>
293 inline void handle_possible_split(Node &n) const
296 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
298 base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
302 template <typename Node>
303 inline void recalculate_aabb_if_necessary(Node const& n) const
305 if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() )
307 // calulate node's new box
312 template <typename Node>
313 inline void recalculate_aabb(Node const& n) const
315 base::m_traverse_data.current_element().first =
316 elements_box<box_type>(rtree::elements(n).begin(), rtree::elements(n).end(),
318 index::detail::get_strategy(base::m_parameters));
321 inline void recalculate_aabb(leaf const& n) const
323 base::m_traverse_data.current_element().first =
324 values_box<box_type>(rtree::elements(n).begin(), rtree::elements(n).end(),
326 index::detail::get_strategy(base::m_parameters));
329 size_type result_relative_level;
330 result_elements_type result_elements;
337 typename MembersHolder,
338 bool IsValue = std::is_same<Element, typename MembersHolder::value_type>::value
341 : public level_insert_base<InsertIndex, Element, MembersHolder>
343 typedef level_insert_base<InsertIndex, Element, MembersHolder> base;
344 typedef typename base::node node;
345 typedef typename base::internal_node internal_node;
346 typedef typename base::leaf leaf;
348 typedef typename base::parameters_type parameters_type;
349 typedef typename base::translator_type translator_type;
350 typedef typename base::allocators_type allocators_type;
352 typedef typename base::node_pointer node_pointer;
353 typedef typename base::size_type size_type;
355 inline level_insert(node_pointer & root,
356 size_type & leafs_level,
357 Element const& element,
358 parameters_type const& parameters,
359 translator_type const& translator,
360 allocators_type & allocators,
361 size_type relative_level)
362 : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
365 inline void operator()(internal_node & n)
367 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
369 if ( base::m_traverse_data.current_level < base::m_level )
371 // next traversing step
372 base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc)
375 if ( 0 < InsertIndex )
377 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
379 if ( base::m_traverse_data.current_level == base::m_level - 1 )
381 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
387 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
391 // push new child node
392 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
396 // NOTE: exception-safety
397 // if the insert fails above, the element won't be stored in the tree, so delete it
399 rtree::visitors::destroy<MembersHolder>::apply(base::m_element.second, base::m_allocators);
401 BOOST_RETHROW // RETHROW
406 if ( 0 == InsertIndex )
408 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
410 // not the first insert
413 base::handle_possible_split(n); // MAY THROW (E: alloc, N: alloc)
417 base::recalculate_aabb_if_necessary(n);
420 inline void operator()(leaf &)
422 BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
426 template <size_t InsertIndex, typename Value, typename MembersHolder>
427 struct level_insert<InsertIndex, Value, MembersHolder, true>
428 : public level_insert_base<InsertIndex, typename MembersHolder::value_type, MembersHolder>
430 typedef level_insert_base<InsertIndex, typename MembersHolder::value_type, MembersHolder> base;
431 typedef typename base::node node;
432 typedef typename base::internal_node internal_node;
433 typedef typename base::leaf leaf;
435 typedef typename MembersHolder::value_type value_type;
436 typedef typename base::parameters_type parameters_type;
437 typedef typename base::translator_type translator_type;
438 typedef typename base::allocators_type allocators_type;
440 typedef typename base::node_pointer node_pointer;
441 typedef typename base::size_type size_type;
443 inline level_insert(node_pointer & root,
444 size_type & leafs_level,
446 parameters_type const& parameters,
447 translator_type const& translator,
448 allocators_type & allocators,
449 size_type relative_level)
450 : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
453 inline void operator()(internal_node & n)
455 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
456 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
458 // next traversing step
459 base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc)
461 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
463 if ( base::m_traverse_data.current_level == base::m_level - 1 )
465 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
468 base::recalculate_aabb_if_necessary(n);
471 inline void operator()(leaf & n)
473 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
475 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
476 base::m_level == (std::numeric_limits<size_t>::max)(),
479 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
481 base::handle_possible_split(n); // MAY THROW (V: alloc, copy, N: alloc)
485 template <typename Value, typename MembersHolder>
486 struct level_insert<0, Value, MembersHolder, true>
487 : public level_insert_base<0, typename MembersHolder::value_type, MembersHolder>
489 typedef level_insert_base<0, typename MembersHolder::value_type, MembersHolder> base;
490 typedef typename base::node node;
491 typedef typename base::internal_node internal_node;
492 typedef typename base::leaf leaf;
494 typedef typename MembersHolder::value_type value_type;
495 typedef typename base::parameters_type parameters_type;
496 typedef typename base::translator_type translator_type;
497 typedef typename base::allocators_type allocators_type;
499 typedef typename base::node_pointer node_pointer;
500 typedef typename base::size_type size_type;
502 inline level_insert(node_pointer & root,
503 size_type & leafs_level,
505 parameters_type const& parameters,
506 translator_type const& translator,
507 allocators_type & allocators,
508 size_type relative_level)
509 : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
512 inline void operator()(internal_node & n)
514 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level,
516 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level,
519 // next traversing step
520 base::traverse(*this, n); // MAY THROW (V: alloc, copy, N: alloc)
522 base::recalculate_aabb_if_necessary(n);
525 inline void operator()(leaf & n)
527 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
529 BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
530 base::m_level == (std::numeric_limits<size_t>::max)(),
533 rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
535 base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (V: alloc, copy, N: alloc)
537 base::recalculate_aabb_if_necessary(n);
543 // R*-tree insert visitor
544 // After passing the Element to insert visitor the Element is managed by the tree
545 // I.e. one should not delete the node passed to the insert visitor after exception is thrown
546 // because this visitor may delete it
547 template <typename Element, typename MembersHolder>
548 class insert<Element, MembersHolder, insert_reinsert_tag>
549 : public MembersHolder::visitor
551 typedef typename MembersHolder::parameters_type parameters_type;
552 typedef typename MembersHolder::translator_type translator_type;
553 typedef typename MembersHolder::allocators_type allocators_type;
555 typedef typename MembersHolder::node node;
556 typedef typename MembersHolder::internal_node internal_node;
557 typedef typename MembersHolder::leaf leaf;
559 typedef typename allocators_type::node_pointer node_pointer;
560 typedef typename allocators_type::size_type size_type;
563 inline insert(node_pointer & root,
564 size_type & leafs_level,
565 Element const& element,
566 parameters_type const& parameters,
567 translator_type const& translator,
568 allocators_type & allocators,
569 size_type relative_level = 0)
570 : m_root(root), m_leafs_level(leafs_level), m_element(element)
571 , m_parameters(parameters), m_translator(translator)
572 , m_relative_level(relative_level), m_allocators(allocators)
575 inline void operator()(internal_node & n)
577 boost::ignore_unused(n);
578 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root), "current node should be the root");
580 // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
581 if ( m_parameters.get_reinserted_elements() > 0 )
583 rstar::level_insert<0, Element, MembersHolder> lins_v(
584 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
586 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
588 if ( !lins_v.result_elements.empty() )
590 recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
595 visitors::insert<Element, MembersHolder, insert_default_tag> ins_v(
596 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
598 rtree::apply_visitor(ins_v, *m_root);
602 inline void operator()(leaf & n)
604 boost::ignore_unused(n);
605 BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<leaf>(*m_root), "current node should be the root");
607 // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
608 if ( m_parameters.get_reinserted_elements() > 0 )
610 rstar::level_insert<0, Element, MembersHolder> lins_v(
611 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
613 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
615 // we're in the root, so root should be split and there should be no elements to reinsert
616 BOOST_GEOMETRY_INDEX_ASSERT(lins_v.result_elements.empty(), "unexpected state");
620 visitors::insert<Element, MembersHolder, insert_default_tag> ins_v(
621 m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
623 rtree::apply_visitor(ins_v, *m_root);
628 template <typename Elements>
629 inline void recursive_reinsert(Elements & elements, size_t relative_level)
631 typedef typename Elements::value_type element_type;
633 // reinsert children starting from the minimum distance
634 typename Elements::reverse_iterator it = elements.rbegin();
635 for ( ; it != elements.rend() ; ++it)
637 rstar::level_insert<1, element_type, MembersHolder> lins_v(
638 m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level);
642 rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
647 for ( ; it != elements.rend() ; ++it)
648 rtree::destroy_element<MembersHolder>::apply(*it, m_allocators);
649 BOOST_RETHROW // RETHROW
653 BOOST_GEOMETRY_INDEX_ASSERT(relative_level + 1 == lins_v.result_relative_level, "unexpected level");
655 // non-root relative level
656 if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty())
658 recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
663 node_pointer & m_root;
664 size_type & m_leafs_level;
665 Element const& m_element;
667 parameters_type const& m_parameters;
668 translator_type const& m_translator;
670 size_type m_relative_level;
672 allocators_type & m_allocators;
675 }}} // namespace detail::rtree::visitors
677 }}} // namespace boost::geometry::index
679 #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP