tg_geometry 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +103 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +385 -0
  6. data/Rakefile +129 -0
  7. data/benchmark/_support.rb +115 -0
  8. data/benchmark/batch_packed_vs_loop.rb +27 -0
  9. data/benchmark/falcon_concurrency.rb +25 -0
  10. data/benchmark/flat_vs_rtree.rb +27 -0
  11. data/benchmark/gvl_threshold.rb +41 -0
  12. data/benchmark/objectspace_memsize.rb +17 -0
  13. data/benchmark/parse_throughput.rb +38 -0
  14. data/benchmark/rss_stability.rb +70 -0
  15. data/docs/ACTIVE_RECORD.md +26 -0
  16. data/docs/ARCHITECTURE.md +130 -0
  17. data/docs/AUTO_STRATEGY.md +15 -0
  18. data/docs/BENCHMARKING.md +75 -0
  19. data/docs/CASUAL_EXAMPLE.md +618 -0
  20. data/docs/CONCURRENCY.md +65 -0
  21. data/docs/ERROR_HANDLING.md +55 -0
  22. data/docs/EXPANSION_E_TO_H_STATUS.md +51 -0
  23. data/docs/FORMAT_COVERAGE.md +23 -0
  24. data/docs/FULL_TG_API_COVERAGE.md +109 -0
  25. data/docs/LIMITATIONS.md +61 -0
  26. data/docs/LOW_LEVEL_GEOMETRY.md +121 -0
  27. data/docs/MEMORY_OWNERSHIP.md +94 -0
  28. data/docs/RACTOR.md +40 -0
  29. data/docs/REGISTRY.md +37 -0
  30. data/docs/RELEASE_CHECKLIST.md +39 -0
  31. data/ext/tg_geometry/extconf.rb +91 -0
  32. data/ext/tg_geometry/tg_geometry_ext.c +3054 -0
  33. data/ext/tg_geometry/tg_geometry_vendor_rtree.c +1 -0
  34. data/ext/tg_geometry/tg_geometry_vendor_tg.c +24 -0
  35. data/ext/tg_geometry/vendor/.vendored +16 -0
  36. data/ext/tg_geometry/vendor/rtree/LICENSE +20 -0
  37. data/ext/tg_geometry/vendor/rtree/README.md +202 -0
  38. data/ext/tg_geometry/vendor/rtree/VERSION +3 -0
  39. data/ext/tg_geometry/vendor/rtree/rtree.c +840 -0
  40. data/ext/tg_geometry/vendor/rtree/rtree.h +105 -0
  41. data/ext/tg_geometry/vendor/tg/LICENSE +19 -0
  42. data/ext/tg_geometry/vendor/tg/README.md +197 -0
  43. data/ext/tg_geometry/vendor/tg/VERSION +3 -0
  44. data/ext/tg_geometry/vendor/tg/tg.c +16010 -0
  45. data/ext/tg_geometry/vendor/tg/tg.h +359 -0
  46. data/lib/tg/geometry/active_record_source.rb +57 -0
  47. data/lib/tg/geometry/registry.rb +119 -0
  48. data/lib/tg/geometry/version.rb +7 -0
  49. data/lib/tg/geometry.rb +6 -0
  50. data/lib/tg_geometry.rb +3 -0
  51. data/script/vendor_libs.rb +264 -0
  52. data/spec/block_10_rtree_strategy_spec.rb +82 -0
  53. data/spec/block_11_rtree_order_spec.rb +53 -0
  54. data/spec/block_12_batch_packed_spec.rb +55 -0
  55. data/spec/block_13_error_hardening_spec.rb +65 -0
  56. data/spec/block_14_memory_gc_hardening_spec.rb +116 -0
  57. data/spec/block_1_skeleton_spec.rb +45 -0
  58. data/spec/block_20_concurrency_spec.rb +157 -0
  59. data/spec/block_20_fuzz_spec.rb +145 -0
  60. data/spec/block_2_vendor_spec.rb +79 -0
  61. data/spec/block_3_geom_parse_spec.rb +89 -0
  62. data/spec/block_4_geom_api_spec.rb +90 -0
  63. data/spec/block_5_rect_api_spec.rb +96 -0
  64. data/spec/block_6_index_build_spec.rb +111 -0
  65. data/spec/block_7_index_owned_geometry_spec.rb +143 -0
  66. data/spec/block_8_index_borrowed_geometry_spec.rb +106 -0
  67. data/spec/block_9_flat_query_spec.rb +65 -0
  68. data/spec/expansion_a_auto_strategy_spec.rb +14 -0
  69. data/spec/expansion_b_registry_spec.rb +47 -0
  70. data/spec/expansion_c_active_record_source_spec.rb +42 -0
  71. data/spec/expansion_d_format_coverage_spec.rb +30 -0
  72. data/spec/expansion_e_low_level_geometry_spec.rb +82 -0
  73. data/spec/expansion_i_ractor_spec.rb +25 -0
  74. data/spec/expansion_j_full_tg_api_coverage_spec.rb +114 -0
  75. data/spec/spec_helper.rb +15 -0
  76. metadata +157 -0
