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