mdds
quad_node.hpp
1 /*************************************************************************
2  *
3  * Copyright (c) 2010 Kohei Yoshida
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use,
9  * copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following
12  * conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  *
26  ************************************************************************/
27 
28 #ifndef __MDDS_QUAD_NODE_HPP__
29 #define __MDDS_QUAD_NODE_HPP__
30 
31 #include "mdds/global.hpp"
32 
33 #include <cassert>
34 
35 #include <boost/intrusive_ptr.hpp>
36 
37 namespace mdds {
38 
39 #ifdef MDDS_DEBUG_NODE_BASE
40 size_t node_instance_count = 0;
41 inline size_t get_node_instance_count()
42 {
43  return node_instance_count;
44 }
45 #endif
46 
52 enum node_quadrant_t
53 {
54  quad_northeast,
55  quad_northwest,
56  quad_southeast,
57  quad_southwest,
58  quad_unspecified
59 };
60 
68 enum search_region_space_t
69 {
70  region_northwest,
71  region_north,
72  region_northeast,
73  region_east,
74  region_southeast,
75  region_south,
76  region_southwest,
77  region_west,
78  region_center
79 };
80 
90 enum direction_t
91 {
92  dir_north,
93  dir_west,
94  dir_south,
95  dir_east
96 };
97 
98 inline node_quadrant_t opposite(node_quadrant_t quad)
99 {
100  switch (quad)
101  {
102  case quad_northeast:
103  return quad_southwest;
104  case quad_northwest:
105  return quad_southeast;
106  case quad_southeast:
107  return quad_northwest;
108  case quad_southwest:
109  return quad_northeast;
110  case quad_unspecified:
111  default:
112  ;
113  }
114  return quad_unspecified;
115 }
116 
117 template<typename _NodePtr, typename _NodeType, typename _Key>
119 {
120  typedef _Key key_type;
121  typedef _NodePtr node_ptr;
122  typedef _NodeType node_type;
123 
124  size_t refcount;
125 
126  node_ptr parent;
127  node_ptr northeast;
128  node_ptr northwest;
129  node_ptr southeast;
130  node_ptr southwest;
131 
132  key_type x;
133  key_type y;
134 
135  quad_node_base(key_type _x, key_type _y) :
136  refcount(0),
137  parent(nullptr),
138  northeast(nullptr),
139  northwest(nullptr),
140  southeast(nullptr),
141  southwest(nullptr),
142  x(_x),
143  y(_y)
144  {
145 #ifdef MDDS_DEBUG_NODE_BASE
146  ++node_instance_count;
147 #endif
148  }
149 
155  refcount(0),
156  parent(nullptr),
157  northeast(nullptr),
158  northwest(nullptr),
159  southeast(nullptr),
160  southwest(nullptr),
161  x(r.x),
162  y(r.y)
163  {
164 #ifdef MDDS_DEBUG_NODE_BASE
165  ++node_instance_count;
166 #endif
167  }
168 
169  bool leaf() const
170  {
171  return !northeast && !northwest && !southeast && !southwest;
172  }
173 
174  bool operator==(const quad_node_base& r) const
175  {
176  return x == r.x && y == r.y;
177  }
178 
183  {
184  if (this == &r)
185  // assignment to self.
186  return *this;
187 
188  x = r.x;
189  y = r.y;
190  return *this;
191  }
192 
193  ~quad_node_base()
194  {
195 #ifdef MDDS_DEBUG_NODE_BASE
196  --node_instance_count;
197 #endif
198  static_cast<node_type*>(this)->dispose();
199  }
200 
207  node_quadrant_t get_quadrant(key_type other_x, key_type other_y) const
208  {
209  if (other_x < x)
210  // west
211  return other_y < y ? quad_northwest : quad_southwest;
212 
213  // east
214  return other_y < y ? quad_northeast : quad_southeast;
215  }
216 
217  bool has_quadrant_node(node_quadrant_t quad) const
218  {
219  switch (quad)
220  {
221  case quad_northeast:
222  return northeast.get() != nullptr;
223  case quad_northwest:
224  return northwest.get() != nullptr;
225  case quad_southeast:
226  return southeast.get() != nullptr;
227  case quad_southwest:
228  return southwest.get() != nullptr;
229  default:
230  throw general_error("unknown quadrant type");
231  }
232  return false;
233  }
234 
235  node_ptr get_quadrant_node(node_quadrant_t quad) const
236  {
237  node_ptr ret;
238  switch (quad)
239  {
240  case quad_northeast:
241  ret = northeast;
242  break;
243  case quad_northwest:
244  ret = northwest;
245  break;
246  case quad_southeast:
247  ret = southeast;
248  break;
249  case quad_southwest:
250  ret = southwest;
251  break;
252  default:
253  throw general_error("unknown quadrant type");
254  }
255  return ret;
256  }
257 };
258 
259 template<typename _NodePtr, typename _NodeType, typename _Key>
260 inline void intrusive_ptr_add_ref(::mdds::quad_node_base<_NodePtr,_NodeType,_Key>* p)
261 {
262  ++p->refcount;
263 }
264 
265 template<typename _NodePtr, typename _NodeType, typename _Key>
266 inline void intrusive_ptr_release(::mdds::quad_node_base<_NodePtr,_NodeType,_Key>* p)
267 {
268  --p->refcount;
269  if (!p->refcount)
270  delete p;
271 }
272 
273 template<typename _NodePtr>
274 void disconnect_node_from_parent(_NodePtr p)
275 {
276  if (!p || !p->parent)
277  // Nothing to do.
278  return;
279 
280  _NodePtr& parent = p->parent;
281  if (parent->northeast && parent->northeast == p)
282  {
283  parent->northeast.reset();
284  }
285  else if (parent->northwest && parent->northwest == p)
286  {
287  parent->northwest.reset();
288  }
289  else if (parent->southwest && parent->southwest == p)
290  {
291  parent->southwest.reset();
292  }
293  else if (parent->southeast && parent->southeast == p)
294  {
295  parent->southeast.reset();
296  }
297  else
298  throw general_error("parent node doesn't lead to the deleted node.");
299 }
300 
301 template<typename _NodePtr>
302 void disconnect_all_nodes(_NodePtr p)
303 {
304  if (!p)
305  return;
306 
307  if (p->northeast)
308  {
309  disconnect_all_nodes(p->northeast);
310  p->northeast.reset();
311  }
312 
313  if (p->northwest)
314  {
315  disconnect_all_nodes(p->northwest);
316  p->northwest.reset();
317  }
318 
319  if (p->southeast)
320  {
321  disconnect_all_nodes(p->southeast);
322  p->southeast.reset();
323  }
324 
325  if (p->southwest)
326  {
327  disconnect_all_nodes(p->southwest);
328  p->southwest.reset();
329  }
330 
331  p->parent.reset();
332 }
333 
334 template<typename _NodeType, typename _Key>
335 search_region_space_t get_search_region_space(
336  _NodeType* p, _Key x1, _Key y1, _Key x2, _Key y2)
337 {
338  typedef _Key key_type;
339 
340  key_type x = p->x, y = p->y;
341  if (x < x1)
342  {
343  // western region
344  if (y < y1)
345  {
346  return region_northwest;
347  }
348  else if (y1 <= y && y <= y2)
349  {
350  return region_west;
351  }
352 
353  assert(y2 < y);
354  return region_southwest;
355  }
356  else if (x1 <= x && x <= x2)
357  {
358  // central region
359  if (y < y1)
360  {
361  return region_north;
362  }
363  else if (y1 <= y && y <= y2)
364  {
365  return region_center;
366  }
367 
368  assert(y2 < y);
369  return region_south;
370  }
371 
372  // eastern region
373  assert(x2 < x);
374  if (y < y1)
375  {
376  return region_northeast;
377  }
378  else if (y1 <= y && y <= y2)
379  {
380  return region_east;
381  }
382 
383  assert(y2 < y);
384  return region_southeast;
385 }
386 
387 }
388 
389 #endif
quad_node_base(const quad_node_base &r)
Definition: quad_node.hpp:154
Definition: global.hpp:58
Definition: flat_segment_tree.hpp:46
quad_node_base & operator=(const quad_node_base &r)
Definition: quad_node.hpp:182
node_quadrant_t get_quadrant(key_type other_x, key_type other_y) const
Definition: quad_node.hpp:207
Definition: quad_node.hpp:118