@@ -0,0 +1,840 @@
1
+ // Copyright 2023 Joshua J Baker. All rights reserved.
2
+ // Use of this source code is governed by an MIT-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ #include <string.h>
6
+ #include <math.h>
7
+ #include <stdbool.h>
8
+ #include "rtree.h"
9
+
10
+ ////////////////////////////////
11
+
12
+ #define DATATYPE void *
13
+ #define DIMS 2
14
+ #define NUMTYPE double
15
+ #define MAXITEMS 64
16
+
17
+ ////////////////////////////////
18
+
19
+ // used for splits
20
+ #define MINITEMS_PERCENTAGE 10
21
+ #define MINITEMS ((MAXITEMS) * (MINITEMS_PERCENTAGE) / 100 + 1)
22
+
23
+ #ifndef RTREE_NOPATHHINT
24
+ #define USE_PATHHINT
25
+ #endif
26
+
27
+ #ifdef RTREE_MAXITEMS
28
+ #undef MAXITEMS
29
+ #define MAXITEMS RTREE_MAXITEMS
30
+ #endif
31
+
32
+ #ifdef RTREE_NOATOMICS
33
+ typedef int rc_t;
34
+ static int rc_load(rc_t *ptr, bool relaxed) {
35
+ (void)relaxed; // nothing to do
36
+ return *ptr;
37
+ }
38
+ static int rc_fetch_sub(rc_t *ptr, int val) {
39
+ int rc = *ptr;
40
+ *ptr -= val;
41
+ return rc;
42
+ }
43
+ static int rc_fetch_add(rc_t *ptr, int val) {
44
+ int rc = *ptr;
45
+ *ptr += val;
46
+ return rc;
47
+ }
48
+ #else
49
+ #include <stdatomic.h>
50
+ typedef atomic_int rc_t;
51
+ static int rc_load(rc_t *ptr, bool relaxed) {
52
+ if (relaxed) {
53
+ return atomic_load_explicit(ptr, memory_order_relaxed);
54
+ } else {
55
+ return atomic_load(ptr);
56
+ }
57
+ }
58
+ static int rc_fetch_sub(rc_t *ptr, int delta) {
59
+ return atomic_fetch_sub(ptr, delta);
60
+ }
61
+ static int rc_fetch_add(rc_t *ptr, int delta) {
62
+ return atomic_fetch_add(ptr, delta);
63
+ }
64
+ #endif
65
+
66
+ enum kind {
67
+ LEAF = 1,
68
+ BRANCH = 2,
69
+ };
70
+
71
+ struct rect {
72
+ NUMTYPE min[DIMS];
73
+ NUMTYPE max[DIMS];
74
+ };
75
+
76
+ struct item {
77
+ const DATATYPE data;
78
+ };
79
+
80
+ struct node {
81
+ rc_t rc; // reference counter for copy-on-write
82
+ enum kind kind; // LEAF or BRANCH
83
+ int count; // number of rects
84
+ struct rect rects[MAXITEMS];
85
+ union {
86
+ struct node *nodes[MAXITEMS];
87
+ struct item datas[MAXITEMS];
88
+ };
89
+ };
90
+
91
+ struct rtree {
92
+ struct rect rect;
93
+ struct node *root;
94
+ size_t count;
95
+ size_t height;
96
+ #ifdef USE_PATHHINT
97
+ int path_hint[16];
98
+ #endif
99
+ bool relaxed;
100
+ void *(*malloc)(size_t);
101
+ void (*free)(void *);
102
+ void *udata;
103
+ bool (*item_clone)(const DATATYPE item, DATATYPE *into, void *udata);
104
+ void (*item_free)(const DATATYPE item, void *udata);
105
+ };
106
+
107
+ static inline NUMTYPE min0(NUMTYPE x, NUMTYPE y) {
108
+ return x < y ? x : y;
109
+ }
110
+
111
+ static inline NUMTYPE max0(NUMTYPE x, NUMTYPE y) {
112
+ return x > y ? x : y;
113
+ }
114
+
115
+ static bool feq(NUMTYPE a, NUMTYPE b) {
116
+ return !(a < b || a > b);
117
+ }
118
+
119
+
120
+ void rtree_set_udata(struct rtree *tr, void *udata) {
121
+ tr->udata = udata;
122
+ }
123
+
124
+ static struct node *node_new(struct rtree *tr, enum kind kind) {
125
+ struct node *node = (struct node *)tr->malloc(sizeof(struct node));
126
+ if (!node) return NULL;
127
+ memset(node, 0, sizeof(struct node));
128
+ node->kind = kind;
129
+ return node;
130
+ }
131
+
132
+ static struct node *node_copy(struct rtree *tr, struct node *node) {
133
+ struct node *node2 = (struct node *)tr->malloc(sizeof(struct node));
134
+ if (!node2) return NULL;
135
+ memcpy(node2, node, sizeof(struct node));
136
+ node2->rc = 0;
137
+ if (node2->kind == BRANCH) {
138
+ for (int i = 0; i < node2->count; i++) {
139
+ rc_fetch_add(&node2->nodes[i]->rc, 1);
140
+ }
141
+ } else {
142
+ if (tr->item_clone) {
143
+ int n = 0;
144
+ bool oom = false;
145
+ for (int i = 0; i < node2->count; i++) {
146
+ if (!tr->item_clone(node->datas[i].data,
147
+ (DATATYPE*)&node2->datas[i].data, tr->udata))
148
+ {
149
+ oom = true;
150
+ break;
151
+ }
152
+ n++;
153
+ }
154
+ if (oom) {
155
+ if (tr->item_free) {
156
+ for (int i = 0; i < n; i++) {
157
+ tr->item_free(node2->datas[i].data, tr->udata);
158
+ }
159
+ }
160
+ tr->free(node2);
161
+ return NULL;
162
+ }
163
+ }
164
+ }
165
+ return node2;
166
+ }
167
+
168
+ static void node_free(struct rtree *tr, struct node *node) {
169
+ if (rc_fetch_sub(&node->rc, 1) > 0) return;
170
+ if (node->kind == BRANCH) {
171
+ for (int i = 0; i < node->count; i++) {
172
+ node_free(tr, node->nodes[i]);
173
+ }
174
+ } else {
175
+ if (tr->item_free) {
176
+ for (int i = 0; i < node->count; i++) {
177
+ tr->item_free(node->datas[i].data, tr->udata);
178
+ }
179
+ }
180
+ }
181
+ tr->free(node);
182
+ }
183
+
184
+ #define cow_node_or(rnode, code) { \
185
+ if (rc_load(&(rnode)->rc, tr->relaxed) > 0) { \
186
+ struct node *node2 = node_copy(tr, (rnode)); \
187
+ if (!node2) { code; } \
188
+ node_free(tr, rnode); \
189
+ (rnode) = node2; \
190
+ } \
191
+ }
192
+
193
+ static void rect_expand(struct rect *rect, const struct rect *other) {
194
+ for (int i = 0; i < DIMS; i++) {
195
+ rect->min[i] = min0(rect->min[i], other->min[i]);
196
+ rect->max[i] = max0(rect->max[i], other->max[i]);
197
+ }
198
+ }
199
+
200
+ static NUMTYPE rect_area(const struct rect *rect) {
201
+ NUMTYPE result = 1;
202
+ for (int i = 0; i < DIMS; i++) {
203
+ result *= (rect->max[i] - rect->min[i]);
204
+ }
205
+ return result;
206
+ }
207
+
208
+ // return the area of two rects expanded
209
+ static NUMTYPE rect_unioned_area(const struct rect *rect,
210
+ const struct rect *other)
211
+ {
212
+ NUMTYPE result = 1;
213
+ for (int i = 0; i < DIMS; i++) {
214
+ result *= (max0(rect->max[i], other->max[i]) -
215
+ min0(rect->min[i], other->min[i]));
216
+ }
217
+ return result;
218
+ }
219
+
220
+ static bool rect_contains(const struct rect *rect, const struct rect *other) {
221
+ int bits = 0;
222
+ for (int i = 0; i < DIMS; i++) {
223
+ bits |= other->min[i] < rect->min[i];
224
+ bits |= other->max[i] > rect->max[i];
225
+ }
226
+ return bits == 0;
227
+ }
228
+
229
+ static bool rect_intersects(const struct rect *rect, const struct rect *other) {
230
+ int bits = 0;
231
+ for (int i = 0; i < DIMS; i++) {
232
+ bits |= other->min[i] > rect->max[i];
233
+ bits |= other->max[i] < rect->min[i];
234
+ }
235
+ return bits == 0;
236
+ }
237
+
238
+ static bool rect_onedge(const struct rect *rect, const struct rect *other) {
239
+ for (int i = 0; i < DIMS; i++) {
240
+ if (feq(rect->min[i], other->min[i]) ||
241
+ feq(rect->max[i], other->max[i]))
242
+ {
243
+ return true;
244
+ }
245
+ }
246
+ return false;
247
+ }
248
+
249
+ static bool rect_equals(const struct rect *rect, const struct rect *other) {
250
+ for (int i = 0; i < DIMS; i++) {
251
+ if (!feq(rect->min[i], other->min[i]) ||
252
+ !feq(rect->max[i], other->max[i]))
253
+ {
254
+ return false;
255
+ }
256
+ }
257
+ return true;
258
+ }
259
+
260
+ static bool rect_equals_bin(const struct rect *rect, const struct rect *other) {
261
+ for (int i = 0; i < DIMS; i++) {
262
+ if (rect->min[i] != other->min[i] ||
263
+ rect->max[i] != other->max[i])
264
+ {
265
+ return false;
266
+ }
267
+ }
268
+ return true;
269
+ }
270
+
271
+ static int rect_largest_axis(const struct rect *rect) {
272
+ int axis = 0;
273
+ NUMTYPE nlength = rect->max[0] - rect->min[0];
274
+ for (int i = 1; i < DIMS; i++) {
275
+ NUMTYPE length = rect->max[i] - rect->min[i];
276
+ if (length > nlength) {
277
+ nlength = length;
278
+ axis = i;
279
+ }
280
+ }
281
+ return axis;
282
+ }
283
+
284
+ // swap two rectangles
285
+ static void node_swap(struct node *node, int i, int j) {
286
+ struct rect tmp = node->rects[i];
287
+ node->rects[i] = node->rects[j];
288
+ node->rects[j] = tmp;
289
+ if (node->kind == LEAF) {
290
+ struct item tmp = node->datas[i];
291
+ node->datas[i] = node->datas[j];
292
+ node->datas[j] = tmp;
293
+ } else {
294
+ struct node *tmp = node->nodes[i];
295
+ node->nodes[i] = node->nodes[j];
296
+ node->nodes[j] = tmp;
297
+ }
298
+ }
299
+
300
+ struct rect4 {
301
+ NUMTYPE all[DIMS*2];
302
+ };
303
+
304
+ static void node_qsort(struct node *node, int s, int e, int index) {
305
+ int nrects = e - s;
306
+ if (nrects < 2) {
307
+ return;
308
+ }
309
+ int left = 0;
310
+ int right = nrects-1;
311
+ int pivot = nrects / 2;
312
+ node_swap(node, s+pivot, s+right);
313
+ struct rect4 *rects = (struct rect4 *)&node->rects[s];
314
+ for (int i = 0; i < nrects; i++) {
315
+ if (rects[right].all[index] < rects[i].all[index]) {
316
+ node_swap(node, s+i, s+left);
317
+ left++;
318
+ }
319
+ }
320
+ node_swap(node, s+left, s+right);
321
+ node_qsort(node, s, s+left, index);
322
+ node_qsort(node, s+left+1, e, index);
323
+ }
324
+
325
+ // sort the node rectangles by the axis. used during splits
326
+ static void node_sort_by_axis(struct node *node, int axis, bool max) {
327
+ int by_index = max ? DIMS+axis : axis;
328
+ node_qsort(node, 0, node->count, by_index);
329
+ }
330
+
331
+ static void node_move_rect_at_index_into(struct node *from, int index,
332
+ struct node *into)
333
+ {
334
+ into->rects[into->count] = from->rects[index];
335
+ from->rects[index] = from->rects[from->count-1];
336
+ if (from->kind == LEAF) {
337
+ into->datas[into->count] = from->datas[index];
338
+ from->datas[index] = from->datas[from->count-1];
339
+ } else {
340
+ into->nodes[into->count] = from->nodes[index];
341
+ from->nodes[index] = from->nodes[from->count-1];
342
+ }
343
+ from->count--;
344
+ into->count++;
345
+ }
346
+
347
+ static bool node_split_largest_axis_edge_snap(struct rtree *tr,
348
+ struct rect *rect, struct node *node, struct node **right_out)
349
+ {
350
+ int axis = rect_largest_axis(rect);
351
+ struct node *right = node_new(tr, node->kind);
352
+ if (!right) {
353
+ return false;
354
+ }
355
+ for (int i = 0; i < node->count; i++) {
356
+ NUMTYPE min_dist = node->rects[i].min[axis] - rect->min[axis];
357
+ NUMTYPE max_dist = rect->max[axis] - node->rects[i].max[axis];
358
+ if (max_dist < min_dist) {
359
+ // move to right
360
+ node_move_rect_at_index_into(node, i, right);
361
+ i--;
362
+ }
363
+ }
364
+ // Make sure that both left and right nodes have at least
365
+ // MINITEMS by moving datas into underflowed nodes.
366
+ if (node->count < MINITEMS) {
367
+ // reverse sort by min axis
368
+ node_sort_by_axis(right, axis, false);
369
+ do {
370
+ node_move_rect_at_index_into(right, right->count-1, node);
371
+ } while (node->count < MINITEMS);
372
+ } else if (right->count < MINITEMS) {
373
+ // reverse sort by max axis
374
+ node_sort_by_axis(node, axis, true);
375
+ do {
376
+ node_move_rect_at_index_into(node, node->count-1, right);
377
+ } while (right->count < MINITEMS);
378
+ }
379
+ if (node->kind == BRANCH) {
380
+ node_sort_by_axis(node, 0, false);
381
+ node_sort_by_axis(right, 0, false);
382
+ }
383
+ *right_out = right;
384
+ return true;
385
+ }
386
+
387
+ static bool node_split(struct rtree *tr, struct rect *rect, struct node *node,
388
+ struct node **right)
389
+ {
390
+ return node_split_largest_axis_edge_snap(tr, rect, node, right);
391
+ }
392
+
393
+ static int node_choose_least_enlargement(const struct node *node,
394
+ const struct rect *ir)
395
+ {
396
+ int j = 0;
397
+ NUMTYPE jenlarge = INFINITY;
398
+ for (int i = 0; i < node->count; i++) {
399
+ // calculate the enlarged area
400
+ NUMTYPE uarea = rect_unioned_area(&node->rects[i], ir);
401
+ NUMTYPE area = rect_area(&node->rects[i]);
402
+ NUMTYPE enlarge = uarea - area;
403
+ if (enlarge < jenlarge) {
404
+ j = i;
405
+ jenlarge = enlarge;
406
+ }
407
+ }
408
+ return j;
409
+ }
410
+
411
+ static int node_choose(struct rtree *tr, const struct node *node,
412
+ const struct rect *rect, int depth)
413
+ {
414
+ #ifdef USE_PATHHINT
415
+ int h = tr->path_hint[depth];
416
+ if (h < node->count) {
417
+ if (rect_contains(&node->rects[h], rect)) {
418
+ return h;
419
+ }
420
+ }
421
+ #endif
422
+ // Take a quick look for the first node that contain the rect.
423
+ for (int i = 0; i < node->count; i++) {
424
+ if (rect_contains(&node->rects[i], rect)) {
425
+ #ifdef USE_PATHHINT
426
+ tr->path_hint[depth] = i;
427
+ #endif
428
+ return i;
429
+ }
430
+ }
431
+ // Fallback to using che "choose least enlargment" algorithm.
432
+ int i = node_choose_least_enlargement(node, rect);
433
+ #ifdef USE_PATHHINT
434
+ tr->path_hint[depth] = i;
435
+ #endif
436
+ return i;
437
+ }
438
+
439
+ static struct rect node_rect_calc(const struct node *node) {
440
+ struct rect rect = node->rects[0];
441
+ for (int i = 1; i < node->count; i++) {
442
+ rect_expand(&rect, &node->rects[i]);
443
+ }
444
+ return rect;
445
+ }
446
+
447
+ // node_insert returns false if out of memory
448
+ static bool node_insert(struct rtree *tr, struct rect *nr, struct node *node,
449
+ struct rect *ir, struct item item, int depth, bool *split)
450
+ {
451
+ if (node->kind == LEAF) {
452
+ if (node->count == MAXITEMS) {
453
+ *split = true;
454
+ return true;
455
+ }
456
+ int index = node->count;
457
+ node->rects[index] = *ir;
458
+ node->datas[index] = item;
459
+ node->count++;
460
+ *split = false;
461
+ return true;
462
+ }
463
+ // Choose a subtree for inserting the rectangle.
464
+ int i = node_choose(tr, node, ir, depth);
465
+ cow_node_or(node->nodes[i], return false);
466
+ if (!node_insert(tr, &node->rects[i], node->nodes[i], ir, item, depth+1,
467
+ split))
468
+ {
469
+ return false;
470
+ }
471
+ if (!*split) {
472
+ rect_expand(&node->rects[i], ir);
473
+ *split = false;
474
+ return true;
475
+ }
476
+ // split the child node
477
+ if (node->count == MAXITEMS) {
478
+ *split = true;
479
+ return true;
480
+ }
481
+ struct node *right;
482
+ if (!node_split(tr, &node->rects[i], node->nodes[i], &right)) {
483
+ return false;
484
+ }
485
+ node->rects[i] = node_rect_calc(node->nodes[i]);
486
+ node->rects[node->count] = node_rect_calc(right);
487
+ node->nodes[node->count] = right;
488
+ node->count++;
489
+ return node_insert(tr, nr, node, ir, item, depth, split);
490
+ }
491
+
492
+ struct rtree *rtree_new_with_allocator(void *(*_malloc)(size_t),
493
+ void (*_free)(void*)
494
+ ) {
495
+ _malloc = _malloc ? _malloc : malloc;
496
+ _free = _free ? _free : free;
497
+ struct rtree *tr = (struct rtree *)_malloc(sizeof(struct rtree));
498
+ if (!tr) return NULL;
499
+ memset(tr, 0, sizeof(struct rtree));
500
+ tr->malloc = _malloc;
501
+ tr->free = _free;
502
+ return tr;
503
+ }
504
+
505
+ struct rtree *rtree_new(void) {
506
+ return rtree_new_with_allocator(NULL, NULL);
507
+ }
508
+
509
+ void rtree_set_item_callbacks(struct rtree *tr,
510
+ bool (*clone)(const DATATYPE item, DATATYPE *into, void *udata),
511
+ void (*free)(const DATATYPE item, void *udata))
512
+ {
513
+ tr->item_clone = clone;
514
+ tr->item_free = free;
515
+ }
516
+
517
+ bool rtree_insert(struct rtree *tr, const NUMTYPE *min,
518
+ const NUMTYPE *max, const DATATYPE data)
519
+ {
520
+ // copy input rect
521
+ struct rect rect;
522
+ memcpy(&rect.min[0], min, sizeof(NUMTYPE)*DIMS);
523
+ memcpy(&rect.max[0], max?max:min, sizeof(NUMTYPE)*DIMS);
524
+
525
+ // copy input data
526
+ struct item item;
527
+ if (tr->item_clone) {
528
+ if (!tr->item_clone(data, (DATATYPE*)&item.data, tr->udata)) {
529
+ return false;
530
+ }
531
+ } else {
532
+ memcpy(&item.data, &data, sizeof(DATATYPE));
533
+ }
534
+
535
+ while (1) {
536
+ if (!tr->root) {
537
+ struct node *new_root = node_new(tr, LEAF);
538
+ if (!new_root) {
539
+ break;
540
+ }
541
+ tr->root = new_root;
542
+ tr->rect = rect;
543
+ tr->height = 1;
544
+ }
545
+ bool split = false;
546
+ cow_node_or(tr->root, break);
547
+ if (!node_insert(tr, &tr->rect, tr->root, &rect, item, 0, &split)) {
548
+ break;
549
+ }
550
+ if (!split) {
551
+ rect_expand(&tr->rect, &rect);
552
+ tr->count++;
553
+ return true;
554
+ }
555
+ struct node *new_root = node_new(tr, BRANCH);
556
+ if (!new_root) {
557
+ break;
558
+ }
559
+ struct node *right;
560
+ if (!node_split(tr, &tr->rect, tr->root, &right)) {
561
+ tr->free(new_root);
562
+ break;
563
+ }
564
+ new_root->rects[0] = node_rect_calc(tr->root);
565
+ new_root->rects[1] = node_rect_calc(right);
566
+ new_root->nodes[0] = tr->root;
567
+ new_root->nodes[1] = right;
568
+ tr->root = new_root;
569
+ tr->root->count = 2;
570
+ tr->height++;
571
+ }
572
+ // out of memory
573
+ if (tr->item_free) {
574
+ tr->item_free(item.data, tr->udata);
575
+ }
576
+ return false;
577
+ }
578
+
579
+ void rtree_free(struct rtree *tr) {
580
+ if (tr->root) {
581
+ node_free(tr, tr->root);
582
+ }
583
+ tr->free(tr);
584
+ }
585
+
586
+ static bool node_search(struct node *node, struct rect *rect,
587
+ bool (*iter)(const NUMTYPE *min, const NUMTYPE *max, const DATATYPE data,
588
+ void *udata),
589
+ void *udata)
590
+ {
591
+ if (node->kind == LEAF) {
592
+ for (int i = 0; i < node->count; i++) {
593
+ if (rect_intersects(&node->rects[i], rect)) {
594
+ if (!iter(node->rects[i].min, node->rects[i].max,
595
+ node->datas[i].data, udata))
596
+ {
597
+ return false;
598
+ }
599
+ }
600
+ }
601
+ return true;
602
+ }
603
+ for (int i = 0; i < node->count; i++) {
604
+ if (rect_intersects(&node->rects[i], rect)) {
605
+ if (!node_search(node->nodes[i], rect, iter, udata)) {
606
+ return false;
607
+ }
608
+ }
609
+ }
610
+ return true;
611
+ }
612
+
613
+ void rtree_search(const struct rtree *tr, const NUMTYPE min[],
614
+ const NUMTYPE max[],
615
+ bool (*iter)(const NUMTYPE min[], const NUMTYPE max[], const DATATYPE data,
616
+ void *udata),
617
+ void *udata)
618
+ {
619
+ // copy input rect
620
+ struct rect rect;
621
+ memcpy(&rect.min[0], min, sizeof(NUMTYPE)*DIMS);
622
+ memcpy(&rect.max[0], max?max:min, sizeof(NUMTYPE)*DIMS);
623
+
624
+ if (tr->root) {
625
+ node_search(tr->root, &rect, iter, udata);
626
+ }
627
+ }
628
+
629
+ static bool node_scan(struct node *node,
630
+ bool (*iter)(const NUMTYPE *min, const NUMTYPE *max, const DATATYPE data,
631
+ void *udata),
632
+ void *udata)
633
+ {
634
+ if (node->kind == LEAF) {
635
+ for (int i = 0; i < node->count; i++) {
636
+ if (!iter(node->rects[i].min, node->rects[i].max,
637
+ node->datas[i].data, udata))
638
+ {
639
+ return false;
640
+ }
641
+ }
642
+ return true;
643
+ }
644
+ for (int i = 0; i < node->count; i++) {
645
+ if (!node_scan(node->nodes[i], iter, udata)) {
646
+ return false;
647
+ }
648
+ }
649
+ return true;
650
+ }
651
+
652
+ void rtree_scan(const struct rtree *tr,
653
+ bool (*iter)(const NUMTYPE *min, const NUMTYPE *max, const DATATYPE data,
654
+ void *udata),
655
+ void *udata)
656
+ {
657
+ if (tr->root) {
658
+ node_scan(tr->root, iter, udata);
659
+ }
660
+ }
661
+
662
+ size_t rtree_count(const struct rtree *tr) {
663
+ return tr->count;
664
+ }
665
+
666
+ static bool node_delete(struct rtree *tr, struct rect *nr, struct node *node,
667
+ struct rect *ir, struct item item, int depth, bool *removed, bool *shrunk,
668
+ int (*compare)(const DATATYPE a, const DATATYPE b, void *udata),
669
+ void *udata)
670
+ {
671
+ *removed = false;
672
+ *shrunk = false;
673
+ if (node->kind == LEAF) {
674
+ for (int i = 0; i < node->count; i++) {
675
+ if (!rect_equals_bin(ir, &node->rects[i])) {
676
+ // Must be exactly the same, binary comparison.
677
+ continue;
678
+ }
679
+ int cmp = compare ?
680
+ compare(node->datas[i].data, item.data, udata) :
681
+ memcmp(&node->datas[i].data, &item.data, sizeof(DATATYPE));
682
+ if (cmp != 0) {
683
+ continue;
684
+ }
685
+ // Found the target item to delete.
686
+ if (tr->item_free) {
687
+ tr->item_free(node->datas[i].data, tr->udata);
688
+ }
689
+ node->rects[i] = node->rects[node->count-1];
690
+ node->datas[i] = node->datas[node->count-1];
691
+ node->count--;
692
+ if (rect_onedge(ir, nr)) {
693
+ // The item rect was on the edge of the node rect.
694
+ // We need to recalculate the node rect.
695
+ *nr = node_rect_calc(node);
696
+ // Notify the caller that we shrunk the rect.
697
+ *shrunk = true;
698
+ }
699
+ *removed = true;
700
+ return true;
701
+ }
702
+ return true;
703
+ }
704
+ int h = 0;
705
+ #ifdef USE_PATHHINT
706
+ h = tr->path_hint[depth];
707
+ if (h < node->count) {
708
+ if (rect_contains(&node->rects[h], ir)) {
709
+ cow_node_or(node->nodes[h], return false);
710
+ if (!node_delete(tr, &node->rects[h], node->nodes[h], ir, item,
711
+ depth+1,removed, shrunk, compare, udata))
712
+ {
713
+ return false;
714
+ }
715
+ if (*removed) {
716
+ goto removed;
717
+ }
718
+ }
719
+ }
720
+ h = 0;
721
+ #endif
722
+ for (; h < node->count; h++) {
723
+ if (!rect_contains(&node->rects[h], ir)) {
724
+ continue;
725
+ }
726
+ struct rect crect = node->rects[h];
727
+ cow_node_or(node->nodes[h], return false);
728
+ if (!node_delete(tr, &node->rects[h], node->nodes[h], ir, item, depth+1,
729
+ removed, shrunk, compare, udata))
730
+ {
731
+ return false;
732
+ }
733
+ if (!*removed) {
734
+ continue;
735
+ }
736
+ removed:
737
+ if (node->nodes[h]->count == 0) {
738
+ // underflow
739
+ node_free(tr, node->nodes[h]);
740
+ node->rects[h] = node->rects[node->count-1];
741
+ node->nodes[h] = node->nodes[node->count-1];
742
+ node->count--;
743
+ *nr = node_rect_calc(node);
744
+ *shrunk = true;
745
+ return true;
746
+ }
747
+ #ifdef USE_PATHHINT
748
+ tr->path_hint[depth] = h;
749
+ #endif
750
+ if (*shrunk) {
751
+ *shrunk = !rect_equals(&node->rects[h], &crect);
752
+ if (*shrunk) {
753
+ *nr = node_rect_calc(node);
754
+ }
755
+ }
756
+ return true;
757
+ }
758
+ return true;
759
+ }
760
+
761
+ // returns false if out of memory
762
+ static bool rtree_delete0(struct rtree *tr, const NUMTYPE *min,
763
+ const NUMTYPE *max, const DATATYPE data,
764
+ int (*compare)(const DATATYPE a, const DATATYPE b, void *udata),
765
+ void *udata)
766
+ {
767
+ // copy input rect
768
+ struct rect rect;
769
+ memcpy(&rect.min[0], min, sizeof(NUMTYPE)*DIMS);
770
+ memcpy(&rect.max[0], max?max:min, sizeof(NUMTYPE)*DIMS);
771
+
772
+ // copy input data
773
+ struct item item;
774
+ memcpy(&item.data, &data, sizeof(DATATYPE));
775
+
776
+ if (!tr->root) {
777
+ return true;
778
+ }
779
+ bool removed = false;
780
+ bool shrunk = false;
781
+ cow_node_or(tr->root, return false);
782
+ if (!node_delete(tr, &tr->rect, tr->root, &rect, item, 0, &removed, &shrunk,
783
+ compare, udata))
784
+ {
785
+ return false;
786
+ }
787
+ if (!removed) {
788
+ return true;
789
+ }
790
+ tr->count--;
791
+ if (tr->count == 0) {
792
+ node_free(tr, tr->root);
793
+ tr->root = NULL;
794
+ memset(&tr->rect, 0, sizeof(struct rect));
795
+ tr->height = 0;
796
+ } else {
797
+ while (tr->root->kind == BRANCH && tr->root->count == 1) {
798
+ struct node *prev = tr->root;
799
+ tr->root = tr->root->nodes[0];
800
+ prev->count = 0;
801
+ node_free(tr, prev);
802
+ tr->height--;
803
+ }
804
+ if (shrunk) {
805
+ tr->rect = node_rect_calc(tr->root);
806
+ }
807
+ }
808
+ return true;
809
+ }
810
+
811
+ bool rtree_delete(struct rtree *tr, const NUMTYPE *min, const NUMTYPE *max,
812
+ const DATATYPE data)
813
+ {
814
+ return rtree_delete0(tr, min, max, data, NULL, NULL);
815
+ }
816
+
817
+ bool rtree_delete_with_comparator(struct rtree *tr, const NUMTYPE *min,
818
+ const NUMTYPE *max, const DATATYPE data,
819
+ int (*compare)(const DATATYPE a, const DATATYPE b, void *udata),
820
+ void *udata)
821
+ {
822
+ return rtree_delete0(tr, min, max, data, compare, udata);
823
+ }
824
+
825
+ struct rtree *rtree_clone(struct rtree *tr) {
826
+ if (!tr) return NULL;
827
+ struct rtree *tr2 = tr->malloc(sizeof(struct rtree));
828
+ if (!tr2) return NULL;
829
+ memcpy(tr2, tr, sizeof(struct rtree));
830
+ if (tr2->root) rc_fetch_add(&tr2->root->rc, 1);
831
+ return tr2;
832
+ }
833
+
834
+ void rtree_opt_relaxed_atomics(struct rtree *tr) {
835
+ tr->relaxed = true;
836
+ }
837
+
838
+ #ifdef TEST_PRIVATE_FUNCTIONS
839
+ #include "tests/priv_funcs.h"
840
+ #endif