1*a27a533eSandvar /* $NetBSD: rpst.c,v 1.12 2021/11/14 20:51:57 andvar Exp $ */
21a764d8cSyamt
31a764d8cSyamt /*-
41a764d8cSyamt * Copyright (c)2009 YAMAMOTO Takashi,
51a764d8cSyamt * All rights reserved.
61a764d8cSyamt *
71a764d8cSyamt * Redistribution and use in source and binary forms, with or without
81a764d8cSyamt * modification, are permitted provided that the following conditions
91a764d8cSyamt * are met:
101a764d8cSyamt * 1. Redistributions of source code must retain the above copyright
111a764d8cSyamt * notice, this list of conditions and the following disclaimer.
121a764d8cSyamt * 2. Redistributions in binary form must reproduce the above copyright
131a764d8cSyamt * notice, this list of conditions and the following disclaimer in the
141a764d8cSyamt * documentation and/or other materials provided with the distribution.
151a764d8cSyamt *
161a764d8cSyamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171a764d8cSyamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181a764d8cSyamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191a764d8cSyamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201a764d8cSyamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211a764d8cSyamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221a764d8cSyamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231a764d8cSyamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241a764d8cSyamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251a764d8cSyamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261a764d8cSyamt * SUCH DAMAGE.
271a764d8cSyamt */
281a764d8cSyamt
291a764d8cSyamt /*
301a764d8cSyamt * radix priority search tree
311a764d8cSyamt *
321a764d8cSyamt * described in:
331a764d8cSyamt * SIAM J. COMPUT.
341a764d8cSyamt * Vol. 14, No. 2, May 1985
351a764d8cSyamt * PRIORITY SEARCH TREES
361a764d8cSyamt * EDWARD M. McCREIGHT
371a764d8cSyamt *
381a764d8cSyamt * ideas from linux:
391a764d8cSyamt * - grow tree height on-demand.
401a764d8cSyamt * - allow duplicated X values. in that case, we act as a heap.
411a764d8cSyamt */
421a764d8cSyamt
431a764d8cSyamt #include <sys/cdefs.h>
441a764d8cSyamt
45949aabf7Syamt #if defined(_KERNEL) || defined(_STANDALONE)
46*a27a533eSandvar __KERNEL_RCSID(0, "$NetBSD: rpst.c,v 1.12 2021/11/14 20:51:57 andvar Exp $");
471a764d8cSyamt #include <sys/param.h>
4825dcdd54Syamt #include <lib/libkern/libkern.h>
4925dcdd54Syamt #if defined(_STANDALONE)
5025dcdd54Syamt #include <lib/libsa/stand.h>
5125dcdd54Syamt #endif /* defined(_STANDALONE) */
52949aabf7Syamt #else /* defined(_KERNEL) || defined(_STANDALONE) */
53*a27a533eSandvar __RCSID("$NetBSD: rpst.c,v 1.12 2021/11/14 20:51:57 andvar Exp $");
541a764d8cSyamt #include <assert.h>
551a764d8cSyamt #include <stdbool.h>
561a764d8cSyamt #include <string.h>
5789ff3f9cSyamt #if 1
581a764d8cSyamt #define KASSERT assert
5989ff3f9cSyamt #else
6089ff3f9cSyamt #define KASSERT(a)
6189ff3f9cSyamt #endif
62949aabf7Syamt #endif /* defined(_KERNEL) || defined(_STANDALONE) */
631a764d8cSyamt
641a764d8cSyamt #include <sys/rpst.h>
651a764d8cSyamt
661a764d8cSyamt /*
671a764d8cSyamt * rpst_init_tree: initialize a tree.
681a764d8cSyamt */
691a764d8cSyamt
701a764d8cSyamt void
rpst_init_tree(struct rpst_tree * t)711a764d8cSyamt rpst_init_tree(struct rpst_tree *t)
721a764d8cSyamt {
731a764d8cSyamt
741a764d8cSyamt t->t_root = NULL;
751a764d8cSyamt t->t_height = 0;
761a764d8cSyamt }
771a764d8cSyamt
781a764d8cSyamt /*
791a764d8cSyamt * rpst_height2max: calculate the maximum index which can be handled by
801a764d8cSyamt * a tree with the given height.
811a764d8cSyamt *
821a764d8cSyamt * 0 ... 0x0000000000000001
831a764d8cSyamt * 1 ... 0x0000000000000003
841a764d8cSyamt * 2 ... 0x0000000000000007
851a764d8cSyamt * 3 ... 0x000000000000000f
861a764d8cSyamt *
871a764d8cSyamt * 31 ... 0x00000000ffffffff
881a764d8cSyamt *
891a764d8cSyamt * 63 ... 0xffffffffffffffff
901a764d8cSyamt */
911a764d8cSyamt
921a764d8cSyamt static uint64_t
rpst_height2max(unsigned int height)931a764d8cSyamt rpst_height2max(unsigned int height)
941a764d8cSyamt {
951a764d8cSyamt
961a764d8cSyamt KASSERT(height < 64);
971a764d8cSyamt if (height == 63) {
981a764d8cSyamt return UINT64_MAX;
991a764d8cSyamt }
1001a764d8cSyamt return (UINT64_C(1) << (height + 1)) - 1;
1011a764d8cSyamt }
1021a764d8cSyamt
1031a764d8cSyamt /*
10489ff3f9cSyamt * rpst_level2mask: calculate the mask for the given level in the tree.
10589ff3f9cSyamt *
10689ff3f9cSyamt * the mask used to index root's children is level 0.
10789ff3f9cSyamt */
10889ff3f9cSyamt
10989ff3f9cSyamt static uint64_t
rpst_level2mask(const struct rpst_tree * t,unsigned int level)11089ff3f9cSyamt rpst_level2mask(const struct rpst_tree *t, unsigned int level)
11189ff3f9cSyamt {
11289ff3f9cSyamt uint64_t mask;
11389ff3f9cSyamt
11489ff3f9cSyamt if (t->t_height < level) {
11589ff3f9cSyamt mask = 0;
11689ff3f9cSyamt } else {
11789ff3f9cSyamt mask = UINT64_C(1) << (t->t_height - level);
11889ff3f9cSyamt }
11989ff3f9cSyamt return mask;
12089ff3f9cSyamt }
12189ff3f9cSyamt
12289ff3f9cSyamt /*
1231a764d8cSyamt * rpst_startmask: calculate the mask for the start of a search.
1241a764d8cSyamt * (ie. the mask for the top-most bit)
1251a764d8cSyamt */
1261a764d8cSyamt
1271a764d8cSyamt static uint64_t
rpst_startmask(const struct rpst_tree * t)1281a764d8cSyamt rpst_startmask(const struct rpst_tree *t)
1291a764d8cSyamt {
13089ff3f9cSyamt const uint64_t mask = rpst_level2mask(t, 0);
1311a764d8cSyamt
13289ff3f9cSyamt KASSERT((mask | (mask - 1)) == rpst_height2max(t->t_height));
13389ff3f9cSyamt return mask;
1341a764d8cSyamt }
1351a764d8cSyamt
1361a764d8cSyamt /*
1375e092cbdSyamt * rpst_update_parents: update n_parent of children
1385e092cbdSyamt */
1395e092cbdSyamt
1405e092cbdSyamt static inline void
rpst_update_parents(struct rpst_node * n)1415e092cbdSyamt rpst_update_parents(struct rpst_node *n)
1425e092cbdSyamt {
1435e092cbdSyamt int i;
1445e092cbdSyamt
1455e092cbdSyamt for (i = 0; i < 2; i++) {
1465e092cbdSyamt if (n->n_children[i] != NULL) {
1475e092cbdSyamt n->n_children[i]->n_parent = n;
1485e092cbdSyamt }
1495e092cbdSyamt }
1505e092cbdSyamt }
1515e092cbdSyamt
1525e092cbdSyamt /*
153502e0d2fSyamt * rpst_enlarge_tree: enlarge tree so that 'idx' can be stored
1541a764d8cSyamt */
1551a764d8cSyamt
1561a764d8cSyamt static void
rpst_enlarge_tree(struct rpst_tree * t,uint64_t idx)1571a764d8cSyamt rpst_enlarge_tree(struct rpst_tree *t, uint64_t idx)
1581a764d8cSyamt {
1591a764d8cSyamt
1601a764d8cSyamt while (idx > rpst_height2max(t->t_height)) {
1611a764d8cSyamt struct rpst_node *n = t->t_root;
1621a764d8cSyamt
1631a764d8cSyamt if (n != NULL) {
1641a764d8cSyamt rpst_remove_node(t, n);
1651a764d8cSyamt memset(&n->n_children, 0, sizeof(n->n_children));
1661a764d8cSyamt n->n_children[0] = t->t_root;
1675e092cbdSyamt t->t_root->n_parent = n;
1681a764d8cSyamt t->t_root = n;
1695e092cbdSyamt n->n_parent = NULL;
1701a764d8cSyamt }
1711a764d8cSyamt t->t_height++;
1721a764d8cSyamt }
1731a764d8cSyamt }
1741a764d8cSyamt
1751a764d8cSyamt /*
1761a764d8cSyamt * rpst_insert_node1: a helper for rpst_insert_node.
1771a764d8cSyamt */
1781a764d8cSyamt
1791a764d8cSyamt static struct rpst_node *
rpst_insert_node1(struct rpst_node ** where,struct rpst_node * n,uint64_t mask)1801a764d8cSyamt rpst_insert_node1(struct rpst_node **where, struct rpst_node *n, uint64_t mask)
1811a764d8cSyamt {
1825e092cbdSyamt struct rpst_node *parent;
1831a764d8cSyamt struct rpst_node *cur;
1841a764d8cSyamt unsigned int idx;
1851a764d8cSyamt
1861a764d8cSyamt KASSERT((n->n_x & ((-mask) << 1)) == 0);
1875e092cbdSyamt parent = NULL;
1881a764d8cSyamt next:
1891a764d8cSyamt cur = *where;
1901a764d8cSyamt if (cur == NULL) {
1915e092cbdSyamt n->n_parent = parent;
1921a764d8cSyamt memset(&n->n_children, 0, sizeof(n->n_children));
1931a764d8cSyamt *where = n;
1941a764d8cSyamt return NULL;
1951a764d8cSyamt }
1965e092cbdSyamt KASSERT(cur->n_parent == parent);
19789c1ff56Syamt if (n->n_y == cur->n_y && n->n_x == cur->n_x) {
1981a764d8cSyamt return cur;
1991a764d8cSyamt }
2001a764d8cSyamt if (n->n_y < cur->n_y) {
2015e092cbdSyamt /*
2025e092cbdSyamt * swap cur and n.
2035e092cbdSyamt * note that n is not in tree.
2045e092cbdSyamt */
2051a764d8cSyamt memcpy(n->n_children, cur->n_children, sizeof(n->n_children));
2065e092cbdSyamt n->n_parent = cur->n_parent;
2075e092cbdSyamt rpst_update_parents(n);
2081a764d8cSyamt *where = n;
2091a764d8cSyamt n = cur;
2101a764d8cSyamt cur = *where;
2111a764d8cSyamt }
2121a764d8cSyamt KASSERT(*where == cur);
2131a764d8cSyamt idx = (n->n_x & mask) != 0;
2141a764d8cSyamt where = &cur->n_children[idx];
2155e092cbdSyamt parent = cur;
21689ff3f9cSyamt KASSERT((*where) == NULL || ((((*where)->n_x & mask) != 0) == idx));
21789ff3f9cSyamt KASSERT((*where) == NULL || (*where)->n_y >= cur->n_y);
2181a764d8cSyamt mask >>= 1;
2191a764d8cSyamt goto next;
2201a764d8cSyamt }
2211a764d8cSyamt
2221a764d8cSyamt /*
2231a764d8cSyamt * rpst_insert_node: insert a node into the tree.
2241a764d8cSyamt *
2251a764d8cSyamt * => return NULL on success.
2261a764d8cSyamt * => if a duplicated node (a node with the same X,Y pair as ours) is found,
2271a764d8cSyamt * return the node. in that case, the tree is intact.
2281a764d8cSyamt */
2291a764d8cSyamt
2301a764d8cSyamt struct rpst_node *
rpst_insert_node(struct rpst_tree * t,struct rpst_node * n)2311a764d8cSyamt rpst_insert_node(struct rpst_tree *t, struct rpst_node *n)
2321a764d8cSyamt {
2331a764d8cSyamt
2341a764d8cSyamt rpst_enlarge_tree(t, n->n_x);
2351a764d8cSyamt return rpst_insert_node1(&t->t_root, n, rpst_startmask(t));
2361a764d8cSyamt }
2371a764d8cSyamt
2381a764d8cSyamt /*
2391a764d8cSyamt * rpst_find_pptr: find a pointer to the given node.
2401a764d8cSyamt *
2411a764d8cSyamt * also, return the parent node via parentp. (NULL for the root node.)
2421a764d8cSyamt */
2431a764d8cSyamt
2445e092cbdSyamt static inline struct rpst_node **
rpst_find_pptr(struct rpst_tree * t,struct rpst_node * n,struct rpst_node ** parentp)2455e092cbdSyamt rpst_find_pptr(struct rpst_tree *t, struct rpst_node *n,
2461a764d8cSyamt struct rpst_node **parentp)
2471a764d8cSyamt {
2485e092cbdSyamt struct rpst_node * const parent = n->n_parent;
2495e092cbdSyamt unsigned int i;
2501a764d8cSyamt
2515e092cbdSyamt *parentp = parent;
2525e092cbdSyamt if (parent == NULL) {
2535e092cbdSyamt return &t->t_root;
2541a764d8cSyamt }
2555e092cbdSyamt for (i = 0; i < 2 - 1; i++) {
2565e092cbdSyamt if (parent->n_children[i] == n) {
2575e092cbdSyamt break;
2585e092cbdSyamt }
2595e092cbdSyamt }
2605e092cbdSyamt KASSERT(parent->n_children[i] == n);
2615e092cbdSyamt return &parent->n_children[i];
2621a764d8cSyamt }
2631a764d8cSyamt
2641a764d8cSyamt /*
2651a764d8cSyamt * rpst_remove_node_at: remove a node at *where.
2661a764d8cSyamt */
2671a764d8cSyamt
2681a764d8cSyamt static void
rpst_remove_node_at(struct rpst_node * parent,struct rpst_node ** where,struct rpst_node * cur)2695e092cbdSyamt rpst_remove_node_at(struct rpst_node *parent, struct rpst_node **where,
2705e092cbdSyamt struct rpst_node *cur)
2711a764d8cSyamt {
2721a764d8cSyamt struct rpst_node *tmp[2];
2731a764d8cSyamt struct rpst_node *selected;
2745e092cbdSyamt unsigned int selected_idx = 0; /* XXX gcc */
2751a764d8cSyamt unsigned int i;
2761a764d8cSyamt
2771a764d8cSyamt KASSERT(cur != NULL);
2785e092cbdSyamt KASSERT(parent == cur->n_parent);
2791a764d8cSyamt next:
2801a764d8cSyamt selected = NULL;
2811a764d8cSyamt for (i = 0; i < 2; i++) {
2821a764d8cSyamt struct rpst_node *c;
2831a764d8cSyamt
2841a764d8cSyamt c = cur->n_children[i];
2855e092cbdSyamt KASSERT(c == NULL || c->n_parent == cur);
2861a764d8cSyamt if (selected == NULL || (c != NULL && c->n_y < selected->n_y)) {
2871a764d8cSyamt selected = c;
2881a764d8cSyamt selected_idx = i;
2891a764d8cSyamt }
2901a764d8cSyamt }
29103578bbeSyamt /*
29203578bbeSyamt * now we have:
29303578bbeSyamt *
2945e092cbdSyamt * parent
29503578bbeSyamt * \ <- where
29603578bbeSyamt * cur
29703578bbeSyamt * / \
29803578bbeSyamt * A selected
29903578bbeSyamt * / \
30003578bbeSyamt * B C
30103578bbeSyamt */
3021a764d8cSyamt *where = selected;
3031a764d8cSyamt if (selected == NULL) {
3041a764d8cSyamt return;
3051a764d8cSyamt }
3061a764d8cSyamt /*
3071a764d8cSyamt * swap selected->n_children and cur->n_children.
3081a764d8cSyamt */
3091a764d8cSyamt memcpy(tmp, selected->n_children, sizeof(tmp));
3101a764d8cSyamt memcpy(selected->n_children, cur->n_children, sizeof(tmp));
3111a764d8cSyamt memcpy(cur->n_children, tmp, sizeof(tmp));
3125e092cbdSyamt rpst_update_parents(cur);
3135e092cbdSyamt rpst_update_parents(selected);
3145e092cbdSyamt selected->n_parent = parent;
31503578bbeSyamt /*
3165e092cbdSyamt * parent
31703578bbeSyamt * \ <- where
31803578bbeSyamt * selected
31903578bbeSyamt * / \
32003578bbeSyamt * A selected
32103578bbeSyamt *
32203578bbeSyamt * cur
32303578bbeSyamt * / \
32403578bbeSyamt * B C
32503578bbeSyamt */
3261a764d8cSyamt where = &selected->n_children[selected_idx];
32703578bbeSyamt /*
3285e092cbdSyamt * parent
32903578bbeSyamt * \
33003578bbeSyamt * selected
33103578bbeSyamt * / \ <- where
3325e092cbdSyamt * A selected (*)
33303578bbeSyamt *
3345e092cbdSyamt * cur (**)
33503578bbeSyamt * / \
33603578bbeSyamt * B C
3375e092cbdSyamt *
3385e092cbdSyamt * (*) this 'selected' will be overwritten in the next iteration.
3395e092cbdSyamt * (**) cur->n_parent is bogus.
34003578bbeSyamt */
3415e092cbdSyamt parent = selected;
3421a764d8cSyamt goto next;
3431a764d8cSyamt }
3441a764d8cSyamt
3451a764d8cSyamt /*
3461a764d8cSyamt * rpst_remove_node: remove a node from the tree.
3471a764d8cSyamt */
3481a764d8cSyamt
3491a764d8cSyamt void
rpst_remove_node(struct rpst_tree * t,struct rpst_node * n)3501a764d8cSyamt rpst_remove_node(struct rpst_tree *t, struct rpst_node *n)
3511a764d8cSyamt {
3521a764d8cSyamt struct rpst_node *parent;
3531a764d8cSyamt struct rpst_node **where;
3541a764d8cSyamt
3555e092cbdSyamt where = rpst_find_pptr(t, n, &parent);
3565e092cbdSyamt rpst_remove_node_at(parent, where, n);
3571a764d8cSyamt }
3581a764d8cSyamt
3591a764d8cSyamt static bool __unused
rpst_iterator_match_p(const struct rpst_node * n,const struct rpst_iterator * it)3601a764d8cSyamt rpst_iterator_match_p(const struct rpst_node *n, const struct rpst_iterator *it)
3611a764d8cSyamt {
3621a764d8cSyamt
3631a764d8cSyamt if (n->n_y > it->it_max_y) {
3641a764d8cSyamt return false;
3651a764d8cSyamt }
3661a764d8cSyamt if (n->n_x < it->it_min_x) {
3671a764d8cSyamt return false;
3681a764d8cSyamt }
3691a764d8cSyamt if (n->n_x > it->it_max_x) {
3701a764d8cSyamt return false;
3711a764d8cSyamt }
3721a764d8cSyamt return true;
3731a764d8cSyamt }
3741a764d8cSyamt
3751a764d8cSyamt struct rpst_node *
rpst_iterate_first(struct rpst_tree * t,uint64_t max_y,uint64_t min_x,uint64_t max_x,struct rpst_iterator * it)3761a764d8cSyamt rpst_iterate_first(struct rpst_tree *t, uint64_t max_y, uint64_t min_x,
3771a764d8cSyamt uint64_t max_x, struct rpst_iterator *it)
3781a764d8cSyamt {
3791a764d8cSyamt struct rpst_node *n;
3801a764d8cSyamt
3811a764d8cSyamt KASSERT(min_x <= max_x);
3821a764d8cSyamt n = t->t_root;
38389ff3f9cSyamt if (n == NULL || n->n_y > max_y) {
3841a764d8cSyamt return NULL;
3851a764d8cSyamt }
38606817202Syamt if (rpst_height2max(t->t_height) < min_x) {
38706817202Syamt return NULL;
38806817202Syamt }
3891a764d8cSyamt it->it_tree = t;
3901a764d8cSyamt it->it_cur = n;
39189ff3f9cSyamt it->it_idx = (min_x & rpst_startmask(t)) != 0;
3921a764d8cSyamt it->it_level = 0;
3931a764d8cSyamt it->it_max_y = max_y;
3941a764d8cSyamt it->it_min_x = min_x;
3951a764d8cSyamt it->it_max_x = max_x;
3961a764d8cSyamt return rpst_iterate_next(it);
3971a764d8cSyamt }
3981a764d8cSyamt
39987a9663cSyamt static inline unsigned int
rpst_node_on_edge_p(const struct rpst_node * n,uint64_t val,uint64_t mask)40089ff3f9cSyamt rpst_node_on_edge_p(const struct rpst_node *n, uint64_t val, uint64_t mask)
40189ff3f9cSyamt {
40289ff3f9cSyamt
40389ff3f9cSyamt return ((n->n_x ^ val) & ((-mask) << 1)) == 0;
40489ff3f9cSyamt }
40589ff3f9cSyamt
40687a9663cSyamt static inline uint64_t
rpst_maxidx(const struct rpst_node * n,uint64_t max_x,uint64_t mask)40789ff3f9cSyamt rpst_maxidx(const struct rpst_node *n, uint64_t max_x, uint64_t mask)
40889ff3f9cSyamt {
40989ff3f9cSyamt
41089ff3f9cSyamt if (rpst_node_on_edge_p(n, max_x, mask)) {
41189ff3f9cSyamt return (max_x & mask) != 0;
41289ff3f9cSyamt } else {
41389ff3f9cSyamt return 1;
41489ff3f9cSyamt }
41589ff3f9cSyamt }
41689ff3f9cSyamt
41787a9663cSyamt static inline uint64_t
rpst_minidx(const struct rpst_node * n,uint64_t min_x,uint64_t mask)41889ff3f9cSyamt rpst_minidx(const struct rpst_node *n, uint64_t min_x, uint64_t mask)
41989ff3f9cSyamt {
42089ff3f9cSyamt
42189ff3f9cSyamt if (rpst_node_on_edge_p(n, min_x, mask)) {
42289ff3f9cSyamt return (min_x & mask) != 0;
42389ff3f9cSyamt } else {
42489ff3f9cSyamt return 0;
42589ff3f9cSyamt }
42689ff3f9cSyamt }
42789ff3f9cSyamt
4281a764d8cSyamt struct rpst_node *
rpst_iterate_next(struct rpst_iterator * it)4291a764d8cSyamt rpst_iterate_next(struct rpst_iterator *it)
4301a764d8cSyamt {
4311a764d8cSyamt struct rpst_tree *t;
4321a764d8cSyamt struct rpst_node *n;
4331a764d8cSyamt struct rpst_node *next;
4341a764d8cSyamt const uint64_t max_y = it->it_max_y;
4351a764d8cSyamt const uint64_t min_x = it->it_min_x;
4361a764d8cSyamt const uint64_t max_x = it->it_max_x;
4371a764d8cSyamt unsigned int idx;
4381a764d8cSyamt unsigned int maxidx;
4391a764d8cSyamt unsigned int level;
4401a764d8cSyamt uint64_t mask;
4411a764d8cSyamt
4421a764d8cSyamt t = it->it_tree;
4431a764d8cSyamt n = it->it_cur;
4441a764d8cSyamt idx = it->it_idx;
4451a764d8cSyamt level = it->it_level;
4461a764d8cSyamt mask = rpst_level2mask(t, level);
44789ff3f9cSyamt maxidx = rpst_maxidx(n, max_x, mask);
4481a764d8cSyamt KASSERT(n == t->t_root || rpst_iterator_match_p(n, it));
4491a764d8cSyamt next:
4501a764d8cSyamt KASSERT(mask == rpst_level2mask(t, level));
45189ff3f9cSyamt KASSERT(idx >= rpst_minidx(n, min_x, mask));
45289ff3f9cSyamt KASSERT(maxidx == rpst_maxidx(n, max_x, mask));
4531a764d8cSyamt KASSERT(idx <= maxidx + 2);
4541a764d8cSyamt KASSERT(n != NULL);
4551a764d8cSyamt #if 0
4561a764d8cSyamt printf("%s: cur=%p, idx=%u maxidx=%u level=%u mask=%" PRIx64 "\n",
4571a764d8cSyamt __func__, (void *)n, idx, maxidx, level, mask);
4581a764d8cSyamt #endif
4591a764d8cSyamt if (idx == maxidx + 1) { /* visit the current node */
4601a764d8cSyamt idx++;
4611a764d8cSyamt if (min_x <= n->n_x && n->n_x <= max_x) {
4621a764d8cSyamt it->it_cur = n;
4631a764d8cSyamt it->it_idx = idx;
4641a764d8cSyamt it->it_level = level;
4651a764d8cSyamt KASSERT(rpst_iterator_match_p(n, it));
4661a764d8cSyamt return n; /* report */
4671a764d8cSyamt }
4681a764d8cSyamt goto next;
4691a764d8cSyamt } else if (idx == maxidx + 2) { /* back to the parent */
4701a764d8cSyamt struct rpst_node **where;
4711a764d8cSyamt
4725e092cbdSyamt where = rpst_find_pptr(t, n, &next);
4731a764d8cSyamt if (next == NULL) {
4741a764d8cSyamt KASSERT(level == 0);
4751a764d8cSyamt KASSERT(t->t_root == n);
4761a764d8cSyamt KASSERT(&t->t_root == where);
4771a764d8cSyamt return NULL; /* done */
4781a764d8cSyamt }
4791a764d8cSyamt KASSERT(level > 0);
4801a764d8cSyamt level--;
4811a764d8cSyamt n = next;
48289ff3f9cSyamt mask = rpst_level2mask(t, level);
48389ff3f9cSyamt maxidx = rpst_maxidx(n, max_x, mask);
4841a764d8cSyamt idx = where - n->n_children + 1;
4851a764d8cSyamt KASSERT(idx < 2 + 1);
4861a764d8cSyamt goto next;
4871a764d8cSyamt }
4881a764d8cSyamt /* go to a child */
4891a764d8cSyamt KASSERT(idx < 2);
4901a764d8cSyamt next = n->n_children[idx];
4911a764d8cSyamt if (next == NULL || next->n_y > max_y) {
4921a764d8cSyamt idx++;
4931a764d8cSyamt goto next;
4941a764d8cSyamt }
4955e092cbdSyamt KASSERT(next->n_parent == n);
49689ff3f9cSyamt KASSERT(next->n_y >= n->n_y);
4971a764d8cSyamt level++;
4981a764d8cSyamt mask >>= 1;
4991a764d8cSyamt n = next;
50089ff3f9cSyamt idx = rpst_minidx(n, min_x, mask);
50189ff3f9cSyamt maxidx = rpst_maxidx(n, max_x, mask);
50289ff3f9cSyamt #if 0
50389ff3f9cSyamt printf("%s: visit %p idx=%u level=%u mask=%llx\n",
50489ff3f9cSyamt __func__, n, idx, level, mask);
50589ff3f9cSyamt #endif
5061a764d8cSyamt goto next;
5071a764d8cSyamt }
5081a764d8cSyamt
5091a764d8cSyamt #if defined(UNITTEST)
5101a764d8cSyamt #include <sys/time.h>
5111a764d8cSyamt
5121a764d8cSyamt #include <inttypes.h>
5131a764d8cSyamt #include <stdio.h>
5141a764d8cSyamt #include <stdlib.h>
5151a764d8cSyamt
5161a764d8cSyamt static void
rpst_dump_node(const struct rpst_node * n,unsigned int depth)5171a764d8cSyamt rpst_dump_node(const struct rpst_node *n, unsigned int depth)
5181a764d8cSyamt {
5191a764d8cSyamt unsigned int i;
5201a764d8cSyamt
5211a764d8cSyamt for (i = 0; i < depth; i++) {
5221a764d8cSyamt printf(" ");
5231a764d8cSyamt }
5241a764d8cSyamt printf("[%u]", depth);
5251a764d8cSyamt if (n == NULL) {
5261a764d8cSyamt printf("NULL\n");
5271a764d8cSyamt return;
5281a764d8cSyamt }
5291a764d8cSyamt printf("%p x=%" PRIx64 "(%" PRIu64 ") y=%" PRIx64 "(%" PRIu64 ")\n",
5301a764d8cSyamt (const void *)n, n->n_x, n->n_x, n->n_y, n->n_y);
5311a764d8cSyamt for (i = 0; i < 2; i++) {
5321a764d8cSyamt rpst_dump_node(n->n_children[i], depth + 1);
5331a764d8cSyamt }
5341a764d8cSyamt }
5351a764d8cSyamt
5361a764d8cSyamt static void
rpst_dump_tree(const struct rpst_tree * t)5371a764d8cSyamt rpst_dump_tree(const struct rpst_tree *t)
5381a764d8cSyamt {
5391a764d8cSyamt
54089ff3f9cSyamt printf("pst %p height=%u\n", (const void *)t, t->t_height);
5411a764d8cSyamt rpst_dump_node(t->t_root, 0);
5421a764d8cSyamt }
5431a764d8cSyamt
5441a764d8cSyamt struct testnode {
5451a764d8cSyamt struct rpst_node n;
5461a764d8cSyamt struct testnode *next;
54789ff3f9cSyamt bool failed;
54889ff3f9cSyamt bool found;
5491a764d8cSyamt };
5501a764d8cSyamt
5511a764d8cSyamt struct rpst_tree t;
5521a764d8cSyamt struct testnode *h = NULL;
55389ff3f9cSyamt
55489ff3f9cSyamt static uintmax_t
tvdiff(const struct timeval * tv1,const struct timeval * tv2)55589ff3f9cSyamt tvdiff(const struct timeval *tv1, const struct timeval *tv2)
55689ff3f9cSyamt {
55789ff3f9cSyamt
55889ff3f9cSyamt return (uintmax_t)tv1->tv_sec * 1000000 + tv1->tv_usec -
55989ff3f9cSyamt tv2->tv_sec * 1000000 - tv2->tv_usec;
56089ff3f9cSyamt }
56189ff3f9cSyamt
56289ff3f9cSyamt static unsigned int
query(uint64_t max_y,uint64_t min_x,uint64_t max_x)56389ff3f9cSyamt query(uint64_t max_y, uint64_t min_x, uint64_t max_x)
56489ff3f9cSyamt {
5651a764d8cSyamt struct testnode *n;
5661a764d8cSyamt struct rpst_node *rn;
5671a764d8cSyamt struct rpst_iterator it;
5681a764d8cSyamt struct timeval start;
5691a764d8cSyamt struct timeval end;
5701a764d8cSyamt unsigned int done;
5711a764d8cSyamt
572*a27a533eSandvar printf("querying max_y=%" PRIu64 " min_x=%" PRIu64 " max_x=%" PRIu64
57389ff3f9cSyamt "\n",
57489ff3f9cSyamt max_y, min_x, max_x);
57589ff3f9cSyamt done = 0;
57689ff3f9cSyamt gettimeofday(&start, NULL);
57789ff3f9cSyamt for (rn = rpst_iterate_first(&t, max_y, min_x, max_x, &it);
57889ff3f9cSyamt rn != NULL;
57989ff3f9cSyamt rn = rpst_iterate_next(&it)) {
58089ff3f9cSyamt done++;
58189ff3f9cSyamt #if 0
58289ff3f9cSyamt printf("found %p x=%" PRIu64 " y=%" PRIu64 "\n",
58389ff3f9cSyamt (void *)rn, rn->n_x, rn->n_y);
58489ff3f9cSyamt #endif
58589ff3f9cSyamt n = (void *)rn;
58689ff3f9cSyamt assert(!n->found);
58789ff3f9cSyamt n->found = true;
58889ff3f9cSyamt }
58989ff3f9cSyamt gettimeofday(&end, NULL);
59089ff3f9cSyamt printf("%u nodes found in %ju usecs\n", done,
59189ff3f9cSyamt tvdiff(&end, &start));
59289ff3f9cSyamt
59389ff3f9cSyamt gettimeofday(&start, NULL);
59489ff3f9cSyamt for (n = h; n != NULL; n = n->next) {
59589ff3f9cSyamt assert(n->failed ||
59689ff3f9cSyamt n->found == rpst_iterator_match_p(&n->n, &it));
59789ff3f9cSyamt n->found = false;
59889ff3f9cSyamt }
59989ff3f9cSyamt gettimeofday(&end, NULL);
60089ff3f9cSyamt printf("(linear search took %ju usecs)\n", tvdiff(&end, &start));
60189ff3f9cSyamt return done;
60289ff3f9cSyamt }
60389ff3f9cSyamt
60489ff3f9cSyamt int
main(int argc,char * argv[])60589ff3f9cSyamt main(int argc, char *argv[])
60689ff3f9cSyamt {
60789ff3f9cSyamt struct testnode *n;
60889ff3f9cSyamt unsigned int i;
60989ff3f9cSyamt struct rpst_iterator it;
61089ff3f9cSyamt struct timeval start;
61189ff3f9cSyamt struct timeval end;
61289ff3f9cSyamt uint64_t min_y = UINT64_MAX;
61389ff3f9cSyamt uint64_t max_y = 0;
61489ff3f9cSyamt uint64_t min_x = UINT64_MAX;
61589ff3f9cSyamt uint64_t max_x = 0;
61689ff3f9cSyamt uint64_t w;
61789ff3f9cSyamt unsigned int done;
61889ff3f9cSyamt unsigned int fail;
61989ff3f9cSyamt unsigned int num = 500000;
62089ff3f9cSyamt
6211a764d8cSyamt rpst_init_tree(&t);
6221a764d8cSyamt rpst_dump_tree(&t);
6231a764d8cSyamt assert(NULL == rpst_iterate_first(&t, UINT64_MAX, 0, UINT64_MAX, &it));
6241a764d8cSyamt
62589ff3f9cSyamt for (i = 0; i < num; i++) {
6261a764d8cSyamt n = malloc(sizeof(*n));
6271a764d8cSyamt if (i > 499000) {
6281a764d8cSyamt n->n.n_x = 10;
6291a764d8cSyamt n->n.n_y = random();
6301a764d8cSyamt } else if (i > 400000) {
6311a764d8cSyamt n->n.n_x = i;
6321a764d8cSyamt n->n.n_y = random();
6331a764d8cSyamt } else {
6341a764d8cSyamt n->n.n_x = random();
6351a764d8cSyamt n->n.n_y = random();
6361a764d8cSyamt }
63789ff3f9cSyamt if (n->n.n_y < min_y) {
63889ff3f9cSyamt min_y = n->n.n_y;
63989ff3f9cSyamt }
64089ff3f9cSyamt if (n->n.n_y > max_y) {
64189ff3f9cSyamt max_y = n->n.n_y;
64289ff3f9cSyamt }
64389ff3f9cSyamt if (n->n.n_x < min_x) {
64489ff3f9cSyamt min_x = n->n.n_x;
64589ff3f9cSyamt }
64689ff3f9cSyamt if (n->n.n_x > max_x) {
64789ff3f9cSyamt max_x = n->n.n_x;
64889ff3f9cSyamt }
64989ff3f9cSyamt n->found = false;
65089ff3f9cSyamt n->failed = false;
6511a764d8cSyamt n->next = h;
6521a764d8cSyamt h = n;
6531a764d8cSyamt }
6541a764d8cSyamt
6551a764d8cSyamt done = 0;
65689ff3f9cSyamt fail = 0;
6571a764d8cSyamt gettimeofday(&start, NULL);
65889ff3f9cSyamt for (n = h; n != NULL; n = n->next) {
65989ff3f9cSyamt struct rpst_node *o;
6601a764d8cSyamt #if 0
66189ff3f9cSyamt printf("insert %p x=%" PRIu64 " y=%" PRIu64 "\n",
66289ff3f9cSyamt n, n->n.n_x, n->n.n_y);
6631a764d8cSyamt #endif
66489ff3f9cSyamt o = rpst_insert_node(&t, &n->n);
66589ff3f9cSyamt if (o == NULL) {
66689ff3f9cSyamt done++;
66789ff3f9cSyamt } else {
66889ff3f9cSyamt n->failed = true;
66989ff3f9cSyamt fail++;
67089ff3f9cSyamt }
6711a764d8cSyamt }
6721a764d8cSyamt gettimeofday(&end, NULL);
67389ff3f9cSyamt printf("%u nodes inserted and %u insertion failed in %ju usecs\n",
67489ff3f9cSyamt done, fail,
67589ff3f9cSyamt tvdiff(&end, &start));
67689ff3f9cSyamt
67789ff3f9cSyamt assert(min_y == 0 || 0 == query(min_y - 1, 0, UINT64_MAX));
67889ff3f9cSyamt assert(max_x == UINT64_MAX ||
67989ff3f9cSyamt 0 == query(UINT64_MAX, max_x + 1, UINT64_MAX));
68089ff3f9cSyamt assert(min_x == 0 || 0 == query(UINT64_MAX, 0, min_x - 1));
68189ff3f9cSyamt
68289ff3f9cSyamt done = query(max_y, min_x, max_x);
68389ff3f9cSyamt assert(done == num - fail);
68489ff3f9cSyamt
68589ff3f9cSyamt done = query(UINT64_MAX, 0, UINT64_MAX);
68689ff3f9cSyamt assert(done == num - fail);
68789ff3f9cSyamt
68889ff3f9cSyamt w = max_x - min_x;
68989ff3f9cSyamt query(max_y / 2, min_x, max_x);
69089ff3f9cSyamt query(max_y, min_x + w / 2, max_x);
69189ff3f9cSyamt query(max_y / 2, min_x + w / 2, max_x);
69289ff3f9cSyamt query(max_y / 2, min_x, max_x - w / 2);
69389ff3f9cSyamt query(max_y / 2, min_x + w / 3, max_x - w / 3);
69489ff3f9cSyamt query(max_y - 1, min_x + 1, max_x - 1);
69589ff3f9cSyamt query(UINT64_MAX, 10, 10);
6961a764d8cSyamt
6971a764d8cSyamt done = 0;
6981a764d8cSyamt gettimeofday(&start, NULL);
69989ff3f9cSyamt for (n = h; n != NULL; n = n->next) {
70089ff3f9cSyamt if (n->failed) {
70189ff3f9cSyamt continue;
70289ff3f9cSyamt }
7031a764d8cSyamt #if 0
70489ff3f9cSyamt printf("remove %p x=%" PRIu64 " y=%" PRIu64 "\n",
7051a764d8cSyamt n, n->n.n_x, n->n.n_y);
7061a764d8cSyamt #endif
7071a764d8cSyamt rpst_remove_node(&t, &n->n);
7081a764d8cSyamt done++;
7091a764d8cSyamt }
7101a764d8cSyamt gettimeofday(&end, NULL);
7111a764d8cSyamt printf("%u nodes removed in %ju usecs\n", done,
71289ff3f9cSyamt tvdiff(&end, &start));
7131a764d8cSyamt
7141a764d8cSyamt rpst_dump_tree(&t);
7151a764d8cSyamt }
7161a764d8cSyamt #endif /* defined(UNITTEST) */
717