mdds
Loading...
Searching...
No Matches
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
17namespace mdds {
18
19namespace 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
76
77enum class node_type
78{
79 unspecified,
80 directory_leaf,
81 directory_nonleaf,
82 value
83};
84
85enum class export_tree_type
86{
91 formatted_node_properties,
92
102 extent_as_obj,
103
108 extent_as_svg
109};
110
111enum class search_type
112{
117 overlap,
118
123 match,
124};
125
126template<typename _NodePtrT>
128
129}} // namespace detail::rtree
130
131template<typename KeyT, typename ValueT, typename Traits = detail::rtree::default_rtree_traits>
132class 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
138public:
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;
213 using integrity_check_properties = detail::rtree::integrity_check_properties;
214
216 {
217 node_type type;
218 extent_type extent;
219 };
220
221private:
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
386public:
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 {
427 using base_type = search_results_base<node_store>;
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>
436 class iterator_base
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
468 class const_iterator
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 {
499 using base_type = iterator_base<iterator, typename search_results::store_type::iterator, rtree::value_type>;
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
528 class bulk_loader
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
554private:
555 rtree(node_store&& root); // only used internally by bulk_loader.
556
557public:
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
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
739private:
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
797private:
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: */
Definition rtree.hpp:471
Definition rtree.hpp:414
Definition rtree.hpp:498
Definition rtree.hpp:389
Definition rtree.hpp:426
void walk(FuncT func) const
void clear()
void insert(const extent_type &extent, value_type &&value)
void erase(iterator pos)
const_search_results search(const extent_type &extent, search_type st) const
search_results search(const extent_type &extent, search_type st)
std::string export_tree(export_tree_type mode) const
size_t size() const
void swap(rtree &other)
void check_integrity(const integrity_check_properties &props) const
search_results search(const point_type &pt, search_type st)
void insert(const point_type &position, const value_type &value)
void erase(const_iterator pos)
void insert(const point_type &position, value_type &&value)
const extent_type & extent() const
void insert(const extent_type &extent, const value_type &value)
bool empty() const
const_search_results search(const point_type &pt, search_type st) const
static constexpr size_t reinsertion_size
Definition rtree.hpp:57
static constexpr size_t dimensions
Definition rtree.hpp:26
static constexpr size_t max_tree_depth
Definition rtree.hpp:44
static constexpr size_t max_node_size
Definition rtree.hpp:39
static constexpr size_t min_node_size
Definition rtree.hpp:33
static constexpr bool enable_forced_reinsertion
Definition rtree.hpp:50
bool throw_on_first_error
Definition rtree.hpp:68
bool error_on_min_node_size
Definition rtree.hpp:74
Definition rtree.hpp:127
Definition rtree.hpp:156
bool contains(const point_type &pt) const
bool intersects(const extent_type &bb) const
bool contains(const extent_type &bb) const
bool contains_at_boundary(const extent_type &other) const
Definition rtree.hpp:216
Definition rtree.hpp:143