Module Name:    src
Committed By:   yamt
Date:           Wed May 20 10:56:29 UTC 2009

Modified Files:
        src/common/lib/libc/gen: rpst.c

Log Message:
- fix various bugs in the iteration code.
- add assertions.
- unittest: more tests.  verify query results by comparing with linear search.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/common/lib/libc/gen/rpst.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/common/lib/libc/gen/rpst.c
diff -u src/common/lib/libc/gen/rpst.c:1.1 src/common/lib/libc/gen/rpst.c:1.2
--- src/common/lib/libc/gen/rpst.c:1.1	Tue May 19 12:39:56 2009
+++ src/common/lib/libc/gen/rpst.c	Wed May 20 10:56:29 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rpst.c,v 1.1 2009/05/19 12:39:56 yamt Exp $	*/
+/*	$NetBSD: rpst.c,v 1.2 2009/05/20 10:56:29 yamt Exp $	*/
 
 /*-
  * Copyright (c)2009 YAMAMOTO Takashi,
@@ -43,14 +43,18 @@
 #include <sys/cdefs.h>
 
 #if defined(_KERNEL)
-__KERNEL_RCSID(0, "$NetBSD: rpst.c,v 1.1 2009/05/19 12:39:56 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rpst.c,v 1.2 2009/05/20 10:56:29 yamt Exp $");
 #include <sys/param.h>
 #else /* defined(_KERNEL) */
-__RCSID("$NetBSD: rpst.c,v 1.1 2009/05/19 12:39:56 yamt Exp $");
+__RCSID("$NetBSD: rpst.c,v 1.2 2009/05/20 10:56:29 yamt Exp $");
 #include <assert.h>
 #include <stdbool.h>
 #include <string.h>
+#if 1
 #define	KASSERT	assert
+#else
+#define	KASSERT(a)
+#endif
 #endif /* defined(_KERNEL) */
 
 #include <sys/rpst.h>
@@ -93,6 +97,25 @@
 }
 
 /*
+ * rpst_level2mask: calculate the mask for the given level in the tree.
+ *
+ * the mask used to index root's children is level 0.
+ */
+
+static uint64_t
+rpst_level2mask(const struct rpst_tree *t, unsigned int level)
+{
+	uint64_t mask;
+
+	if (t->t_height < level) {
+		mask = 0;
+	} else {
+		mask = UINT64_C(1) << (t->t_height - level);
+	}
+	return mask;
+}
+
+/*
  * rpst_startmask: calculate the mask for the start of a search.
  * (ie. the mask for the top-most bit)
  */
