diff --git a/README.md b/README.md index bec5cad..351eba9 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ numeric coordinate type, and `void *` as the data type. The `rtree.c` and `rtree.h` files can be easily customized to change these settings. -Please find the type parameters at the top of the `rtree.c` file: +Please set the parameters globally or before `rtree.h` including. Otherwise default values will be set: ```c #define DATATYPE void * diff --git a/rtree.c b/rtree.c index e06e8ef..db65465 100644 --- a/rtree.c +++ b/rtree.c @@ -7,28 +7,14 @@ #include #include "rtree.h" -//////////////////////////////// - -#define DATATYPE void * -#define DIMS 2 -#define NUMTYPE double -#define MAXITEMS 64 - -//////////////////////////////// - // used for splits #define MINITEMS_PERCENTAGE 10 -#define MINITEMS ((MAXITEMS) * (MINITEMS_PERCENTAGE) / 100 + 1) +#define MINITEMS ((RTREE_MAXITEMS) * (MINITEMS_PERCENTAGE) / 100 + 1) #ifndef RTREE_NOPATHHINT #define USE_PATHHINT #endif -#ifdef RTREE_MAXITEMS -#undef MAXITEMS -#define MAXITEMS RTREE_MAXITEMS -#endif - #ifdef RTREE_NOATOMICS typedef int rc_t; static int rc_load(rc_t *ptr, bool relaxed) { @@ -69,22 +55,22 @@ enum kind { }; struct rect { - NUMTYPE min[DIMS]; - NUMTYPE max[DIMS]; + RTREE_NUMTYPE min[RTREE_DIMS]; + RTREE_NUMTYPE max[RTREE_DIMS]; }; struct item { - const DATATYPE data; + const RTREE_DATATYPE data; }; struct node { rc_t rc; // reference counter for copy-on-write enum kind kind; // LEAF or BRANCH int count; // number of rects - struct rect rects[MAXITEMS]; + struct rect rects[RTREE_MAXITEMS]; union { - struct node *nodes[MAXITEMS]; - struct item datas[MAXITEMS]; + struct node *nodes[RTREE_MAXITEMS]; + struct item datas[RTREE_MAXITEMS]; }; }; @@ -100,19 +86,19 @@ struct rtree { void *(*malloc)(size_t); void (*free)(void *); void *udata; - bool (*item_clone)(const DATATYPE item, DATATYPE *into, void *udata); - void (*item_free)(const DATATYPE item, void *udata); + bool (*item_clone)(const RTREE_DATATYPE item, RTREE_DATATYPE *into, void *udata); + void (*item_free)(const RTREE_DATATYPE item, void *udata); }; -static inline NUMTYPE min0(NUMTYPE x, NUMTYPE y) { +static inline RTREE_NUMTYPE min0(RTREE_NUMTYPE x, RTREE_NUMTYPE y) { return x < y ? x : y; } -static inline NUMTYPE max0(NUMTYPE x, NUMTYPE y) { +static inline RTREE_NUMTYPE max0(RTREE_NUMTYPE x, RTREE_NUMTYPE y) { return x > y ? x : y; } -static bool feq(NUMTYPE a, NUMTYPE b) { +static bool feq(RTREE_NUMTYPE a, RTREE_NUMTYPE b) { return !(a < b || a > b); } @@ -144,7 +130,7 @@ static struct node *node_copy(struct rtree *tr, struct node *node) { bool oom = false; for (int i = 0; i < node2->count; i++) { if (!tr->item_clone(node->datas[i].data, - (DATATYPE*)&node2->datas[i].data, tr->udata)) + (RTREE_DATATYPE*)&node2->datas[i].data, tr->udata)) { oom = true; break; @@ -191,26 +177,26 @@ static void node_free(struct rtree *tr, struct node *node) { } static void rect_expand(struct rect *rect, const struct rect *other) { - for (int i = 0; i < DIMS; i++) { + for (int i = 0; i < RTREE_DIMS; i++) { rect->min[i] = min0(rect->min[i], other->min[i]); rect->max[i] = max0(rect->max[i], other->max[i]); } } -static NUMTYPE rect_area(const struct rect *rect) { - NUMTYPE result = 1; - for (int i = 0; i < DIMS; i++) { +static RTREE_NUMTYPE rect_area(const struct rect *rect) { + RTREE_NUMTYPE result = 1; + for (int i = 0; i < RTREE_DIMS; i++) { result *= (rect->max[i] - rect->min[i]); } return result; } // return the area of two rects expanded -static NUMTYPE rect_unioned_area(const struct rect *rect, +static RTREE_NUMTYPE rect_unioned_area(const struct rect *rect, const struct rect *other) { - NUMTYPE result = 1; - for (int i = 0; i < DIMS; i++) { + RTREE_NUMTYPE result = 1; + for (int i = 0; i < RTREE_DIMS; i++) { result *= (max0(rect->max[i], other->max[i]) - min0(rect->min[i], other->min[i])); } @@ -219,7 +205,7 @@ static NUMTYPE rect_unioned_area(const struct rect *rect, static bool rect_contains(const struct rect *rect, const struct rect *other) { int bits = 0; - for (int i = 0; i < DIMS; i++) { + for (int i = 0; i < RTREE_DIMS; i++) { bits |= other->min[i] < rect->min[i]; bits |= other->max[i] > rect->max[i]; } @@ -228,7 +214,7 @@ static bool rect_contains(const struct rect *rect, const struct rect *other) { static bool rect_intersects(const struct rect *rect, const struct rect *other) { int bits = 0; - for (int i = 0; i < DIMS; i++) { + for (int i = 0; i < RTREE_DIMS; i++) { bits |= other->min[i] > rect->max[i]; bits |= other->max[i] < rect->min[i]; } @@ -236,7 +222,7 @@ static bool rect_intersects(const struct rect *rect, const struct rect *other) { } static bool rect_onedge(const struct rect *rect, const struct rect *other) { - for (int i = 0; i < DIMS; i++) { + for (int i = 0; i < RTREE_DIMS; i++) { if (feq(rect->min[i], other->min[i]) || feq(rect->max[i], other->max[i])) { @@ -247,7 +233,7 @@ static bool rect_onedge(const struct rect *rect, const struct rect *other) { } static bool rect_equals(const struct rect *rect, const struct rect *other) { - for (int i = 0; i < DIMS; i++) { + for (int i = 0; i < RTREE_DIMS; i++) { if (!feq(rect->min[i], other->min[i]) || !feq(rect->max[i], other->max[i])) { @@ -258,7 +244,7 @@ static bool rect_equals(const struct rect *rect, const struct rect *other) { } static bool rect_equals_bin(const struct rect *rect, const struct rect *other) { - for (int i = 0; i < DIMS; i++) { + for (int i = 0; i < RTREE_DIMS; i++) { if (rect->min[i] != other->min[i] || rect->max[i] != other->max[i]) { @@ -270,9 +256,9 @@ static bool rect_equals_bin(const struct rect *rect, const struct rect *other) { static int rect_largest_axis(const struct rect *rect) { int axis = 0; - NUMTYPE nlength = rect->max[0] - rect->min[0]; - for (int i = 1; i < DIMS; i++) { - NUMTYPE length = rect->max[i] - rect->min[i]; + RTREE_NUMTYPE nlength = rect->max[0] - rect->min[0]; + for (int i = 1; i < RTREE_DIMS; i++) { + RTREE_NUMTYPE length = rect->max[i] - rect->min[i]; if (length > nlength) { nlength = length; axis = i; @@ -298,7 +284,7 @@ static void node_swap(struct node *node, int i, int j) { } struct rect4 { - NUMTYPE all[DIMS*2]; + RTREE_NUMTYPE all[RTREE_DIMS*2]; }; static void node_qsort(struct node *node, int s, int e, int index) { @@ -324,7 +310,7 @@ static void node_qsort(struct node *node, int s, int e, int index) { // sort the node rectangles by the axis. used during splits static void node_sort_by_axis(struct node *node, int axis, bool max) { - int by_index = max ? DIMS+axis : axis; + int by_index = max ? RTREE_DIMS+axis : axis; node_qsort(node, 0, node->count, by_index); } @@ -353,8 +339,8 @@ static bool node_split_largest_axis_edge_snap(struct rtree *tr, return false; } for (int i = 0; i < node->count; i++) { - NUMTYPE min_dist = node->rects[i].min[axis] - rect->min[axis]; - NUMTYPE max_dist = rect->max[axis] - node->rects[i].max[axis]; + RTREE_NUMTYPE min_dist = node->rects[i].min[axis] - rect->min[axis]; + RTREE_NUMTYPE max_dist = rect->max[axis] - node->rects[i].max[axis]; if (max_dist < min_dist) { // move to right node_move_rect_at_index_into(node, i, right); @@ -394,12 +380,12 @@ static int node_choose_least_enlargement(const struct node *node, const struct rect *ir) { int j = 0; - NUMTYPE jenlarge = INFINITY; + RTREE_NUMTYPE jenlarge = INFINITY; for (int i = 0; i < node->count; i++) { // calculate the enlarged area - NUMTYPE uarea = rect_unioned_area(&node->rects[i], ir); - NUMTYPE area = rect_area(&node->rects[i]); - NUMTYPE enlarge = uarea - area; + RTREE_NUMTYPE uarea = rect_unioned_area(&node->rects[i], ir); + RTREE_NUMTYPE area = rect_area(&node->rects[i]); + RTREE_NUMTYPE enlarge = uarea - area; if (enlarge < jenlarge) { j = i; jenlarge = enlarge; @@ -449,7 +435,7 @@ static bool node_insert(struct rtree *tr, struct rect *nr, struct node *node, struct rect *ir, struct item item, int depth, bool *split) { if (node->kind == LEAF) { - if (node->count == MAXITEMS) { + if (node->count == RTREE_MAXITEMS) { *split = true; return true; } @@ -474,7 +460,7 @@ static bool node_insert(struct rtree *tr, struct rect *nr, struct node *node, return true; } // split the child node - if (node->count == MAXITEMS) { + if (node->count == RTREE_MAXITEMS) { *split = true; return true; } @@ -507,29 +493,29 @@ struct rtree *rtree_new(void) { } void rtree_set_item_callbacks(struct rtree *tr, - bool (*clone)(const DATATYPE item, DATATYPE *into, void *udata), - void (*free)(const DATATYPE item, void *udata)) + bool (*clone)(const RTREE_DATATYPE item, RTREE_DATATYPE *into, void *udata), + void (*free)(const RTREE_DATATYPE item, void *udata)) { tr->item_clone = clone; tr->item_free = free; } -bool rtree_insert(struct rtree *tr, const NUMTYPE *min, - const NUMTYPE *max, const DATATYPE data) +bool rtree_insert(struct rtree *tr, const RTREE_NUMTYPE *min, + const RTREE_NUMTYPE *max, const RTREE_DATATYPE data) { // copy input rect struct rect rect; - memcpy(&rect.min[0], min, sizeof(NUMTYPE)*DIMS); - memcpy(&rect.max[0], max?max:min, sizeof(NUMTYPE)*DIMS); + memcpy(&rect.min[0], min, sizeof(RTREE_NUMTYPE)*RTREE_DIMS); + memcpy(&rect.max[0], max?max:min, sizeof(RTREE_NUMTYPE)*RTREE_DIMS); // copy input data struct item item; if (tr->item_clone) { - if (!tr->item_clone(data, (DATATYPE*)&item.data, tr->udata)) { + if (!tr->item_clone(data, (RTREE_DATATYPE*)&item.data, tr->udata)) { return false; } } else { - memcpy(&item.data, &data, sizeof(DATATYPE)); + memcpy(&item.data, &data, sizeof(RTREE_DATATYPE)); } while (1) { @@ -584,7 +570,7 @@ void rtree_free(struct rtree *tr) { } static bool node_search(struct node *node, struct rect *rect, - bool (*iter)(const NUMTYPE *min, const NUMTYPE *max, const DATATYPE data, + bool (*iter)(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, void *udata), void *udata) { @@ -610,16 +596,16 @@ static bool node_search(struct node *node, struct rect *rect, return true; } -void rtree_search(const struct rtree *tr, const NUMTYPE min[], - const NUMTYPE max[], - bool (*iter)(const NUMTYPE min[], const NUMTYPE max[], const DATATYPE data, +void rtree_search(const struct rtree *tr, const RTREE_NUMTYPE min[], + const RTREE_NUMTYPE max[], + bool (*iter)(const RTREE_NUMTYPE min[], const RTREE_NUMTYPE max[], const RTREE_DATATYPE data, void *udata), void *udata) { // copy input rect struct rect rect; - memcpy(&rect.min[0], min, sizeof(NUMTYPE)*DIMS); - memcpy(&rect.max[0], max?max:min, sizeof(NUMTYPE)*DIMS); + memcpy(&rect.min[0], min, sizeof(RTREE_NUMTYPE)*RTREE_DIMS); + memcpy(&rect.max[0], max?max:min, sizeof(RTREE_NUMTYPE)*RTREE_DIMS); if (tr->root) { node_search(tr->root, &rect, iter, udata); @@ -627,7 +613,7 @@ void rtree_search(const struct rtree *tr, const NUMTYPE min[], } static bool node_scan(struct node *node, - bool (*iter)(const NUMTYPE *min, const NUMTYPE *max, const DATATYPE data, + bool (*iter)(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, void *udata), void *udata) { @@ -650,7 +636,7 @@ static bool node_scan(struct node *node, } void rtree_scan(const struct rtree *tr, - bool (*iter)(const NUMTYPE *min, const NUMTYPE *max, const DATATYPE data, + bool (*iter)(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, void *udata), void *udata) { @@ -665,7 +651,7 @@ size_t rtree_count(const struct rtree *tr) { static bool node_delete(struct rtree *tr, struct rect *nr, struct node *node, struct rect *ir, struct item item, int depth, bool *removed, bool *shrunk, - int (*compare)(const DATATYPE a, const DATATYPE b, void *udata), + int (*compare)(const RTREE_DATATYPE a, const RTREE_DATATYPE b, void *udata), void *udata) { *removed = false; @@ -678,7 +664,7 @@ static bool node_delete(struct rtree *tr, struct rect *nr, struct node *node, } int cmp = compare ? compare(node->datas[i].data, item.data, udata) : - memcmp(&node->datas[i].data, &item.data, sizeof(DATATYPE)); + memcmp(&node->datas[i].data, &item.data, sizeof(RTREE_DATATYPE)); if (cmp != 0) { continue; } @@ -759,19 +745,19 @@ static bool node_delete(struct rtree *tr, struct rect *nr, struct node *node, } // returns false if out of memory -static bool rtree_delete0(struct rtree *tr, const NUMTYPE *min, - const NUMTYPE *max, const DATATYPE data, - int (*compare)(const DATATYPE a, const DATATYPE b, void *udata), +static bool rtree_delete0(struct rtree *tr, const RTREE_NUMTYPE *min, + const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, + int (*compare)(const RTREE_DATATYPE a, const RTREE_DATATYPE b, void *udata), void *udata) { // copy input rect struct rect rect; - memcpy(&rect.min[0], min, sizeof(NUMTYPE)*DIMS); - memcpy(&rect.max[0], max?max:min, sizeof(NUMTYPE)*DIMS); + memcpy(&rect.min[0], min, sizeof(RTREE_NUMTYPE)*RTREE_DIMS); + memcpy(&rect.max[0], max?max:min, sizeof(RTREE_NUMTYPE)*RTREE_DIMS); // copy input data struct item item; - memcpy(&item.data, &data, sizeof(DATATYPE)); + memcpy(&item.data, &data, sizeof(RTREE_DATATYPE)); if (!tr->root) { return true; @@ -808,15 +794,15 @@ static bool rtree_delete0(struct rtree *tr, const NUMTYPE *min, return true; } -bool rtree_delete(struct rtree *tr, const NUMTYPE *min, const NUMTYPE *max, - const DATATYPE data) +bool rtree_delete(struct rtree *tr, const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, + const RTREE_DATATYPE data) { return rtree_delete0(tr, min, max, data, NULL, NULL); } -bool rtree_delete_with_comparator(struct rtree *tr, const NUMTYPE *min, - const NUMTYPE *max, const DATATYPE data, - int (*compare)(const DATATYPE a, const DATATYPE b, void *udata), +bool rtree_delete_with_comparator(struct rtree *tr, const RTREE_NUMTYPE *min, + const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, + int (*compare)(const RTREE_DATATYPE a, const RTREE_DATATYPE b, void *udata), void *udata) { return rtree_delete0(tr, min, max, data, compare, udata); @@ -834,7 +820,3 @@ struct rtree *rtree_clone(struct rtree *tr) { void rtree_opt_relaxed_atomics(struct rtree *tr) { tr->relaxed = true; } - -#ifdef TEST_PRIVATE_FUNCTIONS -#include "tests/priv_funcs.h" -#endif diff --git a/rtree.h b/rtree.h index 375dcd8..69599be 100644 --- a/rtree.h +++ b/rtree.h @@ -5,9 +5,30 @@ #ifndef RTREE_H #define RTREE_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include +#ifndef RTREE_DATATYPE +#define RTREE_DATATYPE void * +#endif + +#ifndef RTREE_DIMS +#define RTREE_DIMS 2 +#endif + +#ifndef RTREE_NUMTYPE +#define RTREE_NUMTYPE double +#endif + +#ifndef RTREE_MAXITEMS +#define RTREE_MAXITEMS 64 +#endif + + // rtree_new returns a new rtree // // Returns NULL if the system is out of memory. @@ -56,22 +77,20 @@ void rtree_set_udata(struct rtree *tr, void *udata); // When inserting points, the max coordinates is optional (set to NULL). // // Returns false if the system is out of memory. -bool rtree_insert(struct rtree *tr, const double *min, const double *max, const void *data); - +bool rtree_insert(struct rtree *tr, const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const RTREE_DATATYPE data); // rtree_search searches the rtree and iterates over each item that intersect // the provided rectangle. // // Returning false from the iter will stop the search. -void rtree_search(const struct rtree *tr, const double *min, const double *max, - bool (*iter)(const double *min, const double *max, const void *data, void *udata), - void *udata); +void rtree_search(const struct rtree *tr, const RTREE_NUMTYPE min[], const RTREE_NUMTYPE max[], + bool (*iter)(const RTREE_NUMTYPE min[], const RTREE_NUMTYPE max[], const RTREE_DATATYPE data, void *udata), void *udata); // rtree_scan iterates over every item in the rtree. // // Returning false from the iter will stop the scan. void rtree_scan(const struct rtree *tr, - bool (*iter)(const double *min, const double *max, const void *data, void *udata), + bool (*iter)(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, void *udata), void *udata); // rtree_count returns the number of items in the rtree. @@ -84,7 +103,7 @@ size_t rtree_count(const struct rtree *tr); // data. The first item that is found is deleted. // // Returns false if the system is out of memory. -bool rtree_delete(struct rtree *tr, const double *min, const double *max, const void *data); +bool rtree_delete(struct rtree *tr, const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const RTREE_DATATYPE data); // rtree_delete_with_comparator deletes an item from the rtree. // This searches the tree for an item that is contained within the provided @@ -92,9 +111,9 @@ bool rtree_delete(struct rtree *tr, const double *min, const double *max, const // a compare function. The first item that is found is deleted. // // Returns false if the system is out of memory. -bool rtree_delete_with_comparator(struct rtree *tr, const double *min, - const double *max, const void *data, - int (*compare)(const void *a, const void *b, void *udata), +bool rtree_delete_with_comparator(struct rtree *tr, const RTREE_NUMTYPE *min, + const RTREE_NUMTYPE *max, const RTREE_DATATYPE data, + int (*compare)(const RTREE_DATATYPE a, const RTREE_DATATYPE b, void *udata), void *udata); // rtree_opt_relaxed_atomics activates memory_order_relaxed for all atomic @@ -102,4 +121,8 @@ bool rtree_delete_with_comparator(struct rtree *tr, const double *min, // Optionally, define RTREE_NOATOMICS to disbale all atomics. void rtree_opt_relaxed_atomics(struct rtree *tr); +#ifdef __cplusplus +} +#endif + #endif // RTREE_H diff --git a/tests/bench.c b/tests/bench.c index cd3e44e..68b8749 100644 --- a/tests/bench.c +++ b/tests/bench.c @@ -1,8 +1,5 @@ +#define TEST_PRIVATE_FUNCTIONS #include "tests.h" -#include "../rtree.h" - - - #define bench(name, N, code) {{ \ if (strlen(name) > 0) { \ @@ -12,7 +9,7 @@ size_t tallocs = (size_t)total_allocs; \ uint64_t bytes = 0; \ clock_t begin = clock(); \ - for (int i = 0; i < N; i++) { \ + { \ (code); \ } \ clock_t end = clock(); \ @@ -174,22 +171,22 @@ uint32_t hilbert(double lat, double lon) { -static bool search_iter(const double *min, const double *max, const void *item, void *udata) { +static bool search_iter(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const void *item, void *udata) { (*(int*)udata)++; return true; } struct search_iter_one_context { - double *point; + RTREE_NUMTYPE *point; void *data; int count; }; -static bool search_iter_one(const double *min, const double *max, const void *data, void *udata) { +static bool search_iter_one(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const void *data, void *udata) { struct search_iter_one_context *ctx = (struct search_iter_one_context *)udata; if (data == ctx->data) { - assert(memcmp(min, ctx->point, sizeof(double)*2) == 0); - assert(memcmp(max, ctx->point, sizeof(double)*2) == 0); + assert(memcmp(min, ctx->point, sizeof(RTREE_NUMTYPE)*RTREE_DIMS) == 0); + assert(memcmp(max, ctx->point, sizeof(RTREE_NUMTYPE)*RTREE_DIMS) == 0); ctx->count++; return false; } @@ -197,18 +194,24 @@ static bool search_iter_one(const double *min, const double *max, const void *da } int point_compare(const void *a, const void *b) { - const double *p1 = a; - const double *p2 = b; - uint32_t h1 = hilbert(p1[1],p1[0]); - uint32_t h2 = hilbert(p2[1],p2[0]); - - if (h1 < h2) { - return -1; + DISABLE_WARNING_PUSH + DISABLE_WARNING(-Wvoid-pointer-to-int-cast) + const RTREE_NUMTYPE *p1 = (const RTREE_NUMTYPE*)a; + const RTREE_NUMTYPE *p2 = (const RTREE_NUMTYPE*)b; + DISABLE_WARNING_POP + + if (is_float_point(RTREE_NUMTYPE)) { + uint32_t h1 = hilbert(p1[1],p1[0]); + uint32_t h2 = hilbert(p2[1],p2[0]); + + if (h1 < h2) { + return -1; + } + if (h1 > h2) { + return 1; + } + return 0; } - if (h1 > h2) { - return 1; - } - return 0; if (p1[0] < p2[0]) { return -1; @@ -224,168 +227,157 @@ void shuffle_points(double *points, int N) { shuffle(points, N, sizeof(double)*2); } -double *make_random_points(int N) { - double *points = (double *)xmalloc(N*2*sizeof(double)); - for (int i = 0; i < N; i++) { - points[i*2+0] = rand_double() * 360.0 - 180.0;; - points[i*2+1] = rand_double() * 180.0 - 90.0;; +RTREE_NUMTYPE *make_random_points(int N) { + RTREE_NUMTYPE *points = (RTREE_NUMTYPE *)xmalloc(N*RTREE_DIMS*sizeof(RTREE_NUMTYPE)); + if(is_float_point(RTREE_NUMTYPE)) { + for (int i = 0; i < N; i++) { + #if RTREE_DIMS == 2 + points[i*2+0] = rand_double() * 360.0 - 180.0;; + points[i*2+1] = rand_double() * 180.0 - 90.0;; + #else + for (int d = 0; d < RTREE_DIMS; d++){ + points[i*RTREE_DIMS+d] = rand_double(); + } + #endif + } + }else{ + for (int i = 0; i < N; i++) { + for (int d = 0; d < RTREE_DIMS; d++){ + points[i*RTREE_DIMS+d] = rand(); + } + } } return points; } - -void sort_points(double *points, int N) { - qsort(points, N, sizeof(double)*2, point_compare); +void sort_points(RTREE_NUMTYPE *points, int N) { + qsort(points, N, sizeof(RTREE_NUMTYPE)*RTREE_DIMS, point_compare); } -void test_rand_bench(bool hilbert_ordered, int N) { - if (hilbert_ordered) { - printf("-- HILBERT ORDER --\n"); - } else { - printf("-- RANDOM ORDER --\n"); - } - double *points = make_random_points(N); - if (hilbert_ordered) { - sort_points(points, N); - } - - struct rtree *tr = rtree_new_with_allocator(xmalloc, xfree); - bench("insert", N, { - double *point = &points[i*2]; +void insert(struct rtree *tr,RTREE_NUMTYPE *points, int N){ + for (int i = 0; i < N; i++){ + RTREE_NUMTYPE *point = &points[i*RTREE_DIMS]; rtree_insert(tr, point, point, (void *)(uintptr_t)(i)); assert(rtree_count(tr) == i+1); - }); - - rtree_check(tr); - + } +} - // sort_points(points, N); - bench("search-item", N, { - double *point = &points[i*2]; +void search_item(struct rtree *tr,RTREE_NUMTYPE *points, int N){ + for (int i = 0; i < N; i++){ + RTREE_NUMTYPE *point = &points[i*RTREE_DIMS]; struct search_iter_one_context ctx = { 0 }; ctx.point = point; ctx.data = (void *)(uintptr_t)(i); rtree_search(tr, point, point, search_iter_one, &ctx); assert(ctx.count == 1); - }); - + } +} - bench("search-1%", 1000, { - const double p = 0.01; - double min[2]; - double max[2]; - min[0] = rand_double() * 360.0 - 180.0; - min[1] = rand_double() * 180.0 - 90.0; - max[0] = min[0] + 360.0*p; - max[1] = min[1] + 180.0*p; +void search(struct rtree *tr,RTREE_NUMTYPE *points, int N, double p){ + for (int i = 0; i < N; i++){ + RTREE_NUMTYPE min[RTREE_DIMS]; + RTREE_NUMTYPE max[RTREE_DIMS]; + if(is_float_point(RTREE_NUMTYPE)){ + #if RTREE_DIMS == 2 + min[0] = rand_double() * 360.0 - 180.0; + min[1] = rand_double() * 180.0 - 90.0; + max[0] = min[0] + 360.0*p; + max[1] = min[1] + 180.0*p; + #else + for (int d = 0; d < RTREE_DIMS; d++){ + min[d] = rand_double(); + max[d] = min[d] + 360.0*p; + } + #endif + }else{ + for (int d = 0; d < RTREE_DIMS; d++){ + min[d] = rand(); + max[d] = min[d] + 360*p; + } + } int res = 0; rtree_search(tr, min, max, search_iter, &res); // printf("%d\n", res); - }); - - bench("search-5%", 1000, { - const double p = 0.05; - double min[2]; - double max[2]; - min[0] = rand_double() * 360.0 - 180.0; - min[1] = rand_double() * 180.0 - 90.0; - max[0] = min[0] + 360.0*p; - max[1] = min[1] + 180.0*p; - int res = 0; - rtree_search(tr, min, max, search_iter, &res); - }); - - bench("search-10%", 1000, { - const double p = 0.10; - double min[2]; - double max[2]; - min[0] = rand_double() * 360.0 - 180.0; - min[1] = rand_double() * 180.0 - 90.0; - max[0] = min[0] + 360.0*p; - max[1] = min[1] + 180.0*p; - int res = 0; - rtree_search(tr, min, max, search_iter, &res); - }); + } +} - bench("delete", N, { - double *point = &points[i*2]; +void delete(struct rtree *tr,RTREE_NUMTYPE *points, int N){ + for (int i = 0; i < N; i++){ + RTREE_NUMTYPE *point = &points[i*RTREE_DIMS]; rtree_delete(tr, point, point, (void*)(uintptr_t)(i)); assert(rtree_count(tr) == N-i-1); - }); - - double *points2 = (double *)xmalloc(N*2*sizeof(double)); - for (int i = 0; i < N; i++) { - double *point = &points[i*2]; - rtree_insert(tr, point, point, (void*)(uintptr_t)(i)); - assert(rtree_count(tr) == i+1); - double rsize = 0.01; // size of rectangle in degrees - points2[i*2+0] = points[i*2+0] + rand_double()*rsize - rsize/2; - points2[i*2+1] = points[i*2+1] + rand_double()*rsize - rsize/2; } +} - bench("replace", N, { +void replace(struct rtree *tr,RTREE_NUMTYPE *points, RTREE_NUMTYPE *points2, int N){ + for (int i = 0; i < N; i++){ assert(rtree_count(tr) == N); - double *point = &points[i*2]; + RTREE_NUMTYPE *point = &points[i*RTREE_DIMS]; rtree_delete(tr, point, point, (void*)(uintptr_t)(i)); assert(rtree_count(tr) == N-1); - double *point2 = &points2[i*2]; + RTREE_NUMTYPE *point2 = &points2[i*RTREE_DIMS]; rtree_insert(tr, point2, point2, (void*)(uintptr_t)(i)); assert(rtree_count(tr) == N); - }); + } +} + +void test_rand_bench(bool hilbert_ordered, int N) { + if (hilbert_ordered) { + printf("-- HILBERT ORDER --\n"); + } else { + printf("-- RANDOM ORDER --\n"); + } + RTREE_NUMTYPE *points = make_random_points(N); + if (hilbert_ordered) { + sort_points(points, N); + } + + + struct rtree *tr = rtree_new_with_allocator(xmalloc, xfree); + bench("insert", N, insert(tr,points,N)); rtree_check(tr); + // sort_points(points, N); + bench("search-item", N, search_item(tr,points,N)); + + bench("search-1%", N, search(tr,points,N,0.01)); + bench("search-5%", N, search(tr,points,N,0.05)); + bench("search-10%", N, search(tr,points,N,0.10)); + bench("delete", N, delete(tr,points,N)); - double *tmp = points; + RTREE_NUMTYPE *points2 = (RTREE_NUMTYPE *)xmalloc(N*RTREE_DIMS*sizeof(RTREE_NUMTYPE)); + for (int i = 0; i < N; i++) { + RTREE_NUMTYPE *point = &points[i*RTREE_DIMS]; + rtree_insert(tr, point, point, (void*)(uintptr_t)(i)); + assert(rtree_count(tr) == i+1); + if(is_float_point(RTREE_NUMTYPE)){ + double rsize = 0.01; // size of rectangle in degrees + for (int d = 0; d < RTREE_DIMS; d++){ + points2[i*RTREE_DIMS+d] = points2[i*RTREE_DIMS+d] + rand_double()*rsize - rsize/2; + } + }else{ + int rsize = 2; + for (int d = 0; d < RTREE_DIMS; d++){ + points2[i*RTREE_DIMS+d] = points2[i*RTREE_DIMS+d] + rand()*rsize - rsize/2; + } + } + + } + + bench("replace", N, replace(tr,points,points2,N)); + + rtree_check(tr); + + RTREE_NUMTYPE *tmp = points; points = points2; points2 = tmp; + bench("search-item", N, search_item(tr,points,N)); + bench("search-1%", N, search(tr,points,N,0.01)); + bench("search-5%", N, search(tr,points,N,0.05)); + bench("search-10%", N, search(tr,points,N,0.10)); - bench("search-item", N, { - double *point = &points[i*2]; - struct search_iter_one_context ctx = { 0 }; - ctx.point = point; - ctx.data = (void *)(uintptr_t)(i); - rtree_search(tr, point, point, search_iter_one, &ctx); - assert(ctx.count == 1); - }); - - bench("search-1%", 1000, { - const double p = 0.01; - double min[2]; - double max[2]; - min[0] = rand_double() * 360.0 - 180.0; - min[1] = rand_double() * 180.0 - 90.0; - max[0] = min[0] + 360.0*p; - max[1] = min[1] + 180.0*p; - int res = 0; - rtree_search(tr, min, max, search_iter, &res); - // printf("%d\n", res); - }); - - bench("search-5%", 1000, { - const double p = 0.05; - double min[2]; - double max[2]; - min[0] = rand_double() * 360.0 - 180.0; - min[1] = rand_double() * 180.0 - 90.0; - max[0] = min[0] + 360.0*p; - max[1] = min[1] + 180.0*p; - int res = 0; - rtree_search(tr, min, max, search_iter, &res); - }); - - bench("search-10%", 1000, { - const double p = 0.10; - double min[2]; - double max[2]; - min[0] = rand_double() * 360.0 - 180.0; - min[1] = rand_double() * 180.0 - 90.0; - max[0] = min[0] + 360.0*p; - max[1] = min[1] + 180.0*p; - int res = 0; - rtree_search(tr, min, max, search_iter, &res); - }); rtree_free(tr); xfree(points); xfree(points2); @@ -396,7 +388,7 @@ void test_rand_bench(bool hilbert_ordered, int N) { int main() { int seed = getenv("SEED")?atoi(getenv("SEED")):time(NULL); - int N = getenv("N")?atoi(getenv("N")):1000000; + int N = getenv("N")?atoi(getenv("N")):10000; printf("seed=%d, count=%d\n", seed, N); srand(seed); diff --git a/tests/priv_funcs.h b/tests/priv_funcs.h deleted file mode 100644 index 0360110..0000000 --- a/tests/priv_funcs.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifdef TEST_PRIVATE_FUNCTIONS -#include - -////////////////// -// checker -////////////////// - -static bool node_check_rect(const struct rect *rect, struct node *node) { - struct rect rect2 = node_rect_calc(node); - if (!rect_equals(rect, &rect2)){ - fprintf(stderr, "invalid rect\n"); - return false; - } - if (node->kind == BRANCH) { - for (int i = 0; i < node->count; i++) { - if (!node_check_rect(&node->rects[i], node->nodes[i])) { - return false; - } - } - } - return true; -} - -static bool rtree_check_rects(const struct rtree *tr) { - if (tr->root) { - if (!node_check_rect(&tr->rect, tr->root)) return false; - } - return true; -} - -static bool rtree_check_height(const struct rtree *tr) { - size_t height = 0; - struct node *node = tr->root; - while (node) { - height++; - if (node->kind == LEAF) break; - node = node->nodes[0]; - } - if (height != tr->height) { - fprintf(stderr, "invalid height\n"); - return false; - } - return true; -} - -bool rtree_check(const struct rtree *tr) { - if (!rtree_check_rects(tr)) return false; - if (!rtree_check_height(tr)) return false; - return true; -} - -static const double svg_scale = 20.0; -static const char *strokes[] = { "black", "red", "green", "purple" }; -static const int nstrokes = 4; - -static void node_write_svg(const struct node *node, const struct rect *rect, - FILE *f, int depth) -{ - bool point = rect->min[0] == rect->max[0] && rect->min[1] == rect->max[1]; - if (node) { - if (node->kind == BRANCH) { - for (int i = 0; i < node->count; i++) { - node_write_svg(node->nodes[i], &node->rects[i], f, depth+1); - } - } else { - for (int i = 0; i < node->count; i++) { - node_write_svg(NULL, &node->rects[i], f, depth+1); - } - } - } - if (point) { - double w = (rect->max[0]-rect->min[0]+1/svg_scale)*svg_scale*10; - fprintf(f, - "\n", - (rect->min[0])*svg_scale-w/2, - (rect->min[1])*svg_scale-w/2, - w, w, - strokes[depth%nstrokes]); - } else { - fprintf(f, - "\n", - (rect->min[0])*svg_scale, - (rect->min[1])*svg_scale, - (rect->max[0]-rect->min[0]+1/svg_scale)*svg_scale, - (rect->max[1]-rect->min[1]+1/svg_scale)*svg_scale, - strokes[depth%nstrokes], - strokes[depth%nstrokes], - 1); - } -} - -// rtree_write_svg draws the R-tree to an SVG file. This is only useful with -// small geospatial 2D dataset. -void rtree_write_svg(const struct rtree *tr, const char *path) { - FILE *f = fopen(path, "wb+"); - fprintf(f, "\n", - -190.0*svg_scale, -100.0*svg_scale, - 380.0*svg_scale, 190.0*svg_scale); - fprintf(f, "\n"); - if (tr->root) { - node_write_svg(tr->root, &tr->rect, f, 0); - } - fprintf(f, "\n"); - fprintf(f, "\n"); - fclose(f); -} - -#endif // TEST_PRIVATE_FUNCTIONS diff --git a/tests/test_clone.c b/tests/test_clone.c index bcbb1cd..d26f9b3 100644 --- a/tests/test_clone.c +++ b/tests/test_clone.c @@ -6,8 +6,8 @@ // } struct pair { - double min[2]; - double max[2]; + RTREE_NUMTYPE min[RTREE_DIMS]; + RTREE_NUMTYPE max[RTREE_DIMS]; int key; int val; }; @@ -371,7 +371,7 @@ struct iter_clone_access_all { size_t count; }; -bool iter_clone_access_all(const double min[], const double max[], +bool iter_clone_access_all(const RTREE_NUMTYPE min[], const RTREE_NUMTYPE max[], const void *data, void *udata) { (void)min; (void)max; (void)data; diff --git a/tests/test_rtree.c b/tests/test_rtree.c index 35d7595..7c4b5e8 100644 --- a/tests/test_rtree.c +++ b/tests/test_rtree.c @@ -125,6 +125,7 @@ double cities[] = {27.0500,57.4167,13.2000,47.3500,103.4167,4.2500,-71.0495,42.3 -57.8738,-21.0415,-90.8075,14.4803,100.2000,6.4333,18.0269,45.1903}; void test_rtree_predef_svg(void) { + #if RTREE_DIMS == 2 struct rtree *tr; while (!(tr = rtree_new_with_allocator(xmalloc, xfree))){} int N = sizeof(predef)/(sizeof(double)*2); @@ -134,9 +135,11 @@ void test_rtree_predef_svg(void) { } rtree_write_svg(tr, "predefined.svg"); rtree_free(tr); + #endif } void test_rtree_cities_svg(void) { + #if RTREE_DIMS == 2 struct rtree *tr; while (!(tr = rtree_new_with_allocator(xmalloc, xfree))){} int N = sizeof(cities)/(sizeof(double)*2); @@ -146,6 +149,7 @@ void test_rtree_cities_svg(void) { } rtree_write_svg(tr, "cities.svg"); rtree_free(tr); + #endif } @@ -158,7 +162,7 @@ struct iter_scan_all_ctx { size_t count; }; -bool iter_scan_all(const double *min, const double *max, const void *data, +bool iter_scan_all(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const void *data, void *udata) { (void)min; (void)max; (void)data; @@ -171,7 +175,7 @@ struct iter_two_ctx { size_t count; }; -bool iter_two(const double *min, const double *max, const void *data, +bool iter_two(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const void *data, void *udata) { (void)min; (void)max; (void)data; @@ -182,17 +186,17 @@ bool iter_two(const double *min, const double *max, const void *data, void test_rtree_ops(void) { - int N = 100000; - double *coords; - while (!(coords = xmalloc(sizeof(double)*N*4))) {} + int N = 10000; + RTREE_NUMTYPE *coords; + while (!(coords = xmalloc(sizeof(RTREE_NUMTYPE)*RTREE_DIMS*2*N))) {} for (int i = 0; i < N; i++) { - fill_rand_rect(&coords[i*4]); + fill_rand_rect(&coords[i*RTREE_DIMS*2]); } struct rtree *tr; while (!(tr = rtree_new_with_allocator(xmalloc, xfree))){} for (int i = 0; i < N; i++) { - double *min = &coords[i*4+0]; - double *max = &coords[i*4+2]; + RTREE_NUMTYPE *min = &coords[i*RTREE_DIMS*2+0]; + RTREE_NUMTYPE *max = &coords[i*RTREE_DIMS*2+RTREE_DIMS]; void *data = (void *)(uintptr_t)i; while (!rtree_insert(tr, min, max, data)){} assert(find_one(tr, min, max, data, NULL, NULL)); @@ -215,13 +219,17 @@ void test_rtree_ops(void) { // find two and stop struct iter_two_ctx ctx = { 0 }; - rtree_search(tr, (double[2]){ -180.0, -90.0 }, (double[2]){ 180.0, 90.0 }, + if(is_float_point(RTREE_NUMTYPE)){ + #if RTREE_DIMS == 2 + rtree_search(tr, (RTREE_NUMTYPE[RTREE_DIMS]){ -180.0, -90.0 }, (RTREE_NUMTYPE[RTREE_DIMS]){ 180.0, 90.0 }, iter_two, &ctx); - assert(ctx.count == 2); + assert(ctx.count == 2); + #endif + } for (int i = 0; i < N; i++) { - double *min = &coords[i*4+0]; - double *max = &coords[i*4+2]; + RTREE_NUMTYPE *min = &coords[i*RTREE_DIMS*2+0]; + RTREE_NUMTYPE *max = &coords[i*RTREE_DIMS*2+RTREE_DIMS]; void *data = (void *)(uintptr_t)i; assert(rtree_count(tr) == (size_t)(N-i)); assert(find_one(tr, min, max, data, NULL, NULL)); @@ -255,7 +263,7 @@ void test_rtree_various(void) { struct rtree *tr = rtree_new(); assert(tr); rtree_opt_relaxed_atomics(tr); - rtree_insert(tr, (double[2]){1, 1}, (double[2]){2, 2}, (void*)1); + rtree_insert(tr, (RTREE_NUMTYPE[RTREE_DIMS]){1}, (RTREE_NUMTYPE[RTREE_DIMS]){2}, (void*)1); rtree_free(tr); } @@ -263,8 +271,12 @@ void test_rtree_various(void) { int main(int argc, char **argv) { seedrand(); do_chaos_test(test_rtree_ops); - do_chaos_test(test_rtree_cities_svg); - do_chaos_test(test_rtree_predef_svg); + if(is_float_point(RTREE_NUMTYPE)){ + #if RTREE_DIMS == 2 + do_chaos_test(test_rtree_cities_svg); + do_chaos_test(test_rtree_predef_svg); + #endif + } do_test(test_rtree_various); return 0; diff --git a/tests/tests.h b/tests/tests.h index a1b5e8c..9b109aa 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -13,20 +13,151 @@ #include #include #include -#include "../rtree.h" - -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wcompound-token-split-by-macro" +#include "../rtree.c" + +#define is_float_point(x) _Generic((x)0, \ + _Bool: 0, unsigned char: 0, \ + char: 0, signed char: 0, \ + short int: 0, unsigned short int: 0, \ + int: 0, unsigned int: 0, \ + long int: 0, unsigned long int: 0, \ +long long int: 0, unsigned long long int: 0, \ + float: 1, double: 1, \ + long double: 1, char *: 0, \ + void *: 0, int *: 0, \ + default: 0) + + +#if defined(_MSC_VER) + #define DISABLE_WARNING_PUSH __pragma(warning( push )) + #define DISABLE_WARNING_POP __pragma(warning( pop )) + #define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber )) + +#elif defined(__GNUC__) || defined(__clang__) + #define DO_PRAGMA(X) _Pragma(#X) + #define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) + #define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) + #define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) +#else + #define DISABLE_WARNING_PUSH + #define DISABLE_WARNING_POP + #define DISABLE_WARNING(x) #endif -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wpedantic" -#endif +DISABLE_WARNING(-Wcompound-token-split-by-macro) +DISABLE_WARNING(-Wpedantic) + +#include + +////////////////// +// checker +////////////////// +static bool node_check_rect(const struct rect *rect, struct node *node) { + struct rect rect2 = node_rect_calc(node); + if (!rect_equals(rect, &rect2)){ + fprintf(stderr, "invalid rect\n"); + return false; + } + if (node->kind == BRANCH) { + for (int i = 0; i < node->count; i++) { + if (!node_check_rect(&node->rects[i], node->nodes[i])) { + return false; + } + } + } + return true; +} -// private rtree functions -bool rtree_check(struct rtree *tr); -void rtree_write_svg(struct rtree *tr, const char *path); +static bool rtree_check_rects(const struct rtree *tr) { + if (tr->root) { + if (!node_check_rect(&tr->rect, tr->root)) return false; + } + return true; +} + +static bool rtree_check_height(const struct rtree *tr) { + size_t height = 0; + struct node *node = tr->root; + while (node) { + height++; + if (node->kind == LEAF) break; + node = node->nodes[0]; + } + if (height != tr->height) { + fprintf(stderr, "invalid height\n"); + return false; + } + return true; +} + +bool rtree_check(const struct rtree *tr) { + if (!rtree_check_rects(tr)) return false; + if (!rtree_check_height(tr)) return false; + return true; +} + +static const double svg_scale = 20.0; +static const char *strokes[] = { "black", "red", "green", "purple" }; +static const int nstrokes = 4; + +static void node_write_svg(const struct node *node, const struct rect *rect, + FILE *f, int depth) +{ + bool point = rect->min[0] == rect->max[0] && rect->min[1] == rect->max[1]; + if (node) { + if (node->kind == BRANCH) { + for (int i = 0; i < node->count; i++) { + node_write_svg(node->nodes[i], &node->rects[i], f, depth+1); + } + } else { + for (int i = 0; i < node->count; i++) { + node_write_svg(NULL, &node->rects[i], f, depth+1); + } + } + } + if (point) { + double w = (rect->max[0]-rect->min[0]+1/svg_scale)*svg_scale*10; + fprintf(f, + "\n", + (rect->min[0])*svg_scale-w/2, + (rect->min[1])*svg_scale-w/2, + w, w, + strokes[depth%nstrokes]); + } else { + fprintf(f, + "\n", + (rect->min[0])*svg_scale, + (rect->min[1])*svg_scale, + (rect->max[0]-rect->min[0]+1/svg_scale)*svg_scale, + (rect->max[1]-rect->min[1]+1/svg_scale)*svg_scale, + strokes[depth%nstrokes], + strokes[depth%nstrokes], + 1); + } +} + +// rtree_write_svg draws the R-tree to an SVG file. This is only useful with +// small geospatial 2D dataset. +void rtree_write_svg(const struct rtree *tr, const char *path) { + FILE *f = fopen(path, "wb+"); + fprintf(f, "\n", + -190.0*svg_scale, -100.0*svg_scale, + 380.0*svg_scale, 190.0*svg_scale); + fprintf(f, "\n"); + if (tr->root) { + node_write_svg(tr->root, &tr->rect, f, 0); + } + fprintf(f, "\n"); + fprintf(f, "\n"); + fclose(f); +} int64_t crand(void) { uint64_t seed = 0; @@ -160,16 +291,26 @@ double rand_double() { return (double)rand() / ((double)RAND_MAX+1); } -struct rect { - double min[2]; - double max[2]; -}; - -void fill_rand_rect(double coords[]) { - coords[0] = rand_double()*360-180; - coords[1] = rand_double()*180-90; - coords[2] = coords[0]+(rand_double()*2); - coords[3] = coords[1]+(rand_double()*2); +void fill_rand_rect(RTREE_NUMTYPE *coords) { + if (is_float_point(RTREE_NUMTYPE)){ + #if RTREE_DIMS == 2 + coords[0] = rand_double()*360-180; + coords[1] = rand_double()*180-90; + coords[2] = coords[0]+(rand_double()*2); + coords[3] = coords[1]+(rand_double()*2); + #else + for (int d = 0; d < RTREE_DIMS; d++){ + coords[d] = rand_double(); + coords[d+RTREE_DIMS] = coords[d]+(rand_double()); + } + #endif + }else{ + for (int d = 0; d < RTREE_DIMS; d++){ + coords[d] = rand()>>1; + coords[d+RTREE_DIMS] = coords[d]+(rand()>>1); + } + } + } struct rect rand_rect() { @@ -202,7 +343,7 @@ struct find_one_context { int(*compare)(const void *a, const void *b); }; -bool find_one_iter(const double *min, const double *max, const void *data, +bool find_one_iter(const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, const void *data, void *udata) { (void)min; (void)max; @@ -217,7 +358,7 @@ bool find_one_iter(const double *min, const double *max, const void *data, return true; } -bool find_one(struct rtree *tr, const double min[], const double max[], +bool find_one(struct rtree *tr, const RTREE_NUMTYPE min[], const RTREE_NUMTYPE max[], void *data, int(*compare)(const void *a, const void *b), void **found_data) { struct find_one_context ctx = { .target = data, .compare = compare }; @@ -260,7 +401,7 @@ char *rand_key(int nchars) { static void *oom_ptr = (void*)(uintptr_t)(intptr_t)-1; -void *rtree_set(struct rtree *tr, const double *min, const double *max, +void *rtree_set(struct rtree *tr, const RTREE_NUMTYPE *min, const RTREE_NUMTYPE *max, void *data) { void *prev = NULL;