xref: /netbsd-src/common/lib/libc/gen/rpst.c (revision a27a533e2ddbe19942a464029ad899d01b80ad4d)
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