/*- * Copyright (c) 2019 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CRADIX_H #define CRADIX_H #ifdef _KERNEL #include #include #else #include #include #include #include #endif #ifdef _LP64 #define CRADIX_CHUNK_SIZE 5u typedef uint32_t cradix_bitmap_t; #else #define CRADIX_CHUNK_SIZE 4u typedef uint16_t cradix_bitmap_t; #endif #define CRADIX_MAX_FANOUT (1u << CRADIX_CHUNK_SIZE) #define CRADIX_CHUNK_MASK (CRADIX_MAX_FANOUT - 1) /* * Chunk indices are stored in 8 bits in branch nodes, so there can be * up to 256 chunks per key. For the smallest chunk size, 4 bits, 256 * chunks is 1024 bits = 128 bytes. */ #define CRADIX_MAX_KEYLEN 128u struct cradix_ops; struct cradix { const struct cradix_ops *ops; uintptr_t root; }; /* * Should be treated as opaque; used only for alignment and * type-checking. */ struct cradix_node { } __aligned(2); /* Opaque; allocated via the allocator. */ struct cradix_branch; struct cradix_ops { unsigned keylen; const void * (*key)(const struct cradix *, const struct cradix_node *); void * (*alloc)(struct cradix *, size_t); void (*free)(struct cradix *, void *, size_t); void (*recycle)(struct cradix *, void *, size_t); }; void cradix_init(struct cradix *, const struct cradix_ops *); void cradix_destroy(struct cradix *); bool cradix_empty(const struct cradix *); struct cradix_node * cradix_lookup(const struct cradix *, const void *); struct cradix_node * cradix_min(const struct cradix *); struct cradix_node * cradix_max(const struct cradix *); struct cradix_node * cradix_min_prefix(const struct cradix *, const void *, size_t); struct cradix_node * cradix_max_prefix(const struct cradix *, const void *, size_t); struct cradix_insert { struct cradix_branch *alloc[CRADIX_CHUNK_SIZE]; struct cradix_branch *recycle; }; bool cradix_insert_begin(struct cradix *, struct cradix_insert *); void cradix_insert_end(struct cradix *, struct cradix_insert *); struct cradix_node * cradix_insert(struct cradix *, struct cradix_node *, struct cradix_insert *); struct cradix_delete { struct cradix_branch *recycle; }; void cradix_delete_begin(struct cradix *, struct cradix_delete *); void cradix_delete_end(struct cradix *, struct cradix_delete *); void cradix_delete(struct cradix *, struct cradix_node *, struct cradix_delete *); struct cradix_node * cradix_delete_key(struct cradix *, const void *, struct cradix_delete *); struct cradix_iter { struct cradix *cradix; cradix_bitmap_t submask; const struct cradix_branch **branchstack; uint8_t *chunkstack; unsigned depth; unsigned maxdepth; }; #define CRADIX_ITER_STACKDEPTH(KEYLEN) \ ((CHAR_BIT*(KEYLEN) + CRADIX_CHUNK_SIZE - 1) / CRADIX_CHUNK_SIZE) #define CRADIX_ITER_STACKTYPE(KEYLEN) \ struct { \ const struct cradix_branch * \ branchstack[CRADIX_ITER_STACKDEPTH(KEYLEN)]; \ uint8_t chunkstack[CRADIX_ITER_STACKDEPTH(KEYLEN)]; \ } #define CRADIX_ITER_STACKSIZE(KEYLEN) sizeof(CRADIX_ITER_STACKTYPE(KEYLEN)) #define CRADIX_ITER_ALIGNED __attribute__((__aligned__(sizeof(void *)))) #ifdef _LP64 __CTASSERT(CRADIX_ITER_STACKSIZE(CRADIX_MAX_KEYLEN) == 1848); #else __CTASSERT(CRADIX_ITER_STACKSIZE(CRADIX_MAX_KEYLEN) == 1280); #endif #define CRADIX_ITER_STACK(NAME, KEYLEN) \ CRADIX_ITER_STACKTYPE(KEYLEN) NAME[1] /* Alternatively: char NAME[CRADIX_ITER_STACKSIZE(KEYLEN)] CRADIX_ITER_ALIGNED */ void cradix_iter_init(struct cradix *, struct cradix_iter *, void *, size_t); void cradix_iter_destroy(struct cradix *, struct cradix_iter *); bool cradix_iter_begin(struct cradix *, struct cradix_iter *); void cradix_iter_end(struct cradix *, struct cradix_iter *); struct cradix_node * cradix_iter_min(struct cradix *, struct cradix_iter *); struct cradix_node * cradix_iter_max(struct cradix *, struct cradix_iter *); struct cradix_node * cradix_iter_min_prefix(struct cradix *, struct cradix_iter *, const void *, size_t); struct cradix_node * cradix_iter_max_prefix(struct cradix *, struct cradix_iter *, const void *, size_t); struct cradix_node * cradix_iter_next(struct cradix *, struct cradix_iter *); struct cradix_node * cradix_iter_prev(struct cradix *, struct cradix_iter *); void cradix_dump(const struct cradix *); #endif /* CRADIX_H */