mdds
quad_node.hpp
1 // SPDX-FileCopyrightText: 2010 - 2025 Kohei Yoshida
2 //
3 // SPDX-License-Identifier: MIT
4 
5 #pragma once
6 
7 #include "mdds/global.hpp"
8 
9 #include <cassert>
10 
11 #include <boost/intrusive_ptr.hpp>
12 
13 namespace mdds {
14 
15 #ifdef MDDS_DEBUG_NODE_BASE
16 size_t node_instance_count = 0;
17 inline size_t get_node_instance_count()
18 {
19  return node_instance_count;
20 }
21 #endif
22 
28 enum node_quadrant_t
29 {
30  quad_northeast,
31  quad_northwest,
32  quad_southeast,
33  quad_southwest,
34  quad_unspecified
35 };
36 
44 enum search_region_space_t
45 {
46  region_northwest,
47  region_north,
48  region_northeast,
49  region_east,
50  region_southeast,
51  region_south,
52  region_southwest,
53  region_west,
54  region_center
55 };
56 
66 enum direction_t
67 {
68  dir_north,
69  dir_west,
70  dir_south,
71  dir_east
72 };
73 
74 inline node_quadrant_t opposite(node_quadrant_t quad)
75 {
76  switch (quad)
77  {
78  case quad_northeast:
79  return quad_southwest;
80  case quad_northwest:
81  return quad_southeast;
82  case quad_southeast:
83  return quad_northwest;
84  case quad_southwest:
85  return quad_northeast;
86  case quad_unspecified:
87  default:;
88  }
89  return quad_unspecified;
90 }
91 
92 template<typename _NodePtr, typename _NodeType, typename _Key>
94 {
95  typedef _Key key_type;
96  typedef _NodePtr node_ptr;
97  typedef _NodeType node_type;
98 
99  size_t refcount;
100 
101  node_ptr parent;
102  node_ptr northeast;
103  node_ptr northwest;
104  node_ptr southeast;
105  node_ptr southwest;
106 
107  key_type x;
108  key_type y;
109 
110  quad_node_base(key_type _x, key_type _y)
111  : refcount(0), parent(nullptr), northeast(nullptr), northwest(nullptr), southeast(nullptr), southwest(nullptr),
112  x(_x), y(_y)
113  {
114 #ifdef MDDS_DEBUG_NODE_BASE
115  ++node_instance_count;
116 #endif
117  }
118 
124  : refcount(0), parent(nullptr), northeast(nullptr), northwest(nullptr), southeast(nullptr), southwest(nullptr),
125  x(r.x), y(r.y)
126  {
127 #ifdef MDDS_DEBUG_NODE_BASE
128  ++node_instance_count;
129 #endif
130  }
131 
132  bool leaf() const
133  {
134  return !northeast && !northwest && !southeast && !southwest;
135  }
136 
137  bool operator==(const quad_node_base& r) const
138  {
139  return x == r.x && y == r.y;
140  }
141 
146  {
147  if (this == &r)
148  // assignment to self.
149  return *this;
150 
151  x = r.x;
152  y = r.y;
153  return *this;
154  }
155 
156  ~quad_node_base()
157  {
158 #ifdef MDDS_DEBUG_NODE_BASE
159  --node_instance_count;
160 #endif
161  static_cast<node_type*>(this)->dispose();
162  }
163 
170  node_quadrant_t get_quadrant(key_type other_x, key_type other_y) const
171  {
172  if (other_x < x)
173  // west
174  return other_y < y ? quad_northwest : quad_southwest;
175 
176  // east
177  return other_y < y ? quad_northeast : quad_southeast;
178  }
179 
180  bool has_quadrant_node(node_quadrant_t quad) const
181  {
182  switch (quad)
183  {
184  case quad_northeast:
185  return northeast.get() != nullptr;
186  case quad_northwest:
187  return northwest.get() != nullptr;
188  case quad_southeast:
189  return southeast.get() != nullptr;
190  case quad_southwest:
191  return southwest.get() != nullptr;
192  default:
193  throw general_error("unknown quadrant type");
194  }
195  return false;
196  }
197 
198  node_ptr get_quadrant_node(node_quadrant_t quad) const
199  {
200  node_ptr ret;
201  switch (quad)
202  {
203  case quad_northeast:
204  ret = northeast;
205  break;
206  case quad_northwest:
207  ret = northwest;
208  break;
209  case quad_southeast:
210  ret = southeast;
211  break;
212  case quad_southwest:
213  ret = southwest;
214  break;
215  default:
216  throw general_error("unknown quadrant type");
217  }
218  return ret;
219  }
220 };
221 
222 template<typename _NodePtr, typename _NodeType, typename _Key>
223 inline void intrusive_ptr_add_ref(::mdds::quad_node_base<_NodePtr, _NodeType, _Key>* p)
224 {
225  ++p->refcount;
226 }
227 
228 template<typename _NodePtr, typename _NodeType, typename _Key>
229 inline void intrusive_ptr_release(::mdds::quad_node_base<_NodePtr, _NodeType, _Key>* p)
230 {
231  --p->refcount;
232  if (!p->refcount)
233  delete p;
234 }
235 
236 template<typename _NodePtr>
237 void disconnect_node_from_parent(_NodePtr p)
238 {
239  if (!p || !p->parent)
240  // Nothing to do.
241  return;
242 
243  _NodePtr& parent = p->parent;
244  if (parent->northeast && parent->northeast == p)
245  {
246  parent->northeast.reset();
247  }
248  else if (parent->northwest && parent->northwest == p)
249  {
250  parent->northwest.reset();
251  }
252  else if (parent->southwest && parent->southwest == p)
253  {
254  parent->southwest.reset();
255  }
256  else if (parent->southeast && parent->southeast == p)
257  {
258  parent->southeast.reset();
259  }
260  else
261  throw general_error("parent node doesn't lead to the deleted node.");
262 }
263 
264 template<typename _NodePtr>
265 void disconnect_all_nodes(_NodePtr p)
266 {
267  if (!p)
268  return;
269 
270  if (p->northeast)
271  {
272  disconnect_all_nodes(p->northeast);
273  p->northeast.reset();
274  }
275 
276  if (p->northwest)
277  {
278  disconnect_all_nodes(p->northwest);
279  p->northwest.reset();
280  }
281 
282  if (p->southeast)
283  {
284  disconnect_all_nodes(p->southeast);
285  p->southeast.reset();
286  }
287 
288  if (p->southwest)
289  {
290  disconnect_all_nodes(p->southwest);
291  p->southwest.reset();
292  }
293 
294  p->parent.reset();
295 }
296 
297 template<typename _NodeType, typename _Key>
298 search_region_space_t get_search_region_space(_NodeType* p, _Key x1, _Key y1, _Key x2, _Key y2)
299 {
300  typedef _Key key_type;
301 
302  key_type x = p->x, y = p->y;
303  if (x < x1)
304  {
305  // western region
306  if (y < y1)
307  {
308  return region_northwest;
309  }
310  else if (y1 <= y && y <= y2)
311  {
312  return region_west;
313  }
314 
315  assert(y2 < y);
316  return region_southwest;
317  }
318  else if (x1 <= x && x <= x2)
319  {
320  // central region
321  if (y < y1)
322  {
323  return region_north;
324  }
325  else if (y1 <= y && y <= y2)
326  {
327  return region_center;
328  }
329 
330  assert(y2 < y);
331  return region_south;
332  }
333 
334  // eastern region
335  assert(x2 < x);
336  if (y < y1)
337  {
338  return region_northeast;
339  }
340  else if (y1 <= y && y <= y2)
341  {
342  return region_east;
343  }
344 
345  assert(y2 < y);
346  return region_southeast;
347 }
348 
349 } // namespace mdds
quad_node_base(const quad_node_base &r)
Definition: quad_node.hpp:123
Definition: global.hpp:59
Definition: cref_wrapper.hpp:12
quad_node_base & operator=(const quad_node_base &r)
Definition: quad_node.hpp:145
Definition: quad_node.hpp:93
node_quadrant_t get_quadrant(key_type other_x, key_type other_y) const
Definition: quad_node.hpp:170