@@ -100,8 +123,10 @@
 static uint64_t
 rpst_startmask(const struct rpst_tree *t)
 {
+	const uint64_t mask = rpst_level2mask(t, 0);
 
-	return UINT64_C(1) << t->t_height;
+	KASSERT((mask | (mask - 1)) == rpst_height2max(t->t_height));
+	return mask;
 }
 
 /*
@@ -156,6 +181,8 @@
 	KASSERT(*where == cur);
 	idx = (n->n_x & mask) != 0;
 	where = &cur->n_children[idx];
+	KASSERT((*where) == NULL || ((((*where)->n_x & mask) != 0) == idx));
+	KASSERT((*where) == NULL || (*where)->n_y >= cur->n_y);
 	mask >>= 1;
 	goto next;
 }
@@ -196,12 +223,15 @@
 	cur = *where;
 	KASSERT(cur != NULL);
 	if (cur == n) {
+		KASSERT(pn == NULL || pn->n_y <= n->n_y);
 		*parentp = pn;
 		return where;
 	}
 	idx = (n->n_x & mask) != 0;
 	pn = cur;
 	where = &cur->n_children[idx];
+	KASSERT((*where) == NULL || ((((*where)->n_x & mask) != 0) == idx));
+	KASSERT((*where) == NULL || (*where)->n_y >= cur->n_y);
 	mask >>= 1;
 	goto next;
 }
@@ -277,16 +307,6 @@
 	return true;
 }
 
-static uint64_t
-rpst_level2mask(const struct rpst_tree *t, unsigned int level)
-{
-
-	if (t->t_height < level) {
-		return 0;
-	}
-	return UINT64_C(1) << (t->t_height - level);
-}
-
 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)
@@ -295,12 +315,12 @@
 
 	KASSERT(min_x <= max_x);
 	n = t->t_root;
-	if (n == NULL) {
+	if (n == NULL || n->n_y > max_y) {
 		return NULL;
 	}
 	it->it_tree = t;
 	it->it_cur = n;
-	it->it_idx = 0;
+	it->it_idx = (min_x & rpst_startmask(t)) != 0;
 	it->it_level = 0;
 	it->it_max_y = max_y;
 	it->it_min_x = min_x;
@@ -308,6 +328,35 @@
 	return rpst_iterate_next(it);
 }
 
+static unsigned int
+rpst_node_on_edge_p(const struct rpst_node *n, uint64_t val, uint64_t mask)
+{
+
+	return ((n->n_x ^ val) & ((-mask) << 1)) == 0;
+}
+
+static uint64_t
+rpst_maxidx(const struct rpst_node *n, uint64_t max_x, uint64_t mask)
+{
+
+	if (rpst_node_on_edge_p(n, max_x, mask)) {
+		return (max_x & mask) != 0;
+	} else {
+		return 1;
+	}
+}
+
+static uint64_t
+rpst_minidx(const struct rpst_node *n, uint64_t min_x, uint64_t mask)
+{
+
+	if (rpst_node_on_edge_p(n, min_x, mask)) {
+		return (min_x & mask) != 0;
+	} else {
+		return 0;
+	}
+}
+
 struct rpst_node *
 rpst_iterate_next(struct rpst_iterator *it)
 {
@@ -327,11 +376,12 @@
 	idx = it->it_idx;
 	level = it->it_level;
 	mask = rpst_level2mask(t, level);
-	maxidx = (max_x & mask) != 0;
+	maxidx = rpst_maxidx(n, max_x, mask);
 	KASSERT(n == t->t_root || rpst_iterator_match_p(n, it));
 next:
 	KASSERT(mask == rpst_level2mask(t, level));
-	KASSERT(maxidx == ((max_x & mask) != 0));
+	KASSERT(idx >= rpst_minidx(n, min_x, mask));
+	KASSERT(maxidx == rpst_maxidx(n, max_x, mask));
 	KASSERT(idx <= maxidx + 2);
 	KASSERT(n != NULL);
 #if 0
@@ -361,9 +411,9 @@
 		}
 		KASSERT(level > 0);
 		level--;
-		mask = rpst_level2mask(t, level);
-		maxidx = (max_x & mask) != 0;
 		n = next;
+		mask = rpst_level2mask(t, level);
+		maxidx = rpst_maxidx(n, max_x, mask);
 		idx = where - n->n_children + 1;
 		KASSERT(idx < 2 + 1);
 		goto next;
@@ -375,11 +425,16 @@
 		idx++;
 		goto next;
 	}
+	KASSERT(next->n_y >= n->n_y);
 	level++;
 	mask >>= 1;
-	maxidx = (max_x & mask) != 0;
 	n = next;
-	idx = (min_x & mask) != 0;
+	idx = rpst_minidx(n, min_x, mask);
+	maxidx = rpst_maxidx(n, max_x, mask);
+#if 0
+	printf("%s: visit %p idx=%u level=%u mask=%llx\n",
+	    __func__, n, idx, level, mask);
+#endif
 	goto next;
 }
 
@@ -414,35 +469,92 @@
 rpst_dump_tree(const struct rpst_tree *t)
 {
 
-	printf("pst %p bits=%u\n", (const void *)t, t->t_height);
+	printf("pst %p height=%u\n", (const void *)t, t->t_height);
 	rpst_dump_node(t->t_root, 0);
 }
 
 struct testnode {
 	struct rpst_node n;
 	struct testnode *next;
+	bool failed;
+	bool found;
 };
 
+struct rpst_tree t;
+struct testnode *h = NULL;
+
+static uintmax_t
+tvdiff(const struct timeval *tv1, const struct timeval *tv2)
+{
+
+	return (uintmax_t)tv1->tv_sec * 1000000 + tv1->tv_usec -
+	    tv2->tv_sec * 1000000 - tv2->tv_usec;
+}
+
+static unsigned int
+query(uint64_t max_y, uint64_t min_x, uint64_t max_x)
+{
+	struct testnode *n;
+	struct rpst_node *rn;
+	struct rpst_iterator it;
+	struct timeval start;
+	struct timeval end;
+	unsigned int done;
+
+	printf("quering max_y=%" PRIu64 " min_x=%" PRIu64 " max_x=%" PRIu64
+	    "\n",
+	    max_y, min_x, max_x);
+	done = 0;
+	gettimeofday(&start, NULL);
+	for (rn = rpst_iterate_first(&t, max_y, min_x, max_x, &it);
+	    rn != NULL;
+	    rn = rpst_iterate_next(&it)) {
+		done++;
+#if 0
+		printf("found %p x=%" PRIu64 " y=%" PRIu64 "\n",
+		    (void *)rn, rn->n_x, rn->n_y);
+#endif
+		n = (void *)rn;
+		assert(!n->found);
+		n->found = true;
+	}
+	gettimeofday(&end, NULL);
+	printf("%u nodes found in %ju usecs\n", done,
+	    tvdiff(&end, &start));
+
+	gettimeofday(&start, NULL);
+	for (n = h; n != NULL; n = n->next) {
+		assert(n->failed ||
+		    n->found == rpst_iterator_match_p(&n->n, &it));
+		n->found = false;
+	}
+	gettimeofday(&end, NULL);
+	printf("(linear search took %ju usecs)\n", tvdiff(&end, &start));
+	return done;
+}
+
 int
 main(int argc, char *argv[])
 {
-	struct rpst_tree t;
-	struct testnode *h = NULL;
 	struct testnode *n;
-	struct rpst_node *rn;
-	unsigned int i = 500000;
+	unsigned int i;
 	struct rpst_iterator it;
 	struct timeval start;
 	struct timeval end;
+	uint64_t min_y = UINT64_MAX;
+	uint64_t max_y = 0;
+	uint64_t min_x = UINT64_MAX;
+	uint64_t max_x = 0;
+	uint64_t w;
 	unsigned int done;
+	unsigned int fail;
+	unsigned int num = 500000;
 
 	rpst_init_tree(&t);
 	rpst_dump_tree(&t);
 	assert(NULL == rpst_iterate_first(&t, UINT64_MAX, 0, UINT64_MAX, &it));
 
-	done = 0;
-	gettimeofday(&start, NULL);
-	while (i > 0) {
+	for (i = 0; i < num; i++) {
 		n = malloc(sizeof(*n));
 		if (i > 499000) {
 			n->n.n_x = 10;
@@ -454,54 +566,82 @@
 			n->n.n_x = random();
 			n->n.n_y = random();
 		}
-#if 0
-		printf("[%u] insert %p x=%" PRIu64 " y=%" PRIu64 "\n",
-		    i, n, n->n.n_x, n->n.n_y);
-#endif
-		rpst_insert_node(&t, &n->n);
+		if (n->n.n_y < min_y) {
+			min_y = n->n.n_y;
+		}
+		if (n->n.n_y > max_y) {
+			max_y = n->n.n_y;
+		}
+		if (n->n.n_x < min_x) {
+			min_x = n->n.n_x;
+		}
+		if (n->n.n_x > max_x) {
+			max_x = n->n.n_x;
+		}
+		n->found = false;
+		n->failed = false;
 		n->next = h;
 		h = n;
-		i--;
-		done++;
 	}
-	gettimeofday(&end, NULL);
-	printf("%u nodes inserted in %ju usecs\n", done,
-	    (uintmax_t)end.tv_sec * 1000000 + end.tv_usec -
-	    start.tv_sec * 1000000 - start.tv_usec);
 
 	done = 0;
+	fail = 0;
 	gettimeofday(&start, NULL);
-	for (rn = rpst_iterate_first(&t, 100000000, 10, 1000000, &it);
-	    rn != NULL;
-	    rn = rpst_iterate_next(&it)) {
-		done++;
+	for (n = h; n != NULL; n = n->next) {
+		struct rpst_node *o;
 #if 0
-		printf("found %p x=%" PRIu64 " y=%" PRIu64 "\n",
-		    (void *)rn, rn->n_x, rn->n_y);
+		printf("insert %p x=%" PRIu64 " y=%" PRIu64 "\n",
+		    n, n->n.n_x, n->n.n_y);
 #endif
+		o = rpst_insert_node(&t, &n->n);
+		if (o == NULL) {
+			done++;
+		} else {
+			n->failed = true;
+			fail++;
+		}
 	}
 	gettimeofday(&end, NULL);
-	printf("%u nodes found in %ju usecs\n", done,
-	    (uintmax_t)end.tv_sec * 1000000 + end.tv_usec -
-	    start.tv_sec * 1000000 - start.tv_usec);
+	printf("%u nodes inserted and %u insertion failed in %ju usecs\n",
+	    done, fail,
+	    tvdiff(&end, &start));
+
+	assert(min_y == 0 || 0 == query(min_y - 1, 0, UINT64_MAX));
+	assert(max_x == UINT64_MAX ||
+	    0 == query(UINT64_MAX, max_x + 1, UINT64_MAX));
+	assert(min_x == 0 || 0 == query(UINT64_MAX, 0, min_x - 1));
+
+	done = query(max_y, min_x, max_x);
+	assert(done == num - fail);
+
+	done = query(UINT64_MAX, 0, UINT64_MAX);
+	assert(done == num - fail);
+
+	w = max_x - min_x;
+	query(max_y / 2, min_x, max_x);
+	query(max_y, min_x + w / 2, max_x);
+	query(max_y / 2, min_x + w / 2, max_x);
+	query(max_y / 2, min_x, max_x - w / 2);
+	query(max_y / 2, min_x + w / 3, max_x - w / 3);
+	query(max_y - 1, min_x + 1, max_x - 1);
+	query(UINT64_MAX, 10, 10);
 
 	done = 0;
 	gettimeofday(&start, NULL);
-	while (h != NULL) {
-		n = h;
-		h = n->next;
+	for (n = h; n != NULL; n = n->next) {
+		if (n->failed) {
+			continue;
+		}
 #if 0
-		printf("[%u] remove %p x=%" PRIu64 " y=%" PRIu64 "\n",
+		printf("remove %p x=%" PRIu64 " y=%" PRIu64 "\n",
 		    n, n->n.n_x, n->n.n_y);
 #endif
 		rpst_remove_node(&t, &n->n);
-		i++;
 		done++;
 	}
 	gettimeofday(&end, NULL);
 	printf("%u nodes removed in %ju usecs\n", done,
-	    (uintmax_t)end.tv_sec * 1000000 + end.tv_usec -
-	    start.tv_sec * 1000000 - start.tv_usec);
+	    tvdiff(&end, &start));
 
 	rpst_dump_tree(&t);
 }

Reply via email to