xref: /netbsd-src/common/lib/libc/gen/ptree.c (revision 1ab7ad13137bc552bdd37a2505f298a5824ffe18)
1*1ab7ad13Schristos /*	$NetBSD: ptree.c,v 1.13 2024/01/20 14:55:02 christos Exp $	*/
20ad72818Smatt 
30ad72818Smatt /*-
40ad72818Smatt  * Copyright (c) 2008 The NetBSD Foundation, Inc.
50ad72818Smatt  * All rights reserved.
60ad72818Smatt  *
70ad72818Smatt  * This code is derived from software contributed to The NetBSD Foundation
80ad72818Smatt  * by Matt Thomas <matt@3am-software.com>.
90ad72818Smatt  *
100ad72818Smatt  * Redistribution and use in source and binary forms, with or without
110ad72818Smatt  * modification, are permitted provided that the following conditions
120ad72818Smatt  * are met:
130ad72818Smatt  * 1. Redistributions of source code must retain the above copyright
140ad72818Smatt  *    notice, this list of conditions and the following disclaimer.
150ad72818Smatt  * 2. Redistributions in binary form must reproduce the above copyright
160ad72818Smatt  *    notice, this list of conditions and the following disclaimer in the
170ad72818Smatt  *    documentation and/or other materials provided with the distribution.
180ad72818Smatt  *
190ad72818Smatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
200ad72818Smatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
210ad72818Smatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220ad72818Smatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
230ad72818Smatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
240ad72818Smatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
250ad72818Smatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
260ad72818Smatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
270ad72818Smatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
280ad72818Smatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
290ad72818Smatt  * POSSIBILITY OF SUCH DAMAGE.
300ad72818Smatt  */
310ad72818Smatt 
320ad72818Smatt #define _PT_PRIVATE
330ad72818Smatt 
340ad72818Smatt #if defined(PTCHECK) && !defined(PTDEBUG)
350ad72818Smatt #define PTDEBUG
360ad72818Smatt #endif
370ad72818Smatt 
380ad72818Smatt #if defined(_KERNEL) || defined(_STANDALONE)
390ad72818Smatt #include <sys/param.h>
400ad72818Smatt #include <sys/types.h>
410ad72818Smatt #include <sys/systm.h>
42e971cab0Sjnemeth #include <lib/libkern/libkern.h>
43*1ab7ad13Schristos __KERNEL_RCSID(0, "$NetBSD: ptree.c,v 1.13 2024/01/20 14:55:02 christos Exp $");
440ad72818Smatt #else
450ad72818Smatt #include <stddef.h>
460ad72818Smatt #include <stdint.h>
470ad72818Smatt #include <limits.h>
480ad72818Smatt #include <stdbool.h>
490ad72818Smatt #include <string.h>
500ad72818Smatt #ifdef PTDEBUG
510ad72818Smatt #include <assert.h>
520ad72818Smatt #define	KASSERT(e)	assert(e)
530ad72818Smatt #else
542e0e5732Srillig #define	KASSERT(e)	do { } while (0)
550ad72818Smatt #endif
56*1ab7ad13Schristos __RCSID("$NetBSD: ptree.c,v 1.13 2024/01/20 14:55:02 christos Exp $");
570ad72818Smatt #endif /* _KERNEL || _STANDALONE */
580ad72818Smatt 
590ad72818Smatt #ifdef _LIBC
600ad72818Smatt #include "namespace.h"
610ad72818Smatt #endif
620ad72818Smatt 
630ad72818Smatt #ifdef PTTEST
640ad72818Smatt #include "ptree.h"
650ad72818Smatt #else
660ad72818Smatt #include <sys/ptree.h>
670ad72818Smatt #endif
680ad72818Smatt 
690ad72818Smatt /*
700ad72818Smatt  * This is an implementation of a radix / PATRICIA tree.  As in a traditional
710ad72818Smatt  * patricia tree, all the data is at the leaves of the tree.  An N-value
720ad72818Smatt  * tree would have N leaves, N-1 branching nodes, and a root pointer.  Each
730ad72818Smatt  * branching node would have left(0) and right(1) pointers that either point
740ad72818Smatt  * to another branching node or a leaf node.  The root pointer would also
750ad72818Smatt  * point to either the first branching node or a leaf node.  Leaf nodes
760ad72818Smatt  * have no need for pointers.
770ad72818Smatt  *
780ad72818Smatt  * However, allocation for these branching nodes is problematic since the
790ad72818Smatt  * allocation could fail.  This would cause insertions to fail for reasons
804c826f22Srmind  * beyond the user's control.  So to prevent this, in this implementation
810ad72818Smatt  * each node has two identities: its leaf identity and its branch identity.
820ad72818Smatt  * Each is separate from the other.  Every branch is tagged as to whether
830ad72818Smatt  * it points to a leaf or a branch.  This is not an attribute of the object
840ad72818Smatt  * but of the pointer to the object.  The low bit of the pointer is used as
85303f5b9eSyamt  * the tag to determine whether it points to a leaf or branch identity, with
860ad72818Smatt  * branch identities having the low bit set.
870ad72818Smatt  *
880ad72818Smatt  * A node's branch identity has one rule: when traversing the tree from the
890ad72818Smatt  * root to the node's leaf identity, one of the branches traversed will be via
900ad72818Smatt  * the node's branch identity.  Of course, that has an exception: since to
910ad72818Smatt  * store N leaves, you need N-1 branches.  That one node whose branch identity
920ad72818Smatt  * isn't used is stored as "oddman"-out in the root.
930ad72818Smatt  *
940ad72818Smatt  * Branching nodes also has a bit offset and a bit length which determines
950ad72818Smatt  * which branch slot is used.  The bit length can be zero resulting in a
964c826f22Srmind  * one-way branch.  This happens in two special cases: the root and
970ad72818Smatt  * interior mask nodes.
980ad72818Smatt  *
990ad72818Smatt  * To support longest match first lookups, when a mask node (one that only
1000ad72818Smatt  * match the first N bits) has children who first N bits match the mask nodes,
1010ad72818Smatt  * that mask node is converted from being a leaf node to being a one-way
1020ad72818Smatt  * branch-node.  The mask becomes fixed in position in the tree.  The mask
103303f5b9eSyamt  * will always be the longest mask match for its descendants (unless they
1040ad72818Smatt  * traverse an even longer match).
1050ad72818Smatt  */
1060ad72818Smatt 
1070ad72818Smatt #define	NODETOITEM(pt, ptn)	\
1080ad72818Smatt 	((void *)((uintptr_t)(ptn) - (pt)->pt_node_offset))
1090ad72818Smatt #define	NODETOKEY(pt, ptn)	\
1100ad72818Smatt 	((void *)((uintptr_t)(ptn) - (pt)->pt_node_offset + pt->pt_key_offset))
1110ad72818Smatt #define	ITEMTONODE(pt, ptn)	\
1120ad72818Smatt 	((pt_node_t *)((uintptr_t)(ptn) + (pt)->pt_node_offset))
1130ad72818Smatt 
1140ad72818Smatt #if PTCHECK > 1
1150ad72818Smatt #define	PTREE_CHECK(pt)		ptree_check(pt)
1160ad72818Smatt #else
1172e0e5732Srillig #define	PTREE_CHECK(pt)		do { } while (0)
1180ad72818Smatt #endif
1190ad72818Smatt 
1200ad72818Smatt static inline bool
ptree_matchnode(const pt_tree_t * pt,const pt_node_t * target,const pt_node_t * ptn,pt_bitoff_t max_bitoff,pt_bitoff_t * bitoff_p,pt_slot_t * slots_p)1210ad72818Smatt ptree_matchnode(const pt_tree_t *pt, const pt_node_t *target,
1220ad72818Smatt 	const pt_node_t *ptn, pt_bitoff_t max_bitoff,
1230ad72818Smatt 	pt_bitoff_t *bitoff_p, pt_slot_t *slots_p)
1240ad72818Smatt {
1250ad72818Smatt 	return (*pt->pt_ops->ptto_matchnode)(NODETOKEY(pt, target),
12661498e07Srmind 	    (ptn != NULL ? NODETOKEY(pt, ptn) : NULL),
12761498e07Srmind 	    max_bitoff, bitoff_p, slots_p, pt->pt_context);
1280ad72818Smatt }
1290ad72818Smatt 
1300ad72818Smatt static inline pt_slot_t
ptree_testnode(const pt_tree_t * pt,const pt_node_t * target,const pt_node_t * ptn)1310ad72818Smatt ptree_testnode(const pt_tree_t *pt, const pt_node_t *target,
1320ad72818Smatt 	const pt_node_t *ptn)
1330ad72818Smatt {
1340ad72818Smatt 	const pt_bitlen_t bitlen = PTN_BRANCH_BITLEN(ptn);
1350ad72818Smatt 	if (bitlen == 0)
13687ed7965Smatt 		return PT_SLOT_ROOT;	/* mask or root, doesn't matter */
1370ad72818Smatt 	return (*pt->pt_ops->ptto_testnode)(NODETOKEY(pt, target),
13861498e07Srmind 	    PTN_BRANCH_BITOFF(ptn), bitlen, pt->pt_context);
1390ad72818Smatt }
1400ad72818Smatt 
1410ad72818Smatt static inline bool
ptree_matchkey(const pt_tree_t * pt,const void * key,const pt_node_t * ptn,pt_bitoff_t bitoff,pt_bitlen_t bitlen)1420ad72818Smatt ptree_matchkey(const pt_tree_t *pt, const void *key,
1430ad72818Smatt 	const pt_node_t *ptn, pt_bitoff_t bitoff, pt_bitlen_t bitlen)
1440ad72818Smatt {
1450ad72818Smatt 	return (*pt->pt_ops->ptto_matchkey)(key, NODETOKEY(pt, ptn),
14661498e07Srmind 	    bitoff, bitlen, pt->pt_context);
1470ad72818Smatt }
1480ad72818Smatt 
1490ad72818Smatt static inline pt_slot_t
ptree_testkey(const pt_tree_t * pt,const void * key,const pt_node_t * ptn)1500ad72818Smatt ptree_testkey(const pt_tree_t *pt, const void *key, const pt_node_t *ptn)
1510ad72818Smatt {
15287ed7965Smatt 	const pt_bitlen_t bitlen = PTN_BRANCH_BITLEN(ptn);
15387ed7965Smatt 	if (bitlen == 0)
15487ed7965Smatt 		return PT_SLOT_ROOT;	/* mask or root, doesn't matter */
15561498e07Srmind 	return (*pt->pt_ops->ptto_testkey)(key, PTN_BRANCH_BITOFF(ptn),
15661498e07Srmind 	    PTN_BRANCH_BITLEN(ptn), pt->pt_context);
1570ad72818Smatt }
1580ad72818Smatt 
1590ad72818Smatt static inline void
ptree_set_position(uintptr_t node,pt_slot_t position)1600ad72818Smatt ptree_set_position(uintptr_t node, pt_slot_t position)
1610ad72818Smatt {
1620ad72818Smatt 	if (PT_LEAF_P(node))
1630ad72818Smatt 		PTN_SET_LEAF_POSITION(PT_NODE(node), position);
1640ad72818Smatt 	else
1650ad72818Smatt 		PTN_SET_BRANCH_POSITION(PT_NODE(node), position);
1660ad72818Smatt }
1670ad72818Smatt 
1680ad72818Smatt void
ptree_init(pt_tree_t * pt,const pt_tree_ops_t * ops,void * context,size_t node_offset,size_t key_offset)16961498e07Srmind ptree_init(pt_tree_t *pt, const pt_tree_ops_t *ops, void *context,
17061498e07Srmind 	size_t node_offset, size_t key_offset)
1710ad72818Smatt {
1720ad72818Smatt 	memset(pt, 0, sizeof(*pt));
1730ad72818Smatt 	pt->pt_node_offset = node_offset;
1740ad72818Smatt 	pt->pt_key_offset = key_offset;
17561498e07Srmind 	pt->pt_context = context;
1760ad72818Smatt 	pt->pt_ops = ops;
1770ad72818Smatt }
1780ad72818Smatt 
1790ad72818Smatt typedef struct {
1800ad72818Smatt 	uintptr_t *id_insertp;
1810ad72818Smatt 	pt_node_t *id_parent;
1820ad72818Smatt 	uintptr_t id_node;
1830ad72818Smatt 	pt_slot_t id_parent_slot;
1840ad72818Smatt 	pt_bitoff_t id_bitoff;
1850ad72818Smatt 	pt_slot_t id_slot;
1860ad72818Smatt } pt_insertdata_t;
1870ad72818Smatt 
1880ad72818Smatt typedef bool (*pt_insertfunc_t)(pt_tree_t *, pt_node_t *, pt_insertdata_t *);
1890ad72818Smatt 
1900ad72818Smatt /*
1910ad72818Smatt  * Move a branch identify from src to dst.  The leaves don't care since
1920ad72818Smatt  * nothing for them has changed.
1930ad72818Smatt  */
1944de7478cSmatt /*ARGSUSED*/
1950ad72818Smatt static uintptr_t
ptree_move_branch(pt_tree_t * const pt,pt_node_t * const dst,const pt_node_t * const src)1960ad72818Smatt ptree_move_branch(pt_tree_t * const pt, pt_node_t * const dst,
1970ad72818Smatt 	const pt_node_t * const src)
1980ad72818Smatt {
1990ad72818Smatt 	KASSERT(PTN_BRANCH_BITLEN(src) == 1);
2000ad72818Smatt 	/* set branch bitlen and bitoff in one step.  */
2010ad72818Smatt 	dst->ptn_branchdata = src->ptn_branchdata;
2020ad72818Smatt 	PTN_SET_BRANCH_POSITION(dst, PTN_BRANCH_POSITION(src));
2030ad72818Smatt 	PTN_COPY_BRANCH_SLOTS(dst, src);
2040ad72818Smatt 	return PTN_BRANCH(dst);
2050ad72818Smatt }
2060ad72818Smatt 
2070ad72818Smatt #ifndef PTNOMASK
2080ad72818Smatt static inline uintptr_t *
ptree_find_branch(pt_tree_t * const pt,uintptr_t branch_node)2090ad72818Smatt ptree_find_branch(pt_tree_t * const pt, uintptr_t branch_node)
2100ad72818Smatt {
2110ad72818Smatt 	pt_node_t * const branch = PT_NODE(branch_node);
2120ad72818Smatt 	pt_node_t *parent;
2130ad72818Smatt 
2140ad72818Smatt 	for (parent = &pt->pt_rootnode;;) {
2150ad72818Smatt 		uintptr_t *nodep =
2160ad72818Smatt 		    &PTN_BRANCH_SLOT(parent, ptree_testnode(pt, branch, parent));
2170ad72818Smatt 		if (*nodep == branch_node)
2180ad72818Smatt 			return nodep;
2190ad72818Smatt 		if (PT_LEAF_P(*nodep))
2200ad72818Smatt 			return NULL;
2210ad72818Smatt 		parent = PT_NODE(*nodep);
2220ad72818Smatt 	}
2230ad72818Smatt }
2240ad72818Smatt 
2250ad72818Smatt static bool
ptree_insert_leaf_after_mask(pt_tree_t * const pt,pt_node_t * const target,pt_insertdata_t * const id)2260ad72818Smatt ptree_insert_leaf_after_mask(pt_tree_t * const pt, pt_node_t * const target,
2270ad72818Smatt 	pt_insertdata_t * const id)
2280ad72818Smatt {
2290ad72818Smatt 	const uintptr_t target_node = PTN_LEAF(target);
2300ad72818Smatt 	const uintptr_t mask_node = id->id_node;
2310ad72818Smatt 	pt_node_t * const mask = PT_NODE(mask_node);
2320ad72818Smatt 	const pt_bitlen_t mask_len = PTN_MASK_BITLEN(mask);
2330ad72818Smatt 
2340ad72818Smatt 	KASSERT(PT_LEAF_P(mask_node));
2350ad72818Smatt 	KASSERT(PTN_LEAF_POSITION(mask) == id->id_parent_slot);
2360ad72818Smatt 	KASSERT(mask_len <= id->id_bitoff);
2370ad72818Smatt 	KASSERT(PTN_ISMASK_P(mask));
2380ad72818Smatt 	KASSERT(!PTN_ISMASK_P(target) || mask_len < PTN_MASK_BITLEN(target));
2390ad72818Smatt 
2400ad72818Smatt 	if (mask_node == PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode)) {
2410ad72818Smatt 		KASSERT(id->id_parent != mask);
2420ad72818Smatt 		/*
2430ad72818Smatt 		 * Nice, mask was an oddman.  So just set the oddman to target.
2440ad72818Smatt 		 */
2450ad72818Smatt 		PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode) = target_node;
2460ad72818Smatt 	} else {
2470ad72818Smatt 		/*
2480ad72818Smatt 		 * We need to find out who's pointing to mask's branch
2490ad72818Smatt 		 * identity.  We know that between root and the leaf identity,
2500ad72818Smatt 		 * we must traverse the node's branch identity.
2510ad72818Smatt 		 */
2520ad72818Smatt 		uintptr_t * const mask_nodep = ptree_find_branch(pt, PTN_BRANCH(mask));
2530ad72818Smatt 		KASSERT(mask_nodep != NULL);
2540ad72818Smatt 		KASSERT(*mask_nodep == PTN_BRANCH(mask));
2550ad72818Smatt 		KASSERT(PTN_BRANCH_BITLEN(mask) == 1);
2560ad72818Smatt 
2570ad72818Smatt 		/*
2580ad72818Smatt 		 * Alas, mask was used as a branch.  Since the mask is becoming
2590ad72818Smatt 		 * a one-way branch, we need make target take over mask's
2600ad72818Smatt 		 * branching responsibilities.  Only then can we change it.
2610ad72818Smatt 		 */
2620ad72818Smatt 		*mask_nodep = ptree_move_branch(pt, target, mask);
2630ad72818Smatt 
2640ad72818Smatt 		/*
2650ad72818Smatt 		 * However, it's possible that mask's parent is itself.  If
2660ad72818Smatt 		 * that's true, update the insert point to use target since it
2670ad72818Smatt 		 * has taken over mask's branching duties.
2680ad72818Smatt 		 */
2690ad72818Smatt 		if (id->id_parent == mask)
2700ad72818Smatt 			id->id_insertp = &PTN_BRANCH_SLOT(target,
2710ad72818Smatt 			    id->id_parent_slot);
2720ad72818Smatt 	}
2730ad72818Smatt 
2740ad72818Smatt 	PTN_SET_BRANCH_BITLEN(mask, 0);
2750ad72818Smatt 	PTN_SET_BRANCH_BITOFF(mask, mask_len);
2760ad72818Smatt 
2770ad72818Smatt 	PTN_BRANCH_ROOT_SLOT(mask) = target_node;
2780ad72818Smatt 	PTN_BRANCH_ODDMAN_SLOT(mask) = PT_NULL;
2790ad72818Smatt 	PTN_SET_LEAF_POSITION(target, PT_SLOT_ROOT);
2800ad72818Smatt 	PTN_SET_BRANCH_POSITION(mask, id->id_parent_slot);
2810ad72818Smatt 
2820ad72818Smatt 	/*
2830ad72818Smatt 	 * Now that everything is done, to make target visible we need to
2840ad72818Smatt 	 * change mask from a leaf to a branch.
2850ad72818Smatt 	 */
2860ad72818Smatt 	*id->id_insertp = PTN_BRANCH(mask);
2870ad72818Smatt 	PTREE_CHECK(pt);
2880ad72818Smatt 	return true;
2890ad72818Smatt }
2900ad72818Smatt 
2914de7478cSmatt /*ARGSUSED*/
2920ad72818Smatt static bool
ptree_insert_mask_before_node(pt_tree_t * const pt,pt_node_t * const target,pt_insertdata_t * const id)2930ad72818Smatt ptree_insert_mask_before_node(pt_tree_t * const pt, pt_node_t * const target,
2940ad72818Smatt 	pt_insertdata_t * const id)
2950ad72818Smatt {
2960ad72818Smatt 	const uintptr_t node = id->id_node;
2970ad72818Smatt 	pt_node_t * const ptn = PT_NODE(node);
2980ad72818Smatt 	const pt_slot_t mask_len = PTN_MASK_BITLEN(target);
2990ad72818Smatt 	const pt_bitlen_t node_mask_len = PTN_MASK_BITLEN(ptn);
3000ad72818Smatt 
3010ad72818Smatt 	KASSERT(PT_LEAF_P(node) || id->id_parent_slot == PTN_BRANCH_POSITION(ptn));
3020ad72818Smatt 	KASSERT(PT_BRANCH_P(node) || id->id_parent_slot == PTN_LEAF_POSITION(ptn));
3030ad72818Smatt 	KASSERT(PTN_ISMASK_P(target));
3040ad72818Smatt 
3050ad72818Smatt 	/*
3060ad72818Smatt 	 * If the node we are placing ourself in front is a mask with the
3070ad72818Smatt 	 * same mask length as us, return failure.
3080ad72818Smatt 	 */
3090ad72818Smatt 	if (PTN_ISMASK_P(ptn) && node_mask_len == mask_len)
3100ad72818Smatt 		return false;
3110ad72818Smatt 
3120ad72818Smatt 	PTN_SET_BRANCH_BITLEN(target, 0);
3130ad72818Smatt 	PTN_SET_BRANCH_BITOFF(target, mask_len);
3140ad72818Smatt 
3150ad72818Smatt 	PTN_BRANCH_SLOT(target, PT_SLOT_ROOT) = node;
3160ad72818Smatt 	*id->id_insertp = PTN_BRANCH(target);
3170ad72818Smatt 
3180ad72818Smatt 	PTN_SET_BRANCH_POSITION(target, id->id_parent_slot);
3190ad72818Smatt 	ptree_set_position(node, PT_SLOT_ROOT);
3200ad72818Smatt 
3210ad72818Smatt 	PTREE_CHECK(pt);
3220ad72818Smatt 	return true;
3230ad72818Smatt }
3240ad72818Smatt #endif /* !PTNOMASK */
3250ad72818Smatt 
3264de7478cSmatt /*ARGSUSED*/
3270ad72818Smatt static bool
ptree_insert_branch_at_node(pt_tree_t * const pt,pt_node_t * const target,pt_insertdata_t * const id)3280ad72818Smatt ptree_insert_branch_at_node(pt_tree_t * const pt, pt_node_t * const target,
3290ad72818Smatt 	pt_insertdata_t * const id)
3300ad72818Smatt {
3310ad72818Smatt 	const uintptr_t target_node = PTN_LEAF(target);
3320ad72818Smatt 	const uintptr_t node = id->id_node;
3330ad72818Smatt 	const pt_slot_t other_slot = id->id_slot ^ PT_SLOT_OTHER;
3340ad72818Smatt 
3350ad72818Smatt 	KASSERT(PT_BRANCH_P(node) || id->id_parent_slot == PTN_LEAF_POSITION(PT_NODE(node)));
3360ad72818Smatt 	KASSERT(PT_LEAF_P(node) || id->id_parent_slot == PTN_BRANCH_POSITION(PT_NODE(node)));
3370ad72818Smatt 	KASSERT((node == pt->pt_root) == (id->id_parent == &pt->pt_rootnode));
3380ad72818Smatt #ifndef PTNOMASK
3390ad72818Smatt 	KASSERT(!PTN_ISMASK_P(target) || id->id_bitoff <= PTN_MASK_BITLEN(target));
3400ad72818Smatt #endif
3410ad72818Smatt 	KASSERT(node == pt->pt_root || PTN_BRANCH_BITOFF(id->id_parent) + PTN_BRANCH_BITLEN(id->id_parent) <= id->id_bitoff);
3420ad72818Smatt 
3430ad72818Smatt 	PTN_SET_BRANCH_BITOFF(target, id->id_bitoff);
3440ad72818Smatt 	PTN_SET_BRANCH_BITLEN(target, 1);
3450ad72818Smatt 
3460ad72818Smatt 	PTN_BRANCH_SLOT(target, id->id_slot) = target_node;
3470ad72818Smatt 	PTN_BRANCH_SLOT(target, other_slot) = node;
3480ad72818Smatt 	*id->id_insertp = PTN_BRANCH(target);
3490ad72818Smatt 
3500ad72818Smatt 	PTN_SET_LEAF_POSITION(target, id->id_slot);
3510ad72818Smatt 	ptree_set_position(node, other_slot);
3520ad72818Smatt 
3530ad72818Smatt 	PTN_SET_BRANCH_POSITION(target, id->id_parent_slot);
3540ad72818Smatt 	PTREE_CHECK(pt);
3550ad72818Smatt 	return true;
3560ad72818Smatt }
3570ad72818Smatt 
3580ad72818Smatt static bool
ptree_insert_leaf(pt_tree_t * const pt,pt_node_t * const target,pt_insertdata_t * const id)3590ad72818Smatt ptree_insert_leaf(pt_tree_t * const pt, pt_node_t * const target,
3600ad72818Smatt 	pt_insertdata_t * const id)
3610ad72818Smatt {
3620ad72818Smatt 	const uintptr_t leaf_node = id->id_node;
3630ad72818Smatt 	pt_node_t * const leaf = PT_NODE(leaf_node);
3640ad72818Smatt #ifdef PTNOMASK
3650ad72818Smatt 	const bool inserting_mask = false;
3660ad72818Smatt 	const bool at_mask = false;
3670ad72818Smatt #else
3680ad72818Smatt 	const bool inserting_mask = PTN_ISMASK_P(target);
3690ad72818Smatt 	const bool at_mask = PTN_ISMASK_P(leaf);
3700ad72818Smatt 	const pt_bitlen_t leaf_masklen = PTN_MASK_BITLEN(leaf);
3710ad72818Smatt 	const pt_bitlen_t target_masklen = PTN_MASK_BITLEN(target);
3720ad72818Smatt #endif
3730ad72818Smatt 	pt_insertfunc_t insertfunc = ptree_insert_branch_at_node;
3740ad72818Smatt 	bool matched;
3750ad72818Smatt 
3760ad72818Smatt 	/*
3770ad72818Smatt 	 * In all likelyhood we are going simply going to insert a branch
3780ad72818Smatt 	 * where this leaf is which will point to the old and new leaves.
3790ad72818Smatt 	 */
3800ad72818Smatt 	KASSERT(PT_LEAF_P(leaf_node));
3810ad72818Smatt 	KASSERT(PTN_LEAF_POSITION(leaf) == id->id_parent_slot);
3820ad72818Smatt 	matched = ptree_matchnode(pt, target, leaf, UINT_MAX,
3830ad72818Smatt 	    &id->id_bitoff, &id->id_slot);
3840ad72818Smatt 	if (__predict_false(!inserting_mask)) {
3850ad72818Smatt 		/*
3860ad72818Smatt 		 * We aren't inserting a mask nor is the leaf a mask, which
3870ad72818Smatt 		 * means we are trying to insert a duplicate leaf.  Can't do
3880ad72818Smatt 		 * that.
3890ad72818Smatt 		 */
3900ad72818Smatt 		if (!at_mask && matched)
3910ad72818Smatt 			return false;
3920ad72818Smatt 
3930ad72818Smatt #ifndef PTNOMASK
3940ad72818Smatt 		/*
3950ad72818Smatt 		 * We are at a mask and the leaf we are about to insert
3960ad72818Smatt 		 * is at or beyond the mask, we need to convert the mask
3970ad72818Smatt 		 * from a leaf to a one-way branch interior mask.
3980ad72818Smatt 		 */
3990ad72818Smatt 		if (at_mask && id->id_bitoff >= leaf_masklen)
4000ad72818Smatt 			insertfunc = ptree_insert_leaf_after_mask;
4010ad72818Smatt #endif /* PTNOMASK */
4020ad72818Smatt 	}
4030ad72818Smatt #ifndef PTNOMASK
4040ad72818Smatt 	else {
4050ad72818Smatt 		/*
4060ad72818Smatt 		 * We are inserting a mask.
4070ad72818Smatt 		 */
4080ad72818Smatt 		if (matched) {
4090ad72818Smatt 			/*
4100ad72818Smatt 			 * If the leaf isn't a mask, we obviously have to
4110ad72818Smatt 			 * insert the new mask before non-mask leaf.  If the
4120ad72818Smatt 			 * leaf is a mask, and the new node has a LEQ mask
4130ad72818Smatt 			 * length it too needs to inserted before leaf (*).
4140ad72818Smatt 			 *
4150ad72818Smatt 			 * In other cases, we place the new mask as leaf after
4160ad72818Smatt 			 * leaf mask.  Which mask comes first will be a one-way
4170ad72818Smatt 			 * branch interior mask node which has the other mask
4180ad72818Smatt 			 * node as a child.
4190ad72818Smatt 			 *
4200ad72818Smatt 			 * (*) ptree_insert_mask_before_node can detect a
4210ad72818Smatt 			 * duplicate mask and return failure if needed.
4220ad72818Smatt 			 */
4230ad72818Smatt 			if (!at_mask || target_masklen <= leaf_masklen)
4240ad72818Smatt 				insertfunc = ptree_insert_mask_before_node;
4250ad72818Smatt 			else
4260ad72818Smatt 				insertfunc = ptree_insert_leaf_after_mask;
4270ad72818Smatt 		} else if (at_mask && id->id_bitoff >= leaf_masklen) {
4280ad72818Smatt 			/*
4290ad72818Smatt 			 * If the new mask has a bit offset GEQ than the leaf's
4300ad72818Smatt 			 * mask length, convert the left to a one-way branch
4310ad72818Smatt 			 * interior mask and make that point to the new [leaf]
4320ad72818Smatt 			 * mask.
4330ad72818Smatt 			 */
4340ad72818Smatt 			insertfunc = ptree_insert_leaf_after_mask;
4350ad72818Smatt 		} else {
4360ad72818Smatt 			/*
4370ad72818Smatt 			 * The new mask has a bit offset less than the leaf's
4380ad72818Smatt 			 * mask length or if the leaf isn't a mask at all, the
4390ad72818Smatt 			 * new mask deserves to be its own leaf so we use the
4400ad72818Smatt 			 * default insertfunc to do that.
4410ad72818Smatt 			 */
4420ad72818Smatt 		}
4430ad72818Smatt 	}
4440ad72818Smatt #endif /* PTNOMASK */
4450ad72818Smatt 
4460ad72818Smatt 	return (*insertfunc)(pt, target, id);
4470ad72818Smatt }
4480ad72818Smatt 
4490ad72818Smatt static bool
ptree_insert_node_common(pt_tree_t * pt,void * item)4500ad72818Smatt ptree_insert_node_common(pt_tree_t *pt, void *item)
4510ad72818Smatt {
4520ad72818Smatt 	pt_node_t * const target = ITEMTONODE(pt, item);
4530ad72818Smatt #ifndef PTNOMASK
4540ad72818Smatt 	const bool inserting_mask = PTN_ISMASK_P(target);
4550ad72818Smatt 	const pt_bitlen_t target_masklen = PTN_MASK_BITLEN(target);
4560ad72818Smatt #endif
4570ad72818Smatt 	pt_insertfunc_t insertfunc;
4580ad72818Smatt 	pt_insertdata_t id;
4590ad72818Smatt 
4600ad72818Smatt 	/*
46184b1adeaSmatt 	 * If this node already exists in the tree, return failure.
46284b1adeaSmatt 	 */
46384b1adeaSmatt 	if (target == PT_NODE(pt->pt_root))
46484b1adeaSmatt 		return false;
46584b1adeaSmatt 
46684b1adeaSmatt 	/*
4670ad72818Smatt 	 * We need a leaf so we can match against.  Until we get a leaf
4680ad72818Smatt 	 * we having nothing to test against.
4690ad72818Smatt 	 */
4700ad72818Smatt 	if (__predict_false(PT_NULL_P(pt->pt_root))) {
4710ad72818Smatt 		PTN_BRANCH_ROOT_SLOT(&pt->pt_rootnode) = PTN_LEAF(target);
4720ad72818Smatt 		PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode) = PTN_LEAF(target);
4730ad72818Smatt 		PTN_SET_LEAF_POSITION(target, PT_SLOT_ROOT);
4740ad72818Smatt 		PTREE_CHECK(pt);
4750ad72818Smatt 		return true;
4760ad72818Smatt 	}
4770ad72818Smatt 
4780ad72818Smatt 	id.id_bitoff = 0;
4790ad72818Smatt 	id.id_parent = &pt->pt_rootnode;
4800ad72818Smatt 	id.id_parent_slot = PT_SLOT_ROOT;
4810ad72818Smatt 	id.id_insertp = &PTN_BRANCH_ROOT_SLOT(id.id_parent);
4820ad72818Smatt 	for (;;) {
4830ad72818Smatt 		pt_bitoff_t branch_bitoff;
4840ad72818Smatt 		pt_node_t * const ptn = PT_NODE(*id.id_insertp);
4850ad72818Smatt 		id.id_node = *id.id_insertp;
4860ad72818Smatt 
4870ad72818Smatt 		/*
48884b1adeaSmatt 		 * If this node already exists in the tree, return failure.
48984b1adeaSmatt 		 */
49084b1adeaSmatt 		if (target == ptn)
49184b1adeaSmatt 			return false;
49284b1adeaSmatt 
49384b1adeaSmatt 		/*
4940ad72818Smatt 		 * If we hit a leaf, try to insert target at leaf.  We could
4950ad72818Smatt 		 * have inlined ptree_insert_leaf here but that would have
4960ad72818Smatt 		 * made this routine much harder to understand.  Trust the
4970ad72818Smatt 		 * compiler to optimize this properly.
4980ad72818Smatt 		 */
4990ad72818Smatt 		if (PT_LEAF_P(id.id_node)) {
5000ad72818Smatt 			KASSERT(PTN_LEAF_POSITION(ptn) == id.id_parent_slot);
5010ad72818Smatt 			insertfunc = ptree_insert_leaf;
5020ad72818Smatt 			break;
5030ad72818Smatt 		}
5040ad72818Smatt 
5050ad72818Smatt 		/*
5060ad72818Smatt 		 * If we aren't a leaf, we must be a branch.  Make sure we are
5070ad72818Smatt 		 * in the slot we think we are.
5080ad72818Smatt 		 */
5090ad72818Smatt 		KASSERT(PT_BRANCH_P(id.id_node));
5100ad72818Smatt 		KASSERT(PTN_BRANCH_POSITION(ptn) == id.id_parent_slot);
5110ad72818Smatt 
5120ad72818Smatt 		/*
5130ad72818Smatt 		 * Where is this branch?
5140ad72818Smatt 		 */
5150ad72818Smatt 		branch_bitoff = PTN_BRANCH_BITOFF(ptn);
5160ad72818Smatt 
5170ad72818Smatt #ifndef PTNOMASK
5180ad72818Smatt 		/*
5190ad72818Smatt 		 * If this is a one-way mask node, its offset must equal
5200ad72818Smatt 		 * its mask's bitlen.
5210ad72818Smatt 		 */
5220ad72818Smatt 		KASSERT(!(PTN_ISMASK_P(ptn) && PTN_BRANCH_BITLEN(ptn) == 0) || PTN_MASK_BITLEN(ptn) == branch_bitoff);
5230ad72818Smatt 
5240ad72818Smatt 		/*
5250ad72818Smatt 		 * If we are inserting a mask, and we know that at this point
5260ad72818Smatt 		 * all bits before the current bit offset match both the target
5270ad72818Smatt 		 * and the branch.  If the target's mask length is LEQ than
5280ad72818Smatt 		 * this branch's bit offset, then this is where the mask needs
5290ad72818Smatt 		 * to added to the tree.
5300ad72818Smatt 		 */
5310ad72818Smatt 		if (__predict_false(inserting_mask)
5320ad72818Smatt 		    && (PTN_ISROOT_P(pt, id.id_parent)
5330ad72818Smatt 			|| id.id_bitoff < target_masklen)
5340ad72818Smatt 		    && target_masklen <= branch_bitoff) {
5350ad72818Smatt 			/*
5360ad72818Smatt 			 * We don't know about the bits (if any) between
5370ad72818Smatt 			 * id.id_bitoff and the target's mask length match
5380ad72818Smatt 			 * both the target and the branch.  If the target's
5390ad72818Smatt 			 * mask length is greater than the current bit offset
5400ad72818Smatt 			 * make sure the untested bits match both the target
5410ad72818Smatt 			 * and the branch.
5420ad72818Smatt 			 */
5430ad72818Smatt 			if (target_masklen == id.id_bitoff
5440ad72818Smatt 			    || ptree_matchnode(pt, target, ptn, target_masklen,
5450ad72818Smatt 				    &id.id_bitoff, &id.id_slot)) {
5460ad72818Smatt 				/*
5470ad72818Smatt 				 * The bits matched, so insert the mask as a
5480ad72818Smatt 				 * one-way branch.
5490ad72818Smatt 				 */
5500ad72818Smatt 				insertfunc = ptree_insert_mask_before_node;
5510ad72818Smatt 				break;
5520ad72818Smatt 			} else if (id.id_bitoff < branch_bitoff) {
5530ad72818Smatt 				/*
5540ad72818Smatt 				 * They didn't match, so create a normal branch
5550ad72818Smatt 				 * because this mask needs to a be a new leaf.
5560ad72818Smatt 				 */
5570ad72818Smatt 				insertfunc = ptree_insert_branch_at_node;
5580ad72818Smatt 				break;
5590ad72818Smatt 			}
5600ad72818Smatt 		}
5610ad72818Smatt #endif /* PTNOMASK */
5620ad72818Smatt 
5630ad72818Smatt 		/*
5640ad72818Smatt 		 * If we are skipping some bits, verify they match the node.
5650ad72818Smatt 		 * If they don't match, it means we have a leaf to insert.
5660ad72818Smatt 		 * Note that if we are advancing bit by bit, we'll skip
5670ad72818Smatt 		 * doing matchnode and walk the tree bit by bit via testnode.
5680ad72818Smatt 		 */
5690ad72818Smatt 		if (id.id_bitoff < branch_bitoff
5700ad72818Smatt 		    && !ptree_matchnode(pt, target, ptn, branch_bitoff,
5710ad72818Smatt 					&id.id_bitoff, &id.id_slot)) {
5720ad72818Smatt 			KASSERT(id.id_bitoff < branch_bitoff);
5730ad72818Smatt 			insertfunc = ptree_insert_branch_at_node;
5740ad72818Smatt 			break;
5750ad72818Smatt 		}
5760ad72818Smatt 
5770ad72818Smatt 		/*
5780ad72818Smatt 		 * At this point, all bits before branch_bitoff are known
5790ad72818Smatt 		 * to match the target.
5800ad72818Smatt 		 */
5810ad72818Smatt 		KASSERT(id.id_bitoff >= branch_bitoff);
5820ad72818Smatt 
5830ad72818Smatt 		/*
584cdc507f0Sandvar 		 * Descend the tree one level.
5850ad72818Smatt 		 */
5860ad72818Smatt 		id.id_parent = ptn;
5870ad72818Smatt 		id.id_parent_slot = ptree_testnode(pt, target, id.id_parent);
5880ad72818Smatt 		id.id_bitoff += PTN_BRANCH_BITLEN(id.id_parent);
5890ad72818Smatt 		id.id_insertp = &PTN_BRANCH_SLOT(id.id_parent, id.id_parent_slot);
5900ad72818Smatt 	}
5910ad72818Smatt 
5920ad72818Smatt 	/*
5930ad72818Smatt 	 * Do the actual insertion.
5940ad72818Smatt 	 */
5950ad72818Smatt 	return (*insertfunc)(pt, target, &id);
5960ad72818Smatt }
5970ad72818Smatt 
5980ad72818Smatt bool
ptree_insert_node(pt_tree_t * pt,void * item)5990ad72818Smatt ptree_insert_node(pt_tree_t *pt, void *item)
6000ad72818Smatt {
6010ad72818Smatt 	pt_node_t * const target = ITEMTONODE(pt, item);
6020ad72818Smatt 
6030ad72818Smatt 	memset(target, 0, sizeof(*target));
6040ad72818Smatt 	return ptree_insert_node_common(pt, target);
6050ad72818Smatt }
6060ad72818Smatt 
6070ad72818Smatt #ifndef PTNOMASK
6080ad72818Smatt bool
ptree_insert_mask_node(pt_tree_t * pt,void * item,pt_bitlen_t mask_len)6090ad72818Smatt ptree_insert_mask_node(pt_tree_t *pt, void *item, pt_bitlen_t mask_len)
6100ad72818Smatt {
6110ad72818Smatt 	pt_node_t * const target = ITEMTONODE(pt, item);
6120ad72818Smatt 	pt_bitoff_t bitoff = mask_len;
6130ad72818Smatt 	pt_slot_t slot;
6140ad72818Smatt 
6150ad72818Smatt 	memset(target, 0, sizeof(*target));
6160ad72818Smatt 	KASSERT(mask_len == 0 || (~PT__MASK(PTN_MASK_BITLEN) & mask_len) == 0);
6170ad72818Smatt 	/*
6180ad72818Smatt 	 * Only the first <mask_len> bits can be non-zero.
6190ad72818Smatt 	 * All other bits must be 0.
6200ad72818Smatt 	 */
6210ad72818Smatt 	if (!ptree_matchnode(pt, target, NULL, UINT_MAX, &bitoff, &slot))
6220ad72818Smatt 		return false;
6230ad72818Smatt 	PTN_SET_MASK_BITLEN(target, mask_len);
6240ad72818Smatt 	PTN_MARK_MASK(target);
6250ad72818Smatt 	return ptree_insert_node_common(pt, target);
6260ad72818Smatt }
6270ad72818Smatt #endif /* !PTNOMASH */
6280ad72818Smatt 
6290ad72818Smatt void *
ptree_find_filtered_node(pt_tree_t * pt,const void * key,pt_filter_t filter,void * filter_arg)6304c826f22Srmind ptree_find_filtered_node(pt_tree_t *pt, const void *key, pt_filter_t filter,
6310ad72818Smatt 	void *filter_arg)
6320ad72818Smatt {
6330ad72818Smatt #ifndef PTNOMASK
6340ad72818Smatt 	pt_node_t *mask = NULL;
6350ad72818Smatt #endif
6360ad72818Smatt 	bool at_mask = false;
6370ad72818Smatt 	pt_node_t *ptn, *parent;
6380ad72818Smatt 	pt_bitoff_t bitoff;
6390ad72818Smatt 	pt_slot_t parent_slot;
6400ad72818Smatt 
6410ad72818Smatt 	if (PT_NULL_P(PTN_BRANCH_ROOT_SLOT(&pt->pt_rootnode)))
6420ad72818Smatt 		return NULL;
6430ad72818Smatt 
6440ad72818Smatt 	bitoff = 0;
6450ad72818Smatt 	parent = &pt->pt_rootnode;
6460ad72818Smatt 	parent_slot = PT_SLOT_ROOT;
6470ad72818Smatt 	for (;;) {
6480ad72818Smatt 		const uintptr_t node = PTN_BRANCH_SLOT(parent, parent_slot);
6490ad72818Smatt 		const pt_slot_t branch_bitoff = PTN_BRANCH_BITOFF(PT_NODE(node));
6500ad72818Smatt 		ptn = PT_NODE(node);
6510ad72818Smatt 
6520ad72818Smatt 		if (PT_LEAF_P(node)) {
6530ad72818Smatt #ifndef PTNOMASK
6540ad72818Smatt 			at_mask = PTN_ISMASK_P(ptn);
6550ad72818Smatt #endif
6560ad72818Smatt 			break;
6570ad72818Smatt 		}
6580ad72818Smatt 
6590ad72818Smatt 		if (bitoff < branch_bitoff) {
6600ad72818Smatt 			if (!ptree_matchkey(pt, key, ptn, bitoff, branch_bitoff - bitoff)) {
6610ad72818Smatt #ifndef PTNOMASK
6620ad72818Smatt 				if (mask != NULL)
6630ad72818Smatt 					return NODETOITEM(pt, mask);
6640ad72818Smatt #endif
6650ad72818Smatt 				return NULL;
6660ad72818Smatt 			}
6670ad72818Smatt 			bitoff = branch_bitoff;
6680ad72818Smatt 		}
6690ad72818Smatt 
6700ad72818Smatt #ifndef PTNOMASK
6710ad72818Smatt 		if (PTN_ISMASK_P(ptn) && PTN_BRANCH_BITLEN(ptn) == 0
6720ad72818Smatt 		    && (!filter
6730ad72818Smatt 		        || (*filter)(filter_arg, NODETOITEM(pt, ptn),
6740ad72818Smatt 				     PT_FILTER_MASK)))
6750ad72818Smatt 			mask = ptn;
6760ad72818Smatt #endif
6770ad72818Smatt 
6780ad72818Smatt 		parent = ptn;
6790ad72818Smatt 		parent_slot = ptree_testkey(pt, key, parent);
6800ad72818Smatt 		bitoff += PTN_BRANCH_BITLEN(parent);
6810ad72818Smatt 	}
6820ad72818Smatt 
6830ad72818Smatt 	KASSERT(PTN_ISROOT_P(pt, parent) || PTN_BRANCH_BITOFF(parent) + PTN_BRANCH_BITLEN(parent) == bitoff);
6840ad72818Smatt 	if (!filter || (*filter)(filter_arg, NODETOITEM(pt, ptn), at_mask ? PT_FILTER_MASK : 0)) {
6850ad72818Smatt #ifndef PTNOMASK
6860ad72818Smatt 		if (PTN_ISMASK_P(ptn)) {
6870ad72818Smatt 			const pt_bitlen_t mask_len = PTN_MASK_BITLEN(ptn);
6880ad72818Smatt 			if (bitoff == PTN_MASK_BITLEN(ptn))
6890ad72818Smatt 				return NODETOITEM(pt, ptn);
6900ad72818Smatt 			if (ptree_matchkey(pt, key, ptn, bitoff, mask_len - bitoff))
6910ad72818Smatt 				return NODETOITEM(pt, ptn);
6920ad72818Smatt 		} else
6930ad72818Smatt #endif /* !PTNOMASK */
6940ad72818Smatt 		if (ptree_matchkey(pt, key, ptn, bitoff, UINT_MAX))
6950ad72818Smatt 			return NODETOITEM(pt, ptn);
6960ad72818Smatt 	}
6970ad72818Smatt 
6980ad72818Smatt #ifndef PTNOMASK
6990ad72818Smatt 	/*
7000ad72818Smatt 	 * By virtue of how the mask was placed in the tree,
7010ad72818Smatt 	 * all nodes descended from it will match it.  But the bits
7020ad72818Smatt 	 * before the mask still need to be checked and since the
7030ad72818Smatt 	 * mask was a branch, that was done implicitly.
7040ad72818Smatt 	 */
7050ad72818Smatt 	if (mask != NULL) {
7060ad72818Smatt 		KASSERT(ptree_matchkey(pt, key, mask, 0, PTN_MASK_BITLEN(mask)));
7070ad72818Smatt 		return NODETOITEM(pt, mask);
7080ad72818Smatt 	}
7090ad72818Smatt #endif /* !PTNOMASK */
7100ad72818Smatt 
7110ad72818Smatt 	/*
7120ad72818Smatt 	 * Nothing matched.
7130ad72818Smatt 	 */
7140ad72818Smatt 	return NULL;
7150ad72818Smatt }
7160ad72818Smatt 
7170ad72818Smatt void *
ptree_iterate(pt_tree_t * pt,const void * item,pt_direction_t direction)7180ad72818Smatt ptree_iterate(pt_tree_t *pt, const void *item, pt_direction_t direction)
7190ad72818Smatt {
7200ad72818Smatt 	const pt_node_t * const target = ITEMTONODE(pt, item);
7210ad72818Smatt 	uintptr_t node, next_node;
7220ad72818Smatt 
7230ad72818Smatt 	if (direction != PT_ASCENDING && direction != PT_DESCENDING)
7240ad72818Smatt 		return NULL;
7250ad72818Smatt 
7260ad72818Smatt 	node = PTN_BRANCH_ROOT_SLOT(&pt->pt_rootnode);
7270ad72818Smatt 	if (PT_NULL_P(node))
7280ad72818Smatt 		return NULL;
7290ad72818Smatt 
7300ad72818Smatt 	if (item == NULL) {
7310ad72818Smatt 		pt_node_t * const ptn = PT_NODE(node);
7320ad72818Smatt 		if (direction == PT_ASCENDING
7330ad72818Smatt 		    && PTN_ISMASK_P(ptn) && PTN_BRANCH_BITLEN(ptn) == 0)
7340ad72818Smatt 			return NODETOITEM(pt, ptn);
7350ad72818Smatt 		next_node = node;
7360ad72818Smatt 	} else {
7370ad72818Smatt #ifndef PTNOMASK
7380ad72818Smatt 		uintptr_t mask_node = PT_NULL;
7390ad72818Smatt #endif /* !PTNOMASK */
7400ad72818Smatt 		next_node = PT_NULL;
7410ad72818Smatt 		while (!PT_LEAF_P(node)) {
7420ad72818Smatt 			pt_node_t * const ptn = PT_NODE(node);
7430ad72818Smatt 			pt_slot_t slot;
7440ad72818Smatt #ifndef PTNOMASK
7450ad72818Smatt 			if (PTN_ISMASK_P(ptn) && PTN_BRANCH_BITLEN(ptn) == 0) {
7460ad72818Smatt 				if (ptn == target)
7470ad72818Smatt 					break;
7480ad72818Smatt 				if (direction == PT_DESCENDING) {
7490ad72818Smatt 					mask_node = node;
7500ad72818Smatt 					next_node = PT_NULL;
7510ad72818Smatt 				}
7520ad72818Smatt 			}
7530ad72818Smatt #endif /* !PTNOMASK */
7540ad72818Smatt 			slot = ptree_testnode(pt, target, ptn);
7550ad72818Smatt 			node = PTN_BRANCH_SLOT(ptn, slot);
7560ad72818Smatt 			if (direction == PT_ASCENDING) {
757c5eb4ab6Slukem 				if (slot != (pt_slot_t)((1 << PTN_BRANCH_BITLEN(ptn)) - 1))
7580ad72818Smatt 					next_node = PTN_BRANCH_SLOT(ptn, slot + 1);
7590ad72818Smatt 			} else {
7600ad72818Smatt 				if (slot > 0) {
7610ad72818Smatt #ifndef PTNOMASK
7620ad72818Smatt 					mask_node = PT_NULL;
7630ad72818Smatt #endif /* !PTNOMASK */
7640ad72818Smatt 					next_node = PTN_BRANCH_SLOT(ptn, slot - 1);
7650ad72818Smatt 				}
7660ad72818Smatt 			}
7670ad72818Smatt 		}
7680ad72818Smatt 		if (PT_NODE(node) != target)
7690ad72818Smatt 			return NULL;
7700ad72818Smatt #ifndef PTNOMASK
7710ad72818Smatt 		if (PT_BRANCH_P(node)) {
7720ad72818Smatt 			pt_node_t *ptn = PT_NODE(node);
7730ad72818Smatt 			KASSERT(PTN_ISMASK_P(PT_NODE(node)) && PTN_BRANCH_BITLEN(PT_NODE(node)) == 0);
7740ad72818Smatt 			if (direction == PT_ASCENDING) {
7750ad72818Smatt 				next_node = PTN_BRANCH_ROOT_SLOT(ptn);
7760ad72818Smatt 				ptn = PT_NODE(next_node);
7770ad72818Smatt 			}
7780ad72818Smatt 		}
7790ad72818Smatt 		/*
7800ad72818Smatt 		 * When descending, if we countered a mask node then that's
7810ad72818Smatt 		 * we want to return.
7820ad72818Smatt 		 */
7830ad72818Smatt 		if (direction == PT_DESCENDING && !PT_NULL_P(mask_node)) {
7840ad72818Smatt 			KASSERT(PT_NULL_P(next_node));
7850ad72818Smatt 			return NODETOITEM(pt, PT_NODE(mask_node));
7860ad72818Smatt 		}
7870ad72818Smatt #endif /* !PTNOMASK */
7880ad72818Smatt 	}
7890ad72818Smatt 
7900ad72818Smatt 	node = next_node;
7910ad72818Smatt 	if (PT_NULL_P(node))
7920ad72818Smatt 		return NULL;
7930ad72818Smatt 
7940ad72818Smatt 	while (!PT_LEAF_P(node)) {
7950ad72818Smatt 		pt_node_t * const ptn = PT_NODE(node);
7960ad72818Smatt 		pt_slot_t slot;
7970ad72818Smatt 		if (direction == PT_ASCENDING) {
7980ad72818Smatt #ifndef PTNOMASK
7990ad72818Smatt 			if (PT_BRANCH_P(node)
8000ad72818Smatt 			    && PTN_ISMASK_P(ptn)
8010ad72818Smatt 			    && PTN_BRANCH_BITLEN(ptn) == 0)
8020ad72818Smatt 				return NODETOITEM(pt, ptn);
8030ad72818Smatt #endif /* !PTNOMASK */
8040ad72818Smatt 			slot = PT_SLOT_LEFT;
8050ad72818Smatt 		} else {
8060ad72818Smatt 			slot = (1 << PTN_BRANCH_BITLEN(ptn)) - 1;
8070ad72818Smatt 		}
8080ad72818Smatt 		node = PTN_BRANCH_SLOT(ptn, slot);
8090ad72818Smatt 	}
8100ad72818Smatt 	return NODETOITEM(pt, PT_NODE(node));
8110ad72818Smatt }
8120ad72818Smatt 
8130ad72818Smatt void
ptree_remove_node(pt_tree_t * pt,void * item)8140ad72818Smatt ptree_remove_node(pt_tree_t *pt, void *item)
8150ad72818Smatt {
8160ad72818Smatt 	pt_node_t * const target = ITEMTONODE(pt, item);
8170ad72818Smatt 	const pt_slot_t leaf_slot = PTN_LEAF_POSITION(target);
8180ad72818Smatt 	const pt_slot_t branch_slot = PTN_BRANCH_POSITION(target);
8190ad72818Smatt 	pt_node_t *ptn, *parent;
8200ad72818Smatt 	uintptr_t node;
8210ad72818Smatt 	uintptr_t *removep;
8220ad72818Smatt 	uintptr_t *nodep;
8230ad72818Smatt 	pt_bitoff_t bitoff;
8240ad72818Smatt 	pt_slot_t parent_slot;
8250ad72818Smatt #ifndef PTNOMASK
8260ad72818Smatt 	bool at_mask;
8270ad72818Smatt #endif
8280ad72818Smatt 
8290ad72818Smatt 	if (PT_NULL_P(PTN_BRANCH_ROOT_SLOT(&pt->pt_rootnode))) {
8300ad72818Smatt 		KASSERT(!PT_NULL_P(PTN_BRANCH_ROOT_SLOT(&pt->pt_rootnode)));
8310ad72818Smatt 		return;
8320ad72818Smatt 	}
8330ad72818Smatt 
8340ad72818Smatt 	bitoff = 0;
8350ad72818Smatt 	removep = NULL;
8360ad72818Smatt 	nodep = NULL;
8370ad72818Smatt 	parent = &pt->pt_rootnode;
8380ad72818Smatt 	parent_slot = PT_SLOT_ROOT;
8390ad72818Smatt 	for (;;) {
8400ad72818Smatt 		node = PTN_BRANCH_SLOT(parent, parent_slot);
8410ad72818Smatt 		ptn = PT_NODE(node);
8420ad72818Smatt #ifndef PTNOMASK
8430ad72818Smatt 		at_mask = PTN_ISMASK_P(ptn);
8440ad72818Smatt #endif
8450ad72818Smatt 
8460ad72818Smatt 		if (PT_LEAF_P(node))
8470ad72818Smatt 			break;
8480ad72818Smatt 
8490ad72818Smatt 		/*
8500ad72818Smatt 		 * If we are at the target, then we are looking at its branch
8510ad72818Smatt 		 * identity.  We need to remember who's pointing at it so we
8520ad72818Smatt 		 * stop them from doing that.
8530ad72818Smatt 		 */
8540ad72818Smatt 		if (__predict_false(ptn == target)) {
8550ad72818Smatt 			KASSERT(nodep == NULL);
8560ad72818Smatt #ifndef PTNOMASK
8570ad72818Smatt 			/*
8580ad72818Smatt 			 * Interior mask nodes are trivial to get rid of.
8590ad72818Smatt 			 */
8600ad72818Smatt 			if (at_mask && PTN_BRANCH_BITLEN(ptn) == 0) {
8610ad72818Smatt 				PTN_BRANCH_SLOT(parent, parent_slot) =
8620ad72818Smatt 				    PTN_BRANCH_ROOT_SLOT(ptn);
8630ad72818Smatt 				KASSERT(PT_NULL_P(PTN_BRANCH_ODDMAN_SLOT(ptn)));
8640ad72818Smatt 				PTREE_CHECK(pt);
8650ad72818Smatt 				return;
8660ad72818Smatt 			}
8670ad72818Smatt #endif /* !PTNOMASK */
8680ad72818Smatt 			nodep = &PTN_BRANCH_SLOT(parent, parent_slot);
8690ad72818Smatt 			KASSERT(*nodep == PTN_BRANCH(target));
8700ad72818Smatt 		}
8710ad72818Smatt 		/*
8720ad72818Smatt 		 * We need also need to know who's pointing at our parent.
8730ad72818Smatt 		 * After we remove ourselves from our parent, he'll only
8740ad72818Smatt 		 * have one child and that's unacceptable.  So we replace
8750ad72818Smatt 		 * the pointer to the parent with our abadoned sibling.
8760ad72818Smatt 		 */
8770ad72818Smatt 		removep = &PTN_BRANCH_SLOT(parent, parent_slot);
8780ad72818Smatt 
8790ad72818Smatt 		/*
8800ad72818Smatt 		 * Descend into the tree.
8810ad72818Smatt 		 */
8820ad72818Smatt 		parent = ptn;
8830ad72818Smatt 		parent_slot = ptree_testnode(pt, target, parent);
8840ad72818Smatt 		bitoff += PTN_BRANCH_BITLEN(parent);
8850ad72818Smatt 	}
8860ad72818Smatt 
8870ad72818Smatt 	/*
8880ad72818Smatt 	 * We better have found that the leaf we are looking for is target.
8890ad72818Smatt 	 */
8900ad72818Smatt 	if (target != ptn) {
8910ad72818Smatt 		KASSERT(target == ptn);
8920ad72818Smatt 		return;
8930ad72818Smatt 	}
8940ad72818Smatt 
8950ad72818Smatt 	/*
8960ad72818Smatt 	 * If we didn't encounter target as branch, then target must be the
8970ad72818Smatt 	 * oddman-out.
8980ad72818Smatt 	 */
8990ad72818Smatt 	if (nodep == NULL) {
9000ad72818Smatt 		KASSERT(PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode) == PTN_LEAF(target));
9010ad72818Smatt 		KASSERT(nodep == NULL);
9020ad72818Smatt 		nodep = &PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode);
9030ad72818Smatt 	}
9040ad72818Smatt 
9050ad72818Smatt 	KASSERT((removep == NULL) == (parent == &pt->pt_rootnode));
9060ad72818Smatt 
9070ad72818Smatt 	/*
9080ad72818Smatt 	 * We have to special remove the last leaf from the root since
9090ad72818Smatt 	 * the only time the tree can a PT_NULL node is when it's empty.
9100ad72818Smatt 	 */
9110ad72818Smatt 	if (__predict_false(PTN_ISROOT_P(pt, parent))) {
9120ad72818Smatt 		KASSERT(removep == NULL);
9130ad72818Smatt 		KASSERT(parent == &pt->pt_rootnode);
9140ad72818Smatt 		KASSERT(nodep == &PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode));
9150ad72818Smatt 		KASSERT(*nodep == PTN_LEAF(target));
9160ad72818Smatt 		PTN_BRANCH_ROOT_SLOT(&pt->pt_rootnode) = PT_NULL;
9170ad72818Smatt 		PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode) = PT_NULL;
9180ad72818Smatt 		return;
9190ad72818Smatt 	}
9200ad72818Smatt 
9210ad72818Smatt 	KASSERT((parent == target) == (removep == nodep));
9220ad72818Smatt 	if (PTN_BRANCH(parent) == PTN_BRANCH_SLOT(target, PTN_BRANCH_POSITION(parent))) {
9230ad72818Smatt 		/*
9240ad72818Smatt 		 * The pointer to the parent actually lives in the target's
9250ad72818Smatt 		 * branch identity.  We can't just move the target's branch
9260ad72818Smatt 		 * identity since that would result in the parent pointing
9270ad72818Smatt 		 * to its own branch identity and that's fobidden.
9280ad72818Smatt 		 */
9290ad72818Smatt 		const pt_slot_t slot = PTN_BRANCH_POSITION(parent);
9300ad72818Smatt 		const pt_slot_t other_slot = slot ^ PT_SLOT_OTHER;
9310ad72818Smatt 		const pt_bitlen_t parent_bitlen = PTN_BRANCH_BITLEN(parent);
9320ad72818Smatt 
9330ad72818Smatt 		KASSERT(PTN_BRANCH_BITOFF(target) < PTN_BRANCH_BITOFF(parent));
9340ad72818Smatt 
9350ad72818Smatt 		/*
9360ad72818Smatt 		 * This gets so confusing.  The target's branch identity
9370ad72818Smatt 		 * points to the branch identity of the parent of the target's
9380ad72818Smatt 		 * leaf identity:
9390ad72818Smatt 		 *
9400ad72818Smatt 		 * 	TB = { X, PB = { TL, Y } }
9410ad72818Smatt 		 *   or TB = { X, PB = { TL } }
9420ad72818Smatt 		 *
9430ad72818Smatt 		 * So we can't move the target's branch identity to the parent
9440ad72818Smatt 		 * because that would corrupt the tree.
9450ad72818Smatt 		 */
9460ad72818Smatt 		if (__predict_true(parent_bitlen > 0)) {
9470ad72818Smatt 			/*
9480ad72818Smatt 			 * The parent is a two-way branch.  We have to have
9490ad72818Smatt 			 * do to this chang in two steps to keep internally
9500ad72818Smatt 			 * consistent.  First step is to copy our sibling from
9510ad72818Smatt 			 * our parent to where we are pointing to parent's
9520ad72818Smatt 			 * branch identiy.  This remove all references to his
9530ad72818Smatt 			 * branch identity from the tree.  We then simply make
9540ad72818Smatt 			 * the parent assume the target's branching duties.
9550ad72818Smatt 			 *
9560ad72818Smatt 			 *   TB = { X, PB = { Y, TL } } --> PB = { X, Y }.
9570ad72818Smatt 			 *   TB = { X, PB = { TL, Y } } --> PB = { X, Y }.
9580ad72818Smatt 			 *   TB = { PB = { Y, TL }, X } --> PB = { Y, X }.
9590ad72818Smatt 			 *   TB = { PB = { TL, Y }, X } --> PB = { Y, X }.
9600ad72818Smatt 			 */
9610ad72818Smatt 			PTN_BRANCH_SLOT(target, slot) =
9620ad72818Smatt 			    PTN_BRANCH_SLOT(parent, parent_slot ^ PT_SLOT_OTHER);
9630ad72818Smatt 			*nodep = ptree_move_branch(pt, parent, target);
9640ad72818Smatt 			PTREE_CHECK(pt);
9650ad72818Smatt 			return;
9660ad72818Smatt 		} else {
9670ad72818Smatt 			/*
9680ad72818Smatt 			 * If parent was a one-way branch, it must have been
9690ad72818Smatt 			 * mask which pointed to a single leaf which we are
9700ad72818Smatt 			 * removing.  This means we have to convert the
9710ad72818Smatt 			 * parent back to a leaf node.  So in the same
9720ad72818Smatt 			 * position that target pointed to parent, we place
9730ad72818Smatt 			 * leaf pointer to parent.  In the other position,
9740ad72818Smatt 			 * we just put the other node from target.
9750ad72818Smatt 			 *
9760ad72818Smatt 			 *   TB = { X, PB = { TL } } --> PB = { X, PL }
9770ad72818Smatt 			 */
9780ad72818Smatt 			KASSERT(PTN_ISMASK_P(parent));
9790ad72818Smatt 			KASSERT(slot == ptree_testnode(pt, parent, target));
9800ad72818Smatt 			PTN_BRANCH_SLOT(parent, slot) = PTN_LEAF(parent);
9810ad72818Smatt 			PTN_BRANCH_SLOT(parent, other_slot) =
9820ad72818Smatt 			   PTN_BRANCH_SLOT(target, other_slot);
9830ad72818Smatt 			PTN_SET_LEAF_POSITION(parent,slot);
9840ad72818Smatt 			PTN_SET_BRANCH_BITLEN(parent, 1);
9850ad72818Smatt 		}
9860ad72818Smatt 		PTN_SET_BRANCH_BITOFF(parent, PTN_BRANCH_BITOFF(target));
9870ad72818Smatt 		PTN_SET_BRANCH_POSITION(parent, PTN_BRANCH_POSITION(target));
9880ad72818Smatt 
9890ad72818Smatt 		*nodep = PTN_BRANCH(parent);
9900ad72818Smatt 		PTREE_CHECK(pt);
9910ad72818Smatt 		return;
9920ad72818Smatt 	}
9930ad72818Smatt 
9940ad72818Smatt #ifndef PTNOMASK
9950ad72818Smatt 	if (__predict_false(PTN_BRANCH_BITLEN(parent) == 0)) {
9960ad72818Smatt 		/*
9970ad72818Smatt 		 * Parent was a one-way branch which is changing back to a leaf.
9980ad72818Smatt 		 * Since parent is no longer a one-way branch, it can take over
9990ad72818Smatt 		 * target's branching duties.
10000ad72818Smatt 		 *
10010ad72818Smatt 		 *  GB = { PB = { TL } }	--> GB = { PL }
10020ad72818Smatt 		 *  TB = { X, Y }		--> PB = { X, Y }
10030ad72818Smatt 		 */
10040ad72818Smatt 		KASSERT(PTN_ISMASK_P(parent));
10050ad72818Smatt 		KASSERT(parent != target);
10060ad72818Smatt 		*removep = PTN_LEAF(parent);
10070ad72818Smatt 	} else
10080ad72818Smatt #endif /* !PTNOMASK */
10090ad72818Smatt 	{
10100ad72818Smatt 		/*
10110ad72818Smatt 		 * Now we are the normal removal case.  Since after the
10120ad72818Smatt 		 * target's leaf identity is removed from the its parent,
1013cdc507f0Sandvar 		 * that parent will only have one descendant.  So we can
10140ad72818Smatt 		 * just as easily replace the node that has the parent's
10150ad72818Smatt 		 * branch identity with the surviving node.  This freeing
10160ad72818Smatt 		 * parent from its branching duties which means it can
10170ad72818Smatt 		 * take over target's branching duties.
10180ad72818Smatt 		 *
10190ad72818Smatt 		 *  GB = { PB = { X, TL } }	--> GB = { X }
10200ad72818Smatt 		 *  TB = { V, W }		--> PB = { V, W }
10210ad72818Smatt 		 */
10220ad72818Smatt 		const pt_slot_t other_slot = parent_slot ^ PT_SLOT_OTHER;
10230ad72818Smatt 		uintptr_t other_node = PTN_BRANCH_SLOT(parent, other_slot);
10240ad72818Smatt 		const pt_slot_t target_slot = (parent == target ? branch_slot : leaf_slot);
10250ad72818Smatt 
10260ad72818Smatt 		*removep = other_node;
10270ad72818Smatt 
10280ad72818Smatt 		ptree_set_position(other_node, target_slot);
10290ad72818Smatt 
10300ad72818Smatt 		/*
10310ad72818Smatt 		 * If target's branch identity contained its leaf identity, we
10320ad72818Smatt 		 * have nothing left to do.  We've already moved 'X' so there
10330ad72818Smatt 		 * is no longer anything in the target's branch identiy that
10340ad72818Smatt 		 * has to be preserved.
10350ad72818Smatt 		 */
10360ad72818Smatt 		if (parent == target) {
10370ad72818Smatt 			/*
10380ad72818Smatt 			 *  GB = { TB = { X, TL } }	--> GB = { X }
10390ad72818Smatt 			 *  TB = { X, TL }		--> don't care
10400ad72818Smatt 			 */
10410ad72818Smatt 			PTREE_CHECK(pt);
10420ad72818Smatt 			return;
10430ad72818Smatt 		}
10440ad72818Smatt 	}
10450ad72818Smatt 
10460ad72818Smatt 	/*
10470ad72818Smatt 	 * If target wasn't used as a branch, then it must have been the
10480ad72818Smatt 	 * oddman-out of the tree (the one node that doesn't have a branch
10490ad72818Smatt 	 * identity).  This makes parent the new oddman-out.
10500ad72818Smatt 	 */
10510ad72818Smatt 	if (*nodep == PTN_LEAF(target)) {
10520ad72818Smatt 		KASSERT(nodep == &PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode));
10530ad72818Smatt 		PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode) = PTN_LEAF(parent);
10540ad72818Smatt 		PTREE_CHECK(pt);
10550ad72818Smatt 		return;
10560ad72818Smatt 	}
10570ad72818Smatt 
10580ad72818Smatt 	/*
10590ad72818Smatt 	 * Finally move the target's branching duties to the parent.
10600ad72818Smatt 	 */
10610ad72818Smatt 	KASSERT(PTN_BRANCH_BITOFF(parent) > PTN_BRANCH_BITOFF(target));
10620ad72818Smatt 	*nodep = ptree_move_branch(pt, parent, target);
10630ad72818Smatt 	PTREE_CHECK(pt);
10640ad72818Smatt }
10650ad72818Smatt 
10660ad72818Smatt #ifdef PTCHECK
10670ad72818Smatt static const pt_node_t *
ptree_check_find_node2(const pt_tree_t * pt,const pt_node_t * parent,uintptr_t target)10680ad72818Smatt ptree_check_find_node2(const pt_tree_t *pt, const pt_node_t *parent,
10690ad72818Smatt 	uintptr_t target)
10700ad72818Smatt {
10710ad72818Smatt 	const pt_bitlen_t slots = 1 << PTN_BRANCH_BITLEN(parent);
10720ad72818Smatt 	pt_slot_t slot;
10730ad72818Smatt 
10740ad72818Smatt 	for (slot = 0; slot < slots; slot++) {
10750ad72818Smatt 		const uintptr_t node = PTN_BRANCH_SLOT(parent, slot);
10760ad72818Smatt 		if (PTN_BRANCH_SLOT(parent, slot) == node)
10770ad72818Smatt 			return parent;
10780ad72818Smatt 	}
10790ad72818Smatt 	for (slot = 0; slot < slots; slot++) {
10800ad72818Smatt 		const uintptr_t node = PTN_BRANCH_SLOT(parent, slot);
10810ad72818Smatt 		const pt_node_t *branch;
10820ad72818Smatt 		if (!PT_BRANCH_P(node))
10830ad72818Smatt 			continue;
10840ad72818Smatt 		branch = ptree_check_find_node2(pt, PT_NODE(node), target);
10850ad72818Smatt 		if (branch != NULL)
10860ad72818Smatt 			return branch;
10870ad72818Smatt 	}
10880ad72818Smatt 
10890ad72818Smatt 	return NULL;
10900ad72818Smatt }
10910ad72818Smatt 
10920ad72818Smatt static bool
ptree_check_leaf(const pt_tree_t * pt,const pt_node_t * parent,const pt_node_t * ptn)10930ad72818Smatt ptree_check_leaf(const pt_tree_t *pt, const pt_node_t *parent,
10940ad72818Smatt 	const pt_node_t *ptn)
10950ad72818Smatt {
10960ad72818Smatt 	const pt_bitoff_t leaf_position = PTN_LEAF_POSITION(ptn);
10970ad72818Smatt 	const pt_bitlen_t bitlen = PTN_BRANCH_BITLEN(ptn);
10980ad72818Smatt 	const pt_bitlen_t mask_len = PTN_MASK_BITLEN(ptn);
10990ad72818Smatt 	const uintptr_t leaf_node = PTN_LEAF(ptn);
11000ad72818Smatt 	const bool is_parent_root = (parent == &pt->pt_rootnode);
11010ad72818Smatt 	const bool is_mask = PTN_ISMASK_P(ptn);
11020ad72818Smatt 	bool ok = true;
11030ad72818Smatt 
11040ad72818Smatt 	if (is_parent_root) {
11050ad72818Smatt 		ok = ok && PTN_BRANCH_ODDMAN_SLOT(parent) == leaf_node;
11060ad72818Smatt 		KASSERT(ok);
11070ad72818Smatt 		return ok;
11080ad72818Smatt 	}
11090ad72818Smatt 
11100ad72818Smatt 	if (is_mask && PTN_ISMASK_P(parent) && PTN_BRANCH_BITLEN(parent) == 0) {
11110ad72818Smatt 		ok = ok && PTN_MASK_BITLEN(parent) < mask_len;
11120ad72818Smatt 		KASSERT(ok);
11130ad72818Smatt 		ok = ok && PTN_BRANCH_BITOFF(parent) < mask_len;
11140ad72818Smatt 		KASSERT(ok);
11150ad72818Smatt 	}
11160ad72818Smatt 	ok = ok && PTN_BRANCH_SLOT(parent, leaf_position) == leaf_node;
11170ad72818Smatt 	KASSERT(ok);
11180ad72818Smatt 	ok = ok && leaf_position == ptree_testnode(pt, ptn, parent);
11190ad72818Smatt 	KASSERT(ok);
11200ad72818Smatt 	if (PTN_BRANCH_ODDMAN_SLOT(&pt->pt_rootnode) != leaf_node) {
11210ad72818Smatt 		ok = ok && bitlen > 0;
11220ad72818Smatt 		KASSERT(ok);
11230ad72818Smatt 		ok = ok && ptn == ptree_check_find_node2(pt, ptn, PTN_LEAF(ptn));
11240ad72818Smatt 		KASSERT(ok);
11250ad72818Smatt 	}
11260ad72818Smatt 	return ok;
11270ad72818Smatt }
11280ad72818Smatt 
11290ad72818Smatt static bool
ptree_check_branch(const pt_tree_t * pt,const pt_node_t * parent,const pt_node_t * ptn)11300ad72818Smatt ptree_check_branch(const pt_tree_t *pt, const pt_node_t *parent,
11310ad72818Smatt 	const pt_node_t *ptn)
11320ad72818Smatt {
11330ad72818Smatt 	const bool is_parent_root = (parent == &pt->pt_rootnode);
11340ad72818Smatt 	const pt_slot_t branch_slot = PTN_BRANCH_POSITION(ptn);
11350ad72818Smatt 	const pt_bitoff_t bitoff = PTN_BRANCH_BITOFF(ptn);
11360ad72818Smatt 	const pt_bitoff_t bitlen = PTN_BRANCH_BITLEN(ptn);
11370ad72818Smatt 	const pt_bitoff_t parent_bitoff = PTN_BRANCH_BITOFF(parent);
11380ad72818Smatt 	const pt_bitoff_t parent_bitlen = PTN_BRANCH_BITLEN(parent);
11390ad72818Smatt 	const bool is_parent_mask = PTN_ISMASK_P(parent) && parent_bitlen == 0;
11400ad72818Smatt 	const bool is_mask = PTN_ISMASK_P(ptn) && bitlen == 0;
11410ad72818Smatt 	const pt_bitoff_t parent_mask_len = PTN_MASK_BITLEN(parent);
11420ad72818Smatt 	const pt_bitoff_t mask_len = PTN_MASK_BITLEN(ptn);
11430ad72818Smatt 	const pt_bitlen_t slots = 1 << bitlen;
11440ad72818Smatt 	pt_slot_t slot;
11450ad72818Smatt 	bool ok = true;
11460ad72818Smatt 
11470ad72818Smatt 	ok = ok && PTN_BRANCH_SLOT(parent, branch_slot) == PTN_BRANCH(ptn);
11480ad72818Smatt 	KASSERT(ok);
11490ad72818Smatt 	ok = ok && branch_slot == ptree_testnode(pt, ptn, parent);
11500ad72818Smatt 	KASSERT(ok);
11510ad72818Smatt 
11520ad72818Smatt 	if (is_mask) {
11530ad72818Smatt 		ok = ok && bitoff == mask_len;
11540ad72818Smatt 		KASSERT(ok);
11550ad72818Smatt 		if (is_parent_mask) {
11560ad72818Smatt 			ok = ok && parent_mask_len < mask_len;
11570ad72818Smatt 			KASSERT(ok);
11580ad72818Smatt 			ok = ok && parent_bitoff < bitoff;
11590ad72818Smatt 			KASSERT(ok);
11600ad72818Smatt 		}
11610ad72818Smatt 	} else {
11620ad72818Smatt 		if (is_parent_mask) {
11630ad72818Smatt 			ok = ok && parent_bitoff <= bitoff;
11640ad72818Smatt 		} else if (!is_parent_root) {
11650ad72818Smatt 			ok = ok && parent_bitoff < bitoff;
11660ad72818Smatt 		}
11670ad72818Smatt 		KASSERT(ok);
11680ad72818Smatt 	}
11690ad72818Smatt 
11700ad72818Smatt 	for (slot = 0; slot < slots; slot++) {
11710ad72818Smatt 		const uintptr_t node = PTN_BRANCH_SLOT(ptn, slot);
11720ad72818Smatt 		pt_bitoff_t tmp_bitoff = 0;
11730ad72818Smatt 		pt_slot_t tmp_slot;
11740ad72818Smatt 		ok = ok && node != PTN_BRANCH(ptn);
11750ad72818Smatt 		KASSERT(ok);
11760ad72818Smatt 		if (bitlen > 0) {
11770ad72818Smatt 			ok = ok && ptree_matchnode(pt, PT_NODE(node), ptn, bitoff, &tmp_bitoff, &tmp_slot);
11780ad72818Smatt 			KASSERT(ok);
11790ad72818Smatt 			tmp_slot = ptree_testnode(pt, PT_NODE(node), ptn);
11800ad72818Smatt 			ok = ok && slot == tmp_slot;
11810ad72818Smatt 			KASSERT(ok);
11820ad72818Smatt 		}
11830ad72818Smatt 		if (PT_LEAF_P(node))
11840ad72818Smatt 			ok = ok && ptree_check_leaf(pt, ptn, PT_NODE(node));
11850ad72818Smatt 		else
11860ad72818Smatt 			ok = ok && ptree_check_branch(pt, ptn, PT_NODE(node));
11870ad72818Smatt 	}
11880ad72818Smatt 
11890ad72818Smatt 	return ok;
11900ad72818Smatt }
11910ad72818Smatt #endif /* PTCHECK */
11920ad72818Smatt 
11934de7478cSmatt /*ARGSUSED*/
11940ad72818Smatt bool
ptree_check(const pt_tree_t * pt)11950ad72818Smatt ptree_check(const pt_tree_t *pt)
11960ad72818Smatt {
11970ad72818Smatt 	bool ok = true;
11980ad72818Smatt #ifdef PTCHECK
11990ad72818Smatt 	const pt_node_t * const parent = &pt->pt_rootnode;
12000ad72818Smatt 	const uintptr_t node = pt->pt_root;
12010ad72818Smatt 	const pt_node_t * const ptn = PT_NODE(node);
12020ad72818Smatt 
12030ad72818Smatt 	ok = ok && PTN_BRANCH_BITOFF(parent) == 0;
12040ad72818Smatt 	ok = ok && !PTN_ISMASK_P(parent);
12050ad72818Smatt 
12060ad72818Smatt 	if (PT_NULL_P(node))
12070ad72818Smatt 		return ok;
12080ad72818Smatt 
12090ad72818Smatt 	if (PT_LEAF_P(node))
12100ad72818Smatt 		ok = ok && ptree_check_leaf(pt, parent, ptn);
12110ad72818Smatt 	else
12120ad72818Smatt 		ok = ok && ptree_check_branch(pt, parent, ptn);
12130ad72818Smatt #endif
12140ad72818Smatt 	return ok;
12150ad72818Smatt }
1216b40d79bcSmatt 
1217b40d79bcSmatt bool
ptree_mask_node_p(pt_tree_t * pt,const void * item,pt_bitlen_t * lenp)1218b40d79bcSmatt ptree_mask_node_p(pt_tree_t *pt, const void *item, pt_bitlen_t *lenp)
1219b40d79bcSmatt {
1220b40d79bcSmatt 	const pt_node_t * const mask = ITEMTONODE(pt, item);
1221b40d79bcSmatt 
1222b40d79bcSmatt 	if (!PTN_ISMASK_P(mask))
1223b40d79bcSmatt 		return false;
1224b40d79bcSmatt 
1225b40d79bcSmatt 	if (lenp != NULL)
1226b40d79bcSmatt 		*lenp = PTN_MASK_BITLEN(mask);
1227b40d79bcSmatt 
1228b40d79bcSmatt 	return true;
1229b40d79bcSmatt }
1230