mdds
rtree.hpp
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 // SPDX-FileCopyrightText: 2018 - 2025 Kohei Yoshida
4 //
5 // SPDX-License-Identifier: MIT
6 
7 #pragma once
8 
9 #include <deque>
10 #include <vector>
11 #include <cstdlib>
12 #include <string>
13 #include <unordered_set>
14 #include <unordered_map>
15 #include <functional>
16 
17 namespace mdds {
18 
19 namespace detail { namespace rtree {
20 
22 {
26  static constexpr size_t dimensions = 2;
27 
33  static constexpr size_t min_node_size = 40;
34 
39  static constexpr size_t max_node_size = 100;
40 
44  static constexpr size_t max_tree_depth = 100;
45 
50  static constexpr bool enable_forced_reinsertion = true;
51 
57  static constexpr size_t reinsertion_size = 30;
58 };
59 
61 {
68  bool throw_on_first_error = true;
69 
75 };
76 
77 enum class node_type
78 {
79  unspecified,
80  directory_leaf,
81  directory_nonleaf,
82  value
83 };
84 
85 enum class export_tree_type
86 {
91  formatted_node_properties,
92 
102  extent_as_obj,
103 
108  extent_as_svg
109 };
110 
111 enum class search_type
112 {
117  overlap,
118 
123  match,
124 };
125 
126 template<typename _NodePtrT>
128 
129 }} // namespace detail::rtree
130 
131 template<typename KeyT, typename ValueT, typename Traits = detail::rtree::default_rtree_traits>
132 class rtree
133 {
134  using traits_type = Traits;
135 
136  constexpr static size_t max_dist_size = traits_type::max_node_size - traits_type::min_node_size * 2 + 2;
137 
138 public:
139  using key_type = KeyT;
140  using value_type = ValueT;
141 
142  struct point_type
143  {
144  key_type d[traits_type::dimensions];
145 
146  point_type();
147  point_type(std::initializer_list<key_type> vs);
148 
149  std::string to_string() const;
150 
151  bool operator==(const point_type& other) const;
152  bool operator!=(const point_type& other) const;
153  };
154 
155  struct extent_type
156  {
157  point_type start;
158  point_type end;
159 
160  extent_type();
161  extent_type(const point_type& _start, const point_type& _end);
162 
163  std::string to_string() const;
164 
165  bool is_point() const;
166 
167  bool operator==(const extent_type& other) const;
168  bool operator!=(const extent_type& other) const;
169 
179  bool contains(const point_type& pt) const;
180 
190  bool contains(const extent_type& bb) const;
191 
201  bool intersects(const extent_type& bb) const;
202 
207  bool contains_at_boundary(const extent_type& other) const;
208  };
209 
210  using node_type = detail::rtree::node_type;
211  using export_tree_type = detail::rtree::export_tree_type;
212  using search_type = detail::rtree::search_type;
214 
216  {
217  node_type type;
218  extent_type extent;
219  };
220 
221 private:
222  struct node;
223  struct directory_node;
224 
230  struct node_store
231  {
232  node_type type;
234  node_store* parent;
235  node* node_ptr;
236  size_t count;
237 
238  bool valid_pointer;
239 
240  node_store(const node_store&) = delete;
241  node_store& operator=(const node_store&) = delete;
242 
243  node_store();
244  node_store(node_store&& r);
245  node_store(node_type _type, const extent_type& _extent, node* _node_ptr);
246  ~node_store();
247 
248  node_store clone() const;
249 
250  static node_store create_leaf_directory_node();
251  static node_store create_nonleaf_directory_node();
252  static node_store create_value_node(const extent_type& extent, value_type&& v);
253  static node_store create_value_node(const extent_type& extent, const value_type& v);
254 
255  node_store& operator=(node_store&& other);
256 
262  bool pack();
263 
268  void pack_upward();
269 
270  bool is_directory() const;
271  bool is_root() const;
272  bool exceeds_capacity() const;
273 
274  void swap(node_store& other);
275 
281  void reset_parent_pointers_of_children();
282 
288  void reset_parent_pointers();
289 
290  directory_node* get_directory_node();
291  const directory_node* get_directory_node() const;
292 
293  bool erase_child(const node_store* p);
294  };
295 
296  using dir_store_type = std::deque<node_store>;
297 
298  struct dir_store_segment
299  {
300  typename dir_store_type::iterator begin;
301  typename dir_store_type::iterator end;
302  size_t size;
303 
304  dir_store_segment() : size(0)
305  {}
306 
307  dir_store_segment(
308  typename dir_store_type::iterator _begin, typename dir_store_type::iterator _end, size_t _size)
309  : begin(std::move(_begin)), end(std::move(_end)), size(_size)
310  {}
311  };
312 
313  struct distribution
314  {
315  dir_store_segment g1;
316  dir_store_segment g2;
317 
318  distribution(size_t dist, dir_store_type& nodes)
319  {
320  g1.begin = nodes.begin();
321  g1.end = g1.begin;
322  g1.size = traits_type::min_node_size - 1 + dist;
323  std::advance(g1.end, g1.size);
324 
325  g2.begin = g1.end;
326  g2.end = nodes.end();
327  g2.size = nodes.size() - g1.size;
328  }
329  };
330 
331  struct node
332  {
333  node();
334  node(const node&) = delete;
335  ~node();
336  };
337 
338  struct value_node : public node
339  {
340  value_type value;
341 
342  value_node() = delete;
343  value_node(value_type&& _value);
344  value_node(const value_type& _value);
345  ~value_node();
346  };
347 
352  struct directory_node : public node
353  {
354  dir_store_type children;
355 
356  directory_node(const directory_node&) = delete;
357  directory_node& operator=(const directory_node&) = delete;
358 
359  directory_node();
360  ~directory_node();
361 
362  bool erase(const node_store* p);
363 
364  node_store* get_child_with_minimal_overlap(const extent_type& bb);
365  node_store* get_child_with_minimal_area_enlargement(const extent_type& bb);
366 
367  extent_type calc_extent() const;
368  key_type calc_overlap_cost(const extent_type& bb) const;
369  bool has_leaf_directory() const;
370  };
371 
372  struct orphan_node_entry
373  {
374  node_store ns;
375  size_t depth;
376  };
377 
378  using orphan_node_entries_type = std::deque<orphan_node_entry>;
379 
380  struct insertion_point
381  {
382  node_store* ns;
383  size_t depth;
384  };
385 
386 public:
387  template<typename NS>
389  {
390  friend class rtree;
391 
392  protected:
393  using node_store_type = NS;
394 
395  struct entry
396  {
397  node_store_type* ns;
398  size_t depth;
399 
400  entry(node_store_type* _ns, size_t _depth);
401  };
402 
403  using store_type = std::vector<entry>;
404  store_type m_store;
405 
406  void add_node_store(node_store_type* ns, size_t depth);
407  };
408 
409  class const_iterator;
410  class iterator;
411  class search_results;
412 
413  class const_search_results : public search_results_base<const node_store>
414  {
416  using base_type::m_store;
417 
418  public:
419  const_iterator cbegin() const;
420  const_iterator cend() const;
421  const_iterator begin() const;
422  const_iterator end() const;
423  };
424 
425  class search_results : public search_results_base<node_store>
426  {
428  using base_type::m_store;
429 
430  public:
431  iterator begin();
432  iterator end();
433  };
434 
435  template<typename _SelfIter, typename _StoreIter, typename _ValueT>
437  {
438  public:
439  using store_iterator_type = _StoreIter;
440  using self_iterator_type = _SelfIter;
441 
442  protected:
443  store_iterator_type m_pos;
444 
445  iterator_base(store_iterator_type pos);
446 
447  public:
448  // iterator traits
449  using value_type = _ValueT;
450  using pointer = value_type*;
451  using reference = value_type&;
452  using difference_type = std::ptrdiff_t;
453  using iterator_category = std::bidirectional_iterator_tag;
454 
455  bool operator==(const self_iterator_type& other) const;
456  bool operator!=(const self_iterator_type& other) const;
457 
458  self_iterator_type& operator++();
459  self_iterator_type operator++(int);
460 
461  self_iterator_type& operator--();
462  self_iterator_type operator--(int);
463 
464  const extent_type& extent() const;
465  size_t depth() const;
466  };
467 
469  : public iterator_base<
470  const_iterator, typename const_search_results::store_type::const_iterator, const rtree::value_type>
471  {
472  using base_type = iterator_base<
473  const_iterator, typename const_search_results::store_type::const_iterator, const rtree::value_type>;
474 
475  using store_type = typename const_search_results::store_type;
476  using base_type::m_pos;
477  using typename base_type::store_iterator_type;
478 
479  friend class rtree;
480 
481  const_iterator(store_iterator_type pos);
482 
483  public:
484  using typename base_type::value_type;
485 
486  value_type& operator*() const
487  {
488  return static_cast<const value_node*>(m_pos->ns->node_ptr)->value;
489  }
490 
491  value_type* operator->() const
492  {
493  return &operator*();
494  }
495  };
496 
497  class iterator : public iterator_base<iterator, typename search_results::store_type::iterator, rtree::value_type>
498  {
500 
501  using store_type = typename const_search_results::store_type;
502  using base_type::m_pos;
503  using typename base_type::store_iterator_type;
504 
505  friend class rtree;
506 
507  iterator(store_iterator_type pos);
508 
509  public:
510  using typename base_type::value_type;
511 
512  value_type& operator*()
513  {
514  return static_cast<value_node*>(m_pos->ns->node_ptr)->value;
515  }
516 
517  value_type* operator->()
518  {
519  return &operator*();
520  }
521  };
522 
529  {
530  dir_store_type m_store;
531 
532  public:
533  bulk_loader();
534 
535  void insert(const extent_type& extent, value_type&& value);
536  void insert(const extent_type& extent, const value_type& value);
537 
538  void insert(const point_type& position, value_type&& value);
539  void insert(const point_type& position, const value_type& value);
540 
541  rtree pack();
542 
543  private:
544  void pack_level(dir_store_type& store, size_t depth);
545 
546  void insert_impl(const extent_type& extent, value_type&& value);
547  void insert_impl(const extent_type& extent, const value_type& value);
548  };
549 
550  rtree();
551  rtree(rtree&& other);
552  rtree(const rtree& other);
553 
554 private:
555  rtree(node_store&& root); // only used internally by bulk_loader.
556 
557 public:
558  ~rtree();
559 
560  rtree& operator=(const rtree& other);
561 
562  rtree& operator=(rtree&& other);
563 
571  void insert(const extent_type& extent, value_type&& value);
572 
580  void insert(const extent_type& extent, const value_type& value);
581 
589  void insert(const point_type& position, value_type&& value);
590 
598  void insert(const point_type& position, const value_type& value);
599 
611  const_search_results search(const point_type& pt, search_type st) const;
612 
624  search_results search(const point_type& pt, search_type st);
625 
638  const_search_results search(const extent_type& extent, search_type st) const;
639 
652  search_results search(const extent_type& extent, search_type st);
653 
663  void erase(const_iterator pos);
664 
674  void erase(iterator pos);
675 
683  const extent_type& extent() const;
684 
690  bool empty() const;
691 
697  size_t size() const;
698 
704  void swap(rtree& other);
705 
709  void clear();
710 
717  template<typename FuncT>
718  void walk(FuncT func) const;
719 
727  void check_integrity(const integrity_check_properties& props) const;
728 
737  std::string export_tree(export_tree_type mode) const;
738 
739 private:
740  void insert_impl(const point_type& start, const point_type& end, value_type&& value);
741  void insert_impl(const point_type& start, const point_type& end, const value_type& value);
742 
743  void erase_impl(const node_store* ns, size_t depth);
744 
750  detail::rtree::ptr_to_string<const node_store*> build_ptr_to_string_map() const;
751 
752  std::string export_tree_formatted() const;
753  std::string export_tree_extent_as_obj() const;
754  std::string export_tree_extent_as_svg() const;
755 
756  void insert(node_store&& ns, std::unordered_set<size_t>* reinserted_depths);
757  void insert_dir(node_store&& ns, size_t max_depth);
758 
766  void split_node(node_store* ns);
767 
768  void perform_forced_reinsertion(node_store* ns, std::unordered_set<size_t>& reinserted_depth);
769 
776  void sort_dir_store_by_split_dimension(dir_store_type& children);
777 
778  void sort_dir_store_by_dimension(size_t dim, dir_store_type& children);
779 
780  size_t pick_optimal_distribution(dir_store_type& children) const;
781 
782  insertion_point find_leaf_directory_node_for_insertion(const extent_type& bb);
783  node_store* find_nonleaf_directory_node_for_insertion(const extent_type& bb, size_t max_depth);
784 
785  template<typename FuncT>
786  void descend_with_func(FuncT func) const;
787 
788  using search_condition_type = std::function<bool(const node_store&)>;
789 
790  template<typename _ResT>
791  void search_descend(
792  size_t depth, const search_condition_type& dir_cond, const search_condition_type& value_cond,
793  typename _ResT::node_store_type& ns, _ResT& results) const;
794 
795  void shrink_tree_upward(node_store* ns, const extent_type& bb_affected);
796 
797 private:
798  node_store m_root;
799 };
800 
801 } // namespace mdds
802 
803 #include "rtree_def.inl"
804 
805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool intersects(const extent_type &bb) const
bool error_on_min_node_size
Definition: rtree.hpp:74
Definition: rtree.hpp:497
Definition: rtree.hpp:436
Definition: rtree.hpp:142
bool contains_at_boundary(const extent_type &other) const
size_t size() const
static constexpr size_t max_tree_depth
Definition: rtree.hpp:44
void insert(const extent_type &extent, value_type &&value)
Definition: rtree.hpp:388
const_search_results search(const point_type &pt, search_type st) const
void check_integrity(const integrity_check_properties &props) const
Definition: rtree.hpp:215
static constexpr size_t max_node_size
Definition: rtree.hpp:39
Definition: rtree.hpp:468
Definition: rtree.hpp:528
void clear()
void walk(FuncT func) const
bool empty() const
static constexpr size_t reinsertion_size
Definition: rtree.hpp:57
Definition: rtree.hpp:132
static constexpr size_t min_node_size
Definition: rtree.hpp:33
Definition: rtree.hpp:127
bool throw_on_first_error
Definition: rtree.hpp:68
Definition: cref_wrapper.hpp:12
bool contains(const point_type &pt) const
Definition: rtree.hpp:155
static constexpr bool enable_forced_reinsertion
Definition: rtree.hpp:50
Definition: rtree.hpp:413
void swap(rtree &other)
Definition: rtree.hpp:425
const extent_type & extent() const
std::string export_tree(export_tree_type mode) const
static constexpr size_t dimensions
Definition: rtree.hpp:26
void erase(const_iterator pos)