1 /* $NetBSD: rpst.c,v 1.11 2011/04/26 20:53:34 yamt Exp $ */
4 * Copyright (c)2009 YAMAMOTO Takashi,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * radix priority search tree
34 * Vol. 14, No. 2, May 1985
35 * PRIORITY SEARCH TREES
39 * - grow tree height on-demand.
40 * - allow duplicated X values. in that case, we act as a heap.
43 #include <sys/cdefs.h>
45 #if defined(_KERNEL) || defined(_STANDALONE)
46 __KERNEL_RCSID(0, "$NetBSD: rpst.c,v 1.11 2011/04/26 20:53:34 yamt Exp $");
47 #include <sys/param.h>
48 #include <lib/libkern/libkern.h>
49 #if defined(_STANDALONE)
50 #include <lib/libsa/stand.h>
51 #endif /* defined(_STANDALONE) */
52 #else /* defined(_KERNEL) || defined(_STANDALONE) */
53 __RCSID("$NetBSD: rpst.c,v 1.11 2011/04/26 20:53:34 yamt Exp $");
58 #define KASSERT assert
62 #endif /* defined(_KERNEL) || defined(_STANDALONE) */
67 * rpst_init_tree: initialize a tree.
71 rpst_init_tree(struct rpst_tree
*t
)
79 * rpst_height2max: calculate the maximum index which can be handled by
80 * a tree with the given height.
82 * 0 ... 0x0000000000000001
83 * 1 ... 0x0000000000000003
84 * 2 ... 0x0000000000000007
85 * 3 ... 0x000000000000000f
87 * 31 ... 0x00000000ffffffff
89 * 63 ... 0xffffffffffffffff
93 rpst_height2max(unsigned int height
)
100 return (UINT64_C(1) << (height
+ 1)) - 1;
104 * rpst_level2mask: calculate the mask for the given level in the tree.
106 * the mask used to index root's children is level 0.
110 rpst_level2mask(const struct rpst_tree
*t
, unsigned int level
)
114 if (t
->t_height
< level
) {
117 mask
= UINT64_C(1) << (t
->t_height
- level
);
123 * rpst_startmask: calculate the mask for the start of a search.
124 * (ie. the mask for the top-most bit)
128 rpst_startmask(const struct rpst_tree
*t
)
130 const uint64_t mask
= rpst_level2mask(t
, 0);
132 KASSERT((mask
| (mask
- 1)) == rpst_height2max(t
->t_height
));
137 * rpst_update_parents: update n_parent of children
141 rpst_update_parents(struct rpst_node
*n
)
145 for (i
= 0; i
< 2; i
++) {
146 if (n
->n_children
[i
] != NULL
) {
147 n
->n_children
[i
]->n_parent
= n
;
153 * rpst_enlarge_tree: enlarge tree so that 'idx' can be stored
157 rpst_enlarge_tree(struct rpst_tree
*t
, uint64_t idx
)
160 while (idx
> rpst_height2max(t
->t_height
)) {
161 struct rpst_node
*n
= t
->t_root
;
164 rpst_remove_node(t
, n
);
165 memset(&n
->n_children
, 0, sizeof(n
->n_children
));
166 n
->n_children
[0] = t
->t_root
;
167 t
->t_root
->n_parent
= n
;
176 * rpst_insert_node1: a helper for rpst_insert_node.
179 static struct rpst_node
*
180 rpst_insert_node1(struct rpst_node
**where
, struct rpst_node
*n
, uint64_t mask
)
182 struct rpst_node
*parent
;
183 struct rpst_node
*cur
;
186 KASSERT((n
->n_x
& ((-mask
) << 1)) == 0);
191 n
->n_parent
= parent
;
192 memset(&n
->n_children
, 0, sizeof(n
->n_children
));
196 KASSERT(cur
->n_parent
== parent
);
197 if (n
->n_y
== cur
->n_y
&& n
->n_x
== cur
->n_x
) {
200 if (n
->n_y
< cur
->n_y
) {
203 * note that n is not in tree.
205 memcpy(n
->n_children
, cur
->n_children
, sizeof(n
->n_children
));
206 n
->n_parent
= cur
->n_parent
;
207 rpst_update_parents(n
);
212 KASSERT(*where
== cur
);
213 idx
= (n
->n_x
& mask
) != 0;
214 where
= &cur
->n_children
[idx
];
216 KASSERT((*where
) == NULL
|| ((((*where
)->n_x
& mask
) != 0) == idx
));
217 KASSERT((*where
) == NULL
|| (*where
)->n_y
>= cur
->n_y
);
223 * rpst_insert_node: insert a node into the tree.
225 * => return NULL on success.
226 * => if a duplicated node (a node with the same X,Y pair as ours) is found,
227 * return the node. in that case, the tree is intact.
231 rpst_insert_node(struct rpst_tree
*t
, struct rpst_node
*n
)
234 rpst_enlarge_tree(t
, n
->n_x
);
235 return rpst_insert_node1(&t
->t_root
, n
, rpst_startmask(t
));
239 * rpst_find_pptr: find a pointer to the given node.
241 * also, return the parent node via parentp. (NULL for the root node.)
244 static inline struct rpst_node
**
245 rpst_find_pptr(struct rpst_tree
*t
, struct rpst_node
*n
,
246 struct rpst_node
**parentp
)
248 struct rpst_node
* const parent
= n
->n_parent
;
252 if (parent
== NULL
) {
255 for (i
= 0; i
< 2 - 1; i
++) {
256 if (parent
->n_children
[i
] == n
) {
260 KASSERT(parent
->n_children
[i
] == n
);
261 return &parent
->n_children
[i
];
265 * rpst_remove_node_at: remove a node at *where.
269 rpst_remove_node_at(struct rpst_node
*parent
, struct rpst_node
**where
,
270 struct rpst_node
*cur
)
272 struct rpst_node
*tmp
[2];
273 struct rpst_node
*selected
;
274 unsigned int selected_idx
= 0; /* XXX gcc */
277 KASSERT(cur
!= NULL
);
278 KASSERT(parent
== cur
->n_parent
);
281 for (i
= 0; i
< 2; i
++) {
284 c
= cur
->n_children
[i
];
285 KASSERT(c
== NULL
|| c
->n_parent
== cur
);
286 if (selected
== NULL
|| (c
!= NULL
&& c
->n_y
< selected
->n_y
)) {
303 if (selected
== NULL
) {
307 * swap selected->n_children and cur->n_children.
309 memcpy(tmp
, selected
->n_children
, sizeof(tmp
));
310 memcpy(selected
->n_children
, cur
->n_children
, sizeof(tmp
));
311 memcpy(cur
->n_children
, tmp
, sizeof(tmp
));
312 rpst_update_parents(cur
);
313 rpst_update_parents(selected
);
314 selected
->n_parent
= parent
;
326 where
= &selected
->n_children
[selected_idx
];
338 * (*) this 'selected' will be overwritten in the next iteration.
339 * (**) cur->n_parent is bogus.
346 * rpst_remove_node: remove a node from the tree.
350 rpst_remove_node(struct rpst_tree
*t
, struct rpst_node
*n
)
352 struct rpst_node
*parent
;
353 struct rpst_node
**where
;
355 where
= rpst_find_pptr(t
, n
, &parent
);
356 rpst_remove_node_at(parent
, where
, n
);
360 rpst_iterator_match_p(const struct rpst_node
*n
, const struct rpst_iterator
*it
)
363 if (n
->n_y
> it
->it_max_y
) {
366 if (n
->n_x
< it
->it_min_x
) {
369 if (n
->n_x
> it
->it_max_x
) {
376 rpst_iterate_first(struct rpst_tree
*t
, uint64_t max_y
, uint64_t min_x
,
377 uint64_t max_x
, struct rpst_iterator
*it
)
381 KASSERT(min_x
<= max_x
);
383 if (n
== NULL
|| n
->n_y
> max_y
) {
386 if (rpst_height2max(t
->t_height
) < min_x
) {
391 it
->it_idx
= (min_x
& rpst_startmask(t
)) != 0;
393 it
->it_max_y
= max_y
;
394 it
->it_min_x
= min_x
;
395 it
->it_max_x
= max_x
;
396 return rpst_iterate_next(it
);
399 static inline unsigned int
400 rpst_node_on_edge_p(const struct rpst_node
*n
, uint64_t val
, uint64_t mask
)
403 return ((n
->n_x
^ val
) & ((-mask
) << 1)) == 0;
406 static inline uint64_t
407 rpst_maxidx(const struct rpst_node
*n
, uint64_t max_x
, uint64_t mask
)
410 if (rpst_node_on_edge_p(n
, max_x
, mask
)) {
411 return (max_x
& mask
) != 0;
417 static inline uint64_t
418 rpst_minidx(const struct rpst_node
*n
, uint64_t min_x
, uint64_t mask
)
421 if (rpst_node_on_edge_p(n
, min_x
, mask
)) {
422 return (min_x
& mask
) != 0;
429 rpst_iterate_next(struct rpst_iterator
*it
)
433 struct rpst_node
*next
;
434 const uint64_t max_y
= it
->it_max_y
;
435 const uint64_t min_x
= it
->it_min_x
;
436 const uint64_t max_x
= it
->it_max_x
;
445 level
= it
->it_level
;
446 mask
= rpst_level2mask(t
, level
);
447 maxidx
= rpst_maxidx(n
, max_x
, mask
);
448 KASSERT(n
== t
->t_root
|| rpst_iterator_match_p(n
, it
));
450 KASSERT(mask
== rpst_level2mask(t
, level
));
451 KASSERT(idx
>= rpst_minidx(n
, min_x
, mask
));
452 KASSERT(maxidx
== rpst_maxidx(n
, max_x
, mask
));
453 KASSERT(idx
<= maxidx
+ 2);
456 printf("%s: cur=%p, idx=%u maxidx=%u level=%u mask=%" PRIx64
"\n",
457 __func__
, (void *)n
, idx
, maxidx
, level
, mask
);
459 if (idx
== maxidx
+ 1) { /* visit the current node */
461 if (min_x
<= n
->n_x
&& n
->n_x
<= max_x
) {
464 it
->it_level
= level
;
465 KASSERT(rpst_iterator_match_p(n
, it
));
466 return n
; /* report */
469 } else if (idx
== maxidx
+ 2) { /* back to the parent */
470 struct rpst_node
**where
;
472 where
= rpst_find_pptr(t
, n
, &next
);
475 KASSERT(t
->t_root
== n
);
476 KASSERT(&t
->t_root
== where
);
477 return NULL
; /* done */
482 mask
= rpst_level2mask(t
, level
);
483 maxidx
= rpst_maxidx(n
, max_x
, mask
);
484 idx
= where
- n
->n_children
+ 1;
485 KASSERT(idx
< 2 + 1);
490 next
= n
->n_children
[idx
];
491 if (next
== NULL
|| next
->n_y
> max_y
) {
495 KASSERT(next
->n_parent
== n
);
496 KASSERT(next
->n_y
>= n
->n_y
);
500 idx
= rpst_minidx(n
, min_x
, mask
);
501 maxidx
= rpst_maxidx(n
, max_x
, mask
);
503 printf("%s: visit %p idx=%u level=%u mask=%llx\n",
504 __func__
, n
, idx
, level
, mask
);
509 #if defined(UNITTEST)
510 #include <sys/time.h>
512 #include <inttypes.h>
517 rpst_dump_node(const struct rpst_node
*n
, unsigned int depth
)
521 for (i
= 0; i
< depth
; i
++) {
524 printf("[%u]", depth
);
529 printf("%p x=%" PRIx64
"(%" PRIu64
") y=%" PRIx64
"(%" PRIu64
")\n",
530 (const void *)n
, n
->n_x
, n
->n_x
, n
->n_y
, n
->n_y
);
531 for (i
= 0; i
< 2; i
++) {
532 rpst_dump_node(n
->n_children
[i
], depth
+ 1);
537 rpst_dump_tree(const struct rpst_tree
*t
)
540 printf("pst %p height=%u\n", (const void *)t
, t
->t_height
);
541 rpst_dump_node(t
->t_root
, 0);
546 struct testnode
*next
;
552 struct testnode
*h
= NULL
;
555 tvdiff(const struct timeval
*tv1
, const struct timeval
*tv2
)
558 return (uintmax_t)tv1
->tv_sec
* 1000000 + tv1
->tv_usec
-
559 tv2
->tv_sec
* 1000000 - tv2
->tv_usec
;
563 query(uint64_t max_y
, uint64_t min_x
, uint64_t max_x
)
566 struct rpst_node
*rn
;
567 struct rpst_iterator it
;
568 struct timeval start
;
572 printf("quering max_y=%" PRIu64
" min_x=%" PRIu64
" max_x=%" PRIu64
574 max_y
, min_x
, max_x
);
576 gettimeofday(&start
, NULL
);
577 for (rn
= rpst_iterate_first(&t
, max_y
, min_x
, max_x
, &it
);
579 rn
= rpst_iterate_next(&it
)) {
582 printf("found %p x=%" PRIu64
" y=%" PRIu64
"\n",
583 (void *)rn
, rn
->n_x
, rn
->n_y
);
589 gettimeofday(&end
, NULL
);
590 printf("%u nodes found in %ju usecs\n", done
,
591 tvdiff(&end
, &start
));
593 gettimeofday(&start
, NULL
);
594 for (n
= h
; n
!= NULL
; n
= n
->next
) {
596 n
->found
== rpst_iterator_match_p(&n
->n
, &it
));
599 gettimeofday(&end
, NULL
);
600 printf("(linear search took %ju usecs)\n", tvdiff(&end
, &start
));
605 main(int argc
, char *argv
[])
609 struct rpst_iterator it
;
610 struct timeval start
;
612 uint64_t min_y
= UINT64_MAX
;
614 uint64_t min_x
= UINT64_MAX
;
619 unsigned int num
= 500000;
623 assert(NULL
== rpst_iterate_first(&t
, UINT64_MAX
, 0, UINT64_MAX
, &it
));
625 for (i
= 0; i
< num
; i
++) {
626 n
= malloc(sizeof(*n
));
630 } else if (i
> 400000) {
637 if (n
->n
.n_y
< min_y
) {
640 if (n
->n
.n_y
> max_y
) {
643 if (n
->n
.n_x
< min_x
) {
646 if (n
->n
.n_x
> max_x
) {
657 gettimeofday(&start
, NULL
);
658 for (n
= h
; n
!= NULL
; n
= n
->next
) {
661 printf("insert %p x=%" PRIu64
" y=%" PRIu64
"\n",
662 n
, n
->n
.n_x
, n
->n
.n_y
);
664 o
= rpst_insert_node(&t
, &n
->n
);
672 gettimeofday(&end
, NULL
);
673 printf("%u nodes inserted and %u insertion failed in %ju usecs\n",
675 tvdiff(&end
, &start
));
677 assert(min_y
== 0 || 0 == query(min_y
- 1, 0, UINT64_MAX
));
678 assert(max_x
== UINT64_MAX
||
679 0 == query(UINT64_MAX
, max_x
+ 1, UINT64_MAX
));
680 assert(min_x
== 0 || 0 == query(UINT64_MAX
, 0, min_x
- 1));
682 done
= query(max_y
, min_x
, max_x
);
683 assert(done
== num
- fail
);
685 done
= query(UINT64_MAX
, 0, UINT64_MAX
);
686 assert(done
== num
- fail
);
689 query(max_y
/ 2, min_x
, max_x
);
690 query(max_y
, min_x
+ w
/ 2, max_x
);
691 query(max_y
/ 2, min_x
+ w
/ 2, max_x
);
692 query(max_y
/ 2, min_x
, max_x
- w
/ 2);
693 query(max_y
/ 2, min_x
+ w
/ 3, max_x
- w
/ 3);
694 query(max_y
- 1, min_x
+ 1, max_x
- 1);
695 query(UINT64_MAX
, 10, 10);
698 gettimeofday(&start
, NULL
);
699 for (n
= h
; n
!= NULL
; n
= n
->next
) {
704 printf("remove %p x=%" PRIu64
" y=%" PRIu64
"\n",
705 n
, n
->n
.n_x
, n
->n
.n_y
);
707 rpst_remove_node(&t
, &n
->n
);
710 gettimeofday(&end
, NULL
);
711 printf("%u nodes removed in %ju usecs\n", done
,
712 tvdiff(&end
, &start
));
716 #endif /* defined(UNITTEST) */