summaryrefslogtreecommitdiff
path: root/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch')
-rw-r--r--debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch1439
1 files changed, 0 insertions, 1439 deletions
diff --git a/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch b/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch
deleted file mode 100644
index 5f784ae8..00000000
--- a/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch
+++ /dev/null
@@ -1,1439 +0,0 @@
-From faf8b98c69b66785246651ed3852e98243b4db0c Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Mon, 19 May 2014 18:42:30 +0200
-Subject: [PATCH 11/27] librdxtree: add a radix tree implementation
-
-Radix trees offer search, insert, and delete operations in time linear
-in the size of the key. They are also very cache efficient.
-
-This is an verbatim copy from git://git.sceen.net/rbraun/librbraun.git
-as of 45fef4ad. Only macros.h has been slightly amended. This file
-defines two macros, which are also defined in cthreads.h. Undefine
-the macros first to work around this problem.
-
-* librdxtree/Makefile: New file.
-* librdxtree/rdxtree.c: Likewise.
-* librdxtree/rdxtree.h: Likewise.
-* librdxtree/rdxtree_i.h: Likewise.
-* librdxtree/error.c: Likewise.
-* librdxtree/error.h: Likewise.
-* librdxtree/macros.h: Likewise. Also, undefine MACRO_{BEGIN,END}.
-* Makefile (lib-subdirs): Add librdxtree.
----
- Makefile | 1 +
- librdxtree/Makefile | 27 ++
- librdxtree/error.c | 94 ++++++
- librdxtree/error.h | 84 +++++
- librdxtree/macros.h | 70 +++++
- librdxtree/rdxtree.c | 808 +++++++++++++++++++++++++++++++++++++++++++++++++
- librdxtree/rdxtree.h | 195 ++++++++++++
- librdxtree/rdxtree_i.h | 65 ++++
- 8 files changed, 1344 insertions(+)
- create mode 100644 librdxtree/Makefile
- create mode 100644 librdxtree/error.c
- create mode 100644 librdxtree/error.h
- create mode 100644 librdxtree/macros.h
- create mode 100644 librdxtree/rdxtree.c
- create mode 100644 librdxtree/rdxtree.h
- create mode 100644 librdxtree/rdxtree_i.h
-
-diff --git a/Makefile b/Makefile
-index 8a0be83..53dac72 100644
---- a/Makefile
-+++ b/Makefile
-@@ -48,6 +48,7 @@ other-subdirs = hurd doc config release include
-
- # XXX
- lib-subdirs += librbtree
-+lib-subdirs += librdxtree
-
- # All the subdirectories together
- subdirs = $(lib-subdirs) $(prog-subdirs) $(other-subdirs)
-diff --git a/librdxtree/Makefile b/librdxtree/Makefile
-new file mode 100644
-index 0000000..c9d3c9d
---- /dev/null
-+++ b/librdxtree/Makefile
-@@ -0,0 +1,27 @@
-+# Copyright (C) 2014 Free Software Foundation, Inc.
-+#
-+# This file is part of the GNU Hurd.
-+#
-+# The GNU Hurd is free software; you can redistribute it and/or
-+# modify it under the terms of the GNU General Public License as
-+# published by the Free Software Foundation; either version 2, or (at
-+# your option) any later version.
-+#
-+# The GNU Hurd is distributed in the hope that it will be useful, but
-+# WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+# General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
-+
-+dir := librdxtree
-+makemode := library
-+
-+libname := librdxtree
-+SRCS = rdxtree.c
-+installhdrs = rdxtree.h rdxtree_i.h macros.h
-+
-+OBJS = $(SRCS:.c=.o)
-+
-+include ../Makeconf
-diff --git a/librdxtree/error.c b/librdxtree/error.c
-new file mode 100644
-index 0000000..dcc574f
---- /dev/null
-+++ b/librdxtree/error.c
-@@ -0,0 +1,94 @@
-+/*
-+ * Copyright (c) 2009, 2010 Richard Braun.
-+ * 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 ``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 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.
-+ */
-+
-+#include <errno.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+
-+#include "error.h"
-+#include "macros.h"
-+
-+/*
-+ * Error message table.
-+ *
-+ * This table must be consistent with the enum defined in error.h.
-+ */
-+static const char *errormsg_table[] = {
-+ "success",
-+ "unknown error",
-+ "invalid argument",
-+ "not enough space",
-+ "invalid format",
-+ "not enough resources",
-+ "operation not permitted",
-+ "resource busy",
-+ "memory limit exceeded",
-+ "operation timed out",
-+ "operation would block",
-+ "entry not found",
-+ "internal memory allocator failure"
-+};
-+
-+#define ERRORMSG_TABLE_SIZE ARRAY_SIZE(errormsg_table)
-+
-+const char *
-+error_str(unsigned int error)
-+{
-+ if (error >= ERRORMSG_TABLE_SIZE)
-+ return "invalid error code";
-+
-+ return errormsg_table[error];
-+}
-+
-+unsigned int
-+error_from_errno(int errno_code)
-+{
-+ switch (errno_code) {
-+ case 0:
-+ return ERR_SUCCESS;
-+ case EINVAL:
-+ return ERR_INVAL;
-+ case ENOMEM:
-+ return ERR_NOMEM;
-+ case EAGAIN:
-+ return ERR_NORES;
-+ case EPERM:
-+ return ERR_PERM;
-+ case EBUSY:
-+ return ERR_BUSY;
-+ case ETIMEDOUT:
-+ return ERR_TIMEDOUT;
-+ default:
-+ fprintf(stderr, "unable to translate errno code (%d)\n", errno_code);
-+ return ERR_UNKNOWN;
-+ }
-+}
-+
-+void
-+error_die(unsigned int error)
-+{
-+ fprintf(stderr, "process terminating, reason: %s\n", error_str(error));
-+ abort();
-+}
-diff --git a/librdxtree/error.h b/librdxtree/error.h
-new file mode 100644
-index 0000000..81babf7
---- /dev/null
-+++ b/librdxtree/error.h
-@@ -0,0 +1,84 @@
-+/*
-+ * Copyright (c) 2009, 2010 Richard Braun.
-+ * 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 ``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 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 _ERROR_H
-+#define _ERROR_H
-+
-+#include "macros.h"
-+
-+/*
-+ * List of errors this library can return.
-+ *
-+ * ERR_SUCCESS is guaranteed to be 0, allowing code such as :
-+ *
-+ * error = do_smth();
-+ *
-+ * if (error) {
-+ * ...;
-+ * }
-+ */
-+enum {
-+ ERR_SUCCESS,
-+ ERR_UNKNOWN,
-+ ERR_INVAL,
-+ ERR_NOMEM,
-+ ERR_FORMAT,
-+ ERR_NORES,
-+ ERR_PERM,
-+ ERR_BUSY,
-+ ERR_MEMLIM,
-+ ERR_TIMEDOUT,
-+ ERR_WOULDBLOCK,
-+ ERR_LOOKUP,
-+ ERR_MEM_CACHE
-+};
-+
-+/*
-+ * Return the message matching the given error.
-+ *
-+ * The returned address points to a statically allocated, read only,
-+ * null-terminated string literal. The caller must not attempt to use it
-+ * for anything else than error reporting.
-+ */
-+const char * error_str(unsigned int error);
-+
-+/*
-+ * Map standard error codes to error values.
-+ *
-+ * This function accepts a subset of the standard error codes in errno.h.
-+ * When called, and if the errno value is handled, it will return the
-+ * corresponding ERR_xxx code. Otherwise ERR_UNKNOWN is returned.
-+ */
-+unsigned int error_from_errno(int errno_code);
-+
-+/*
-+ * Exit the current process, reporting an error.
-+ *
-+ * This function will report the given error and make the process exit,
-+ * using the error code as the exit() parameter.
-+ */
-+void __noreturn error_die(unsigned int error);
-+
-+#endif /* _ERROR_H */
-diff --git a/librdxtree/macros.h b/librdxtree/macros.h
-new file mode 100644
-index 0000000..f0960a3
---- /dev/null
-+++ b/librdxtree/macros.h
-@@ -0,0 +1,70 @@
-+/*
-+ * Copyright (c) 2009, 2010 Richard Braun.
-+ * 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 ``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 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.
-+ *
-+ *
-+ * Helper macros.
-+ */
-+
-+#ifndef _MACROS_H
-+#define _MACROS_H
-+
-+#include <stddef.h>
-+
-+#undef MACRO_BEGIN
-+#undef MACRO_END
-+#define MACRO_BEGIN ({
-+#define MACRO_END })
-+
-+#define XQUOTE(x) #x
-+#define QUOTE(x) XQUOTE(x)
-+
-+#define STRLEN(x) (sizeof(x) - 1)
-+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-+
-+#define MIN(a, b) ((a) < (b) ? (a) : (b))
-+#define MAX(a, b) ((a) > (b) ? (a) : (b))
-+
-+#define P2ALIGNED(x, a) (((x) & ((a) - 1)) == 0)
-+#define ISP2(x) P2ALIGNED(x, x)
-+#define P2ALIGN(x, a) ((x) & -(a))
-+#define P2ROUND(x, a) (-(-(x) & -(a)))
-+#define P2END(x, a) (-(~(x) & -(a)))
-+
-+#define structof(ptr, type, member) \
-+ ((type *)((char *)(ptr) - offsetof(type, member)))
-+
-+#define alignof(x) __alignof__(x)
-+
-+#define likely(expr) __builtin_expect(!!(expr), 1)
-+#define unlikely(expr) __builtin_expect(!!(expr), 0)
-+
-+#define barrier() asm volatile("" : : : "memory")
-+
-+#define __noreturn __attribute__((noreturn))
-+#define __aligned(x) __attribute__((aligned(x)))
-+
-+#define __format_printf(fmt, args) \
-+ __attribute__((format(printf, fmt, args)))
-+
-+#endif /* _MACROS_H */
-diff --git a/librdxtree/rdxtree.c b/librdxtree/rdxtree.c
-new file mode 100644
-index 0000000..36fd09f
---- /dev/null
-+++ b/librdxtree/rdxtree.c
-@@ -0,0 +1,808 @@
-+/*
-+ * Copyright (c) 2013 Richard Braun.
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation, either version 3 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/*
-+ * Copyright (c) 2011 Richard Braun.
-+ * 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 ``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 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.
-+ */
-+
-+#include <assert.h>
-+#include <limits.h>
-+#include <stddef.h>
-+#include <stdlib.h>
-+#include <string.h>
-+
-+#include "error.h"
-+#include "macros.h"
-+#include "rdxtree.h"
-+#include "rdxtree_i.h"
-+
-+/*
-+ * Mask applied on an entry to obtain its address.
-+ */
-+#define RDXTREE_ENTRY_ADDR_MASK (~0x3UL)
-+
-+/*
-+ * Global properties used to shape radix trees.
-+ */
-+#define RDXTREE_RADIX 6
-+#define RDXTREE_RADIX_SIZE (1UL << RDXTREE_RADIX)
-+#define RDXTREE_RADIX_MASK (RDXTREE_RADIX_SIZE - 1)
-+
-+#if RDXTREE_RADIX < 6
-+typedef unsigned long rdxtree_bm_t;
-+#define rdxtree_ffs(x) __builtin_ffsl(x)
-+#elif RDXTREE_RADIX == 6 /* RDXTREE_RADIX < 6 */
-+typedef unsigned long long rdxtree_bm_t;
-+#define rdxtree_ffs(x) __builtin_ffsll(x)
-+#else /* RDXTREE_RADIX < 6 */
-+#error "radix too high"
-+#endif /* RDXTREE_RADIX < 6 */
-+
-+/*
-+ * Allocation bitmap size in bits.
-+ */
-+#define RDXTREE_BM_SIZE (sizeof(rdxtree_bm_t) * CHAR_BIT)
-+
-+/*
-+ * Empty/full allocation bitmap words.
-+ */
-+#define RDXTREE_BM_EMPTY ((rdxtree_bm_t)0)
-+#define RDXTREE_BM_FULL \
-+ ((~(rdxtree_bm_t)0) >> (RDXTREE_BM_SIZE - RDXTREE_RADIX_SIZE))
-+
-+/*
-+ * These macros can be replaced by actual functions in an environment
-+ * that provides lockless synchronization such as RCU.
-+ */
-+#define llsync_assign_ptr(ptr, value) ((ptr) = (value))
-+#define llsync_read_ptr(ptr) (ptr)
-+
-+/*
-+ * Radix tree node.
-+ *
-+ * The height of a tree is the number of nodes to traverse until stored
-+ * pointers are reached. A height of 0 means the entries of a node (or the
-+ * tree root) directly point to stored pointers.
-+ *
-+ * The index is valid if and only if the parent isn't NULL.
-+ *
-+ * Concerning the allocation bitmap, a bit is set when the node it denotes,
-+ * or one of its children, can be used to allocate an entry. Conversely, a bit
-+ * is clear when the matching node and all of its children have no free entry.
-+ *
-+ * In order to support safe lockless lookups, in particular during a resize,
-+ * each node includes the height of its subtree, which is invariant during
-+ * the entire node lifetime. Since the tree height does vary, it can't be
-+ * used to determine whether the tree root is a node or a stored pointer.
-+ * This implementation assumes that all nodes and stored pointers are at least
-+ * 4-byte aligned, and uses the least significant bit of entries to indicate
-+ * the pointer type. This bit is set for internal nodes, and clear for stored
-+ * pointers so that they can be accessed from slots without conversion.
-+ */
-+struct rdxtree_node {
-+ struct rdxtree_node *parent;
-+ unsigned int index;
-+ unsigned int height;
-+ unsigned int nr_entries;
-+ rdxtree_bm_t alloc_bm;
-+ void *entries[RDXTREE_RADIX_SIZE];
-+};
-+
-+#ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES
-+unsigned int rdxtree_fail_node_creation_threshold;
-+unsigned int rdxtree_nr_node_creations;
-+#endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */
-+
-+static inline int
-+rdxtree_check_alignment(const void *ptr)
-+{
-+ return ((unsigned long)ptr & ~RDXTREE_ENTRY_ADDR_MASK) == 0;
-+}
-+
-+static inline void *
-+rdxtree_entry_addr(void *entry)
-+{
-+ return (void *)((unsigned long)entry & RDXTREE_ENTRY_ADDR_MASK);
-+}
-+
-+static inline int
-+rdxtree_entry_is_node(const void *entry)
-+{
-+ return ((unsigned long)entry & 1) != 0;
-+}
-+
-+static inline void *
-+rdxtree_node_to_entry(struct rdxtree_node *node)
-+{
-+ return (void *)((unsigned long)node | 1);
-+}
-+
-+static int
-+rdxtree_node_create(struct rdxtree_node **nodep, unsigned int height)
-+{
-+ struct rdxtree_node *node;
-+
-+#ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES
-+ if (rdxtree_fail_node_creation_threshold != 0) {
-+ rdxtree_nr_node_creations++;
-+
-+ if (rdxtree_nr_node_creations == rdxtree_fail_node_creation_threshold)
-+ return ERR_NOMEM;
-+ }
-+#endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */
-+
-+ node = malloc(sizeof(*node));
-+
-+ if (node == NULL)
-+ return ERR_NOMEM;
-+
-+ assert(rdxtree_check_alignment(node));
-+ node->parent = NULL;
-+ node->height = height;
-+ node->nr_entries = 0;
-+ node->alloc_bm = RDXTREE_BM_FULL;
-+ memset(node->entries, 0, sizeof(node->entries));
-+ *nodep = node;
-+ return 0;
-+}
-+
-+static void
-+rdxtree_node_schedule_destruction(struct rdxtree_node *node)
-+{
-+ /*
-+ * This function is intended to use the appropriate interface to defer
-+ * destruction until all read-side references are dropped in an
-+ * environment that provides lockless synchronization.
-+ *
-+ * Otherwise, it simply "schedules" destruction immediately.
-+ */
-+ free(node);
-+}
-+
-+static inline void
-+rdxtree_node_link(struct rdxtree_node *node, struct rdxtree_node *parent,
-+ unsigned int index)
-+{
-+ node->parent = parent;
-+ node->index = index;
-+}
-+
-+static inline void
-+rdxtree_node_unlink(struct rdxtree_node *node)
-+{
-+ assert(node->parent != NULL);
-+ node->parent = NULL;
-+}
-+
-+static inline int
-+rdxtree_node_full(struct rdxtree_node *node)
-+{
-+ return (node->nr_entries == ARRAY_SIZE(node->entries));
-+}
-+
-+static inline int
-+rdxtree_node_empty(struct rdxtree_node *node)
-+{
-+ return (node->nr_entries == 0);
-+}
-+
-+static inline void
-+rdxtree_node_insert(struct rdxtree_node *node, unsigned int index,
-+ void *entry)
-+{
-+ assert(index < ARRAY_SIZE(node->entries));
-+ assert(node->entries[index] == NULL);
-+
-+ node->nr_entries++;
-+ llsync_assign_ptr(node->entries[index], entry);
-+}
-+
-+static inline void
-+rdxtree_node_insert_node(struct rdxtree_node *node, unsigned int index,
-+ struct rdxtree_node *child)
-+{
-+ rdxtree_node_insert(node, index, rdxtree_node_to_entry(child));
-+}
-+
-+static inline void
-+rdxtree_node_remove(struct rdxtree_node *node, unsigned int index)
-+{
-+ assert(index < ARRAY_SIZE(node->entries));
-+ assert(node->entries[index] != NULL);
-+
-+ node->nr_entries--;
-+ llsync_assign_ptr(node->entries[index], NULL);
-+}
-+
-+static inline void *
-+rdxtree_node_find(struct rdxtree_node *node, unsigned int index, int get_slot)
-+{
-+ void *ptr;
-+
-+ while (index < ARRAY_SIZE(node->entries)) {
-+ ptr = rdxtree_entry_addr(node->entries[index]);
-+
-+ if (ptr != NULL)
-+ return get_slot ? (void *)&node->entries[index] : ptr;
-+
-+ index++;
-+ }
-+
-+ return NULL;
-+}
-+
-+static inline void
-+rdxtree_node_bm_set(struct rdxtree_node *node, unsigned int index)
-+{
-+ node->alloc_bm |= (rdxtree_bm_t)1 << index;
-+}
-+
-+static inline void
-+rdxtree_node_bm_clear(struct rdxtree_node *node, unsigned int index)
-+{
-+ node->alloc_bm &= ~((rdxtree_bm_t)1 << index);
-+}
-+
-+static inline int
-+rdxtree_node_bm_is_set(struct rdxtree_node *node, unsigned int index)
-+{
-+ return (node->alloc_bm & ((rdxtree_bm_t)1 << index));
-+}
-+
-+static inline int
-+rdxtree_node_bm_empty(struct rdxtree_node *node)
-+{
-+ return (node->alloc_bm == RDXTREE_BM_EMPTY);
-+}
-+
-+static inline unsigned int
-+rdxtree_node_bm_first(struct rdxtree_node *node)
-+{
-+ return rdxtree_ffs(node->alloc_bm) - 1;
-+}
-+
-+static inline unsigned long long
-+rdxtree_max_key(unsigned int height)
-+{
-+ size_t shift;
-+
-+ shift = RDXTREE_RADIX * height;
-+
-+ if (likely(shift < (sizeof(unsigned long long) * CHAR_BIT)))
-+ return (1ULL << shift) - 1;
-+ else
-+ return ~0ULL;
-+}
-+
-+static void
-+rdxtree_shrink(struct rdxtree *tree)
-+{
-+ struct rdxtree_node *node;
-+ void *entry;
-+
-+ while (tree->height > 0) {
-+ node = rdxtree_entry_addr(tree->root);
-+
-+ if (node->nr_entries != 1)
-+ break;
-+
-+ entry = node->entries[0];
-+
-+ if (entry == NULL)
-+ break;
-+
-+ tree->height--;
-+
-+ if (tree->height > 0)
-+ rdxtree_node_unlink(rdxtree_entry_addr(entry));
-+
-+ llsync_assign_ptr(tree->root, entry);
-+ rdxtree_node_schedule_destruction(node);
-+ }
-+}
-+
-+static int
-+rdxtree_grow(struct rdxtree *tree, unsigned long long key)
-+{
-+ struct rdxtree_node *root, *node;
-+ unsigned int new_height;
-+ int error;
-+
-+ new_height = tree->height + 1;
-+
-+ while (key > rdxtree_max_key(new_height))
-+ new_height++;
-+
-+ if (tree->root == NULL) {
-+ tree->height = new_height;
-+ return ERR_SUCCESS;
-+ }
-+
-+ root = rdxtree_entry_addr(tree->root);
-+
-+ do {
-+ error = rdxtree_node_create(&node, tree->height);
-+
-+ if (error) {
-+ rdxtree_shrink(tree);
-+ return error;
-+ }
-+
-+ if (tree->height == 0)
-+ rdxtree_node_bm_clear(node, 0);
-+ else {
-+ rdxtree_node_link(root, node, 0);
-+
-+ if (rdxtree_node_bm_empty(root))
-+ rdxtree_node_bm_clear(node, 0);
-+ }
-+
-+ rdxtree_node_insert(node, 0, tree->root);
-+ tree->height++;
-+ llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node));
-+ root = node;
-+ } while (new_height > tree->height);
-+
-+ return ERR_SUCCESS;
-+}
-+
-+static void
-+rdxtree_cleanup(struct rdxtree *tree, struct rdxtree_node *node)
-+{
-+ struct rdxtree_node *prev;
-+
-+ for (;;) {
-+ if (likely(!rdxtree_node_empty(node))) {
-+ if (unlikely(node->parent == NULL))
-+ rdxtree_shrink(tree);
-+
-+ break;
-+ }
-+
-+ if (node->parent == NULL) {
-+ tree->height = 0;
-+ llsync_assign_ptr(tree->root, NULL);
-+ rdxtree_node_schedule_destruction(node);
-+ break;
-+ }
-+
-+ prev = node;
-+ node = node->parent;
-+ rdxtree_node_unlink(prev);
-+ rdxtree_node_remove(node, prev->index);
-+ rdxtree_node_schedule_destruction(prev);
-+ }
-+}
-+
-+static void
-+rdxtree_insert_bm_clear(struct rdxtree_node *node, unsigned int index)
-+{
-+ for (;;) {
-+ rdxtree_node_bm_clear(node, index);
-+
-+ if (!rdxtree_node_full(node) || (node->parent == NULL))
-+ break;
-+
-+ index = node->index;
-+ node = node->parent;
-+ }
-+}
-+
-+int
-+rdxtree_insert_common(struct rdxtree *tree, unsigned long long key,
-+ void *ptr, void ***slotp)
-+{
-+ struct rdxtree_node *node, *prev;
-+ unsigned int height, shift, index = index;
-+ int error;
-+
-+ assert(ptr != NULL);
-+ assert(rdxtree_check_alignment(ptr));
-+
-+ if (unlikely(key > rdxtree_max_key(tree->height))) {
-+ error = rdxtree_grow(tree, key);
-+
-+ if (error)
-+ return error;
-+ }
-+
-+ height = tree->height;
-+
-+ if (unlikely(height == 0)) {
-+ if (tree->root != NULL)
-+ return ERR_BUSY;
-+
-+ llsync_assign_ptr(tree->root, ptr);
-+
-+ if (slotp != NULL)
-+ *slotp = &tree->root;
-+
-+ return ERR_SUCCESS;
-+ }
-+
-+ node = rdxtree_entry_addr(tree->root);
-+ shift = (height - 1) * RDXTREE_RADIX;
-+ prev = NULL;
-+
-+ do {
-+ if (node == NULL) {
-+ error = rdxtree_node_create(&node, height - 1);
-+
-+ if (error) {
-+ if (prev == NULL)
-+ tree->height = 0;
-+ else
-+ rdxtree_cleanup(tree, prev);
-+
-+ return error;
-+ }
-+
-+ if (prev == NULL)
-+ llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node));
-+ else {
-+ rdxtree_node_link(node, prev, index);
-+ rdxtree_node_insert_node(prev, index, node);
-+ }
-+ }
-+
-+ prev = node;
-+ index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
-+ node = rdxtree_entry_addr(prev->entries[index]);
-+ shift -= RDXTREE_RADIX;
-+ height--;
-+ } while (height > 0);
-+
-+ if (unlikely(node != NULL))
-+ return ERR_BUSY;
-+
-+ rdxtree_node_insert(prev, index, ptr);
-+ rdxtree_insert_bm_clear(prev, index);
-+
-+ if (slotp != NULL)
-+ *slotp = &prev->entries[index];
-+
-+ return ERR_SUCCESS;
-+}
-+
-+int
-+rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr,
-+ unsigned long long *keyp, void ***slotp)
-+{
-+ struct rdxtree_node *node, *prev;
-+ unsigned long long key;
-+ unsigned int height, shift, index = index;
-+ int error;
-+
-+ assert(ptr != NULL);
-+ assert(rdxtree_check_alignment(ptr));
-+
-+ height = tree->height;
-+
-+ if (unlikely(height == 0)) {
-+ if (tree->root == NULL) {
-+ llsync_assign_ptr(tree->root, ptr);
-+ *keyp = 0;
-+
-+ if (slotp != NULL)
-+ *slotp = &tree->root;
-+
-+ return ERR_SUCCESS;
-+ }
-+
-+ goto grow;
-+ }
-+
-+ node = rdxtree_entry_addr(tree->root);
-+ key = 0;
-+ shift = (height - 1) * RDXTREE_RADIX;
-+ prev = NULL;
-+
-+ do {
-+ if (node == NULL) {
-+ error = rdxtree_node_create(&node, height - 1);
-+
-+ if (error) {
-+ rdxtree_cleanup(tree, prev);
-+ return error;
-+ }
-+
-+ rdxtree_node_link(node, prev, index);
-+ rdxtree_node_insert_node(prev, index, node);
-+ }
-+
-+ prev = node;
-+ index = rdxtree_node_bm_first(node);
-+
-+ if (index == (unsigned int)-1)
-+ goto grow;
-+
-+ key |= (unsigned long long)index << shift;
-+ node = rdxtree_entry_addr(node->entries[index]);
-+ shift -= RDXTREE_RADIX;
-+ height--;
-+ } while (height > 0);
-+
-+ rdxtree_node_insert(prev, index, ptr);
-+ rdxtree_insert_bm_clear(prev, index);
-+
-+ if (slotp != NULL)
-+ *slotp = &prev->entries[index];
-+
-+ goto out;
-+
-+grow:
-+ key = rdxtree_max_key(height) + 1;
-+ error = rdxtree_insert_common(tree, key, ptr, slotp);
-+
-+ if (error)
-+ return error;
-+
-+out:
-+ *keyp = key;
-+ return ERR_SUCCESS;
-+}
-+
-+static void
-+rdxtree_remove_bm_set(struct rdxtree_node *node, unsigned int index)
-+{
-+ do {
-+ rdxtree_node_bm_set(node, index);
-+
-+ if (node->parent == NULL)
-+ break;
-+
-+ index = node->index;
-+ node = node->parent;
-+ } while (!rdxtree_node_bm_is_set(node, index));
-+}
-+
-+void *
-+rdxtree_remove(struct rdxtree *tree, unsigned long long key)
-+{
-+ struct rdxtree_node *node, *prev;
-+ unsigned int height, shift, index;
-+
-+ height = tree->height;
-+
-+ if (unlikely(key > rdxtree_max_key(height)))
-+ return NULL;
-+
-+ node = rdxtree_entry_addr(tree->root);
-+
-+ if (unlikely(height == 0)) {
-+ llsync_assign_ptr(tree->root, NULL);
-+ return node;
-+ }
-+
-+ shift = (height - 1) * RDXTREE_RADIX;
-+
-+ do {
-+ if (node == NULL)
-+ return NULL;
-+
-+ prev = node;
-+ index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
-+ node = rdxtree_entry_addr(node->entries[index]);
-+ shift -= RDXTREE_RADIX;
-+ height--;
-+ } while (height > 0);
-+
-+ if (node == NULL)
-+ return NULL;
-+
-+ rdxtree_node_remove(prev, index);
-+ rdxtree_remove_bm_set(prev, index);
-+ rdxtree_cleanup(tree, prev);
-+ return node;
-+}
-+
-+void *
-+rdxtree_lookup_common(const struct rdxtree *tree, unsigned long long key,
-+ int get_slot)
-+{
-+ struct rdxtree_node *node, *prev;
-+ unsigned int height, shift, index;
-+ void *entry;
-+
-+ entry = llsync_read_ptr(tree->root);
-+
-+ if (entry == NULL) {
-+ node = NULL;
-+ height = 0;
-+ } else {
-+ node = rdxtree_entry_addr(entry);
-+ height = rdxtree_entry_is_node(entry) ? node->height + 1 : 0;
-+ }
-+
-+ if (key > rdxtree_max_key(height))
-+ return NULL;
-+
-+ if (height == 0) {
-+ if (node == NULL)
-+ return NULL;
-+
-+ return get_slot ? (void *)&tree->root : node;
-+ }
-+
-+ shift = (height - 1) * RDXTREE_RADIX;
-+
-+ do {
-+ if (node == NULL)
-+ return NULL;
-+
-+ prev = node;
-+ index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
-+ entry = llsync_read_ptr(node->entries[index]);
-+ node = rdxtree_entry_addr(entry);
-+ shift -= RDXTREE_RADIX;
-+ height--;
-+ } while (height > 0);
-+
-+ if (node == NULL)
-+ return NULL;
-+
-+ return get_slot ? (void *)&prev->entries[index] : node;
-+}
-+
-+void *
-+rdxtree_replace_slot(void **slot, void *ptr)
-+{
-+ void *old;
-+
-+ assert(ptr != NULL);
-+ assert(rdxtree_check_alignment(ptr));
-+
-+ old = *slot;
-+ assert(old != NULL);
-+ assert(rdxtree_check_alignment(old));
-+ llsync_assign_ptr(*slot, ptr);
-+ return old;
-+}
-+
-+static struct rdxtree_node *
-+rdxtree_walk(struct rdxtree *tree, struct rdxtree_node *node)
-+{
-+ struct rdxtree_node *prev, *child;
-+ unsigned int height, index;
-+
-+ if (node == NULL) {
-+ height = tree->height;
-+ node = rdxtree_entry_addr(tree->root);
-+
-+ while (height > 1) {
-+ node = rdxtree_node_find(node, 0, 0);
-+ height--;
-+ }
-+
-+ return node;
-+ }
-+
-+ height = 0;
-+
-+ for (;;) {
-+ prev = node->parent;
-+
-+ if (prev == NULL)
-+ return NULL;
-+
-+ index = node->index;
-+ child = rdxtree_node_find(prev, index + 1, 0);
-+
-+ if (child != NULL)
-+ break;
-+
-+ height++;
-+ node = prev;
-+ }
-+
-+ node = child;
-+
-+ while (height > 0) {
-+ node = rdxtree_node_find(node, 0, 0);
-+ height--;
-+ }
-+
-+ return node;
-+}
-+
-+void *
-+rdxtree_iter_next(struct rdxtree *tree, struct rdxtree_iter *iter)
-+{
-+ unsigned int index;
-+
-+ if (tree->height == 0) {
-+ if (iter->slot != NULL)
-+ return NULL;
-+
-+ iter->slot = &tree->root;
-+ return *iter->slot;
-+ }
-+
-+ if (iter->node != NULL) {
-+ index = iter->slot - ((struct rdxtree_node *)iter->node)->entries;
-+ iter->slot = rdxtree_node_find(iter->node, index + 1, 1);
-+ }
-+
-+ if (iter->slot == NULL) {
-+ iter->node = rdxtree_walk(tree, iter->node);
-+
-+ if (iter->node != NULL)
-+ iter->slot = rdxtree_node_find(iter->node, 0, 1);
-+ }
-+
-+ if (iter->slot == NULL)
-+ return NULL;
-+
-+ return *iter->slot;
-+}
-+
-+void
-+rdxtree_remove_all(struct rdxtree *tree)
-+{
-+ struct rdxtree_node *node, *parent, *next;
-+ unsigned int height, index;
-+
-+ height = tree->height;
-+
-+ if (height == 0) {
-+ if (tree->root != NULL)
-+ llsync_assign_ptr(tree->root, NULL);
-+
-+ return;
-+ }
-+
-+ node = rdxtree_walk(tree, NULL);
-+
-+ do {
-+ next = rdxtree_walk(tree, node);
-+
-+ parent = node->parent;
-+
-+ if (parent != NULL) {
-+ index = node->index;
-+ rdxtree_node_remove(parent, index);
-+ rdxtree_remove_bm_set(parent, index);
-+ rdxtree_cleanup(tree, parent);
-+ node->parent = NULL;
-+ }
-+
-+ rdxtree_node_schedule_destruction(node);
-+
-+ node = next;
-+ } while (node != NULL);
-+}
-diff --git a/librdxtree/rdxtree.h b/librdxtree/rdxtree.h
-new file mode 100644
-index 0000000..8ccfa25
---- /dev/null
-+++ b/librdxtree/rdxtree.h
-@@ -0,0 +1,195 @@
-+/*
-+ * Copyright (c) 2013 Richard Braun.
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation, either version 3 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/*
-+ * Copyright (c) 2011 Richard Braun.
-+ * 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 ``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 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.
-+ *
-+ *
-+ * Radix tree.
-+ *
-+ * In addition to the standard insertion operation, this implementation
-+ * can allocate keys for the caller at insertion time.
-+ */
-+
-+#ifndef _RDXTREE_H
-+#define _RDXTREE_H
-+
-+#include <stddef.h>
-+
-+/*
-+ * Radix tree.
-+ */
-+struct rdxtree;
-+
-+/*
-+ * Radix tree iterator.
-+ */
-+struct rdxtree_iter;
-+
-+/*
-+ * Static tree initializer.
-+ */
-+#define RDXTREE_INITIALIZER { 0, NULL }
-+
-+#include "rdxtree_i.h"
-+
-+/*
-+ * Initialize a tree.
-+ */
-+static inline void
-+rdxtree_init(struct rdxtree *tree)
-+{
-+ tree->height = 0;
-+ tree->root = NULL;
-+}
-+
-+/*
-+ * Insert a pointer in a tree.
-+ *
-+ * The ptr parameter must not be NULL.
-+ */
-+static inline int
-+rdxtree_insert(struct rdxtree *tree, unsigned long long key, void *ptr)
-+{
-+ return rdxtree_insert_common(tree, key, ptr, NULL);
-+}
-+
-+/*
-+ * Insert a pointer in a tree and obtain its slot.
-+ *
-+ * The ptr and slotp parameters must not be NULL. If successful, the slot of
-+ * the newly inserted pointer is stored at the address pointed to by the slotp
-+ * parameter.
-+ */
-+static inline int
-+rdxtree_insert_slot(struct rdxtree *tree, unsigned long long key, void *ptr,
-+ void ***slotp)
-+{
-+ return rdxtree_insert_common(tree, key, ptr, slotp);
-+}
-+
-+/*
-+ * Insert a pointer in a tree, for which a new key is allocated.
-+ *
-+ * The ptr and keyp parameters must not be NULL. The newly allocated key is
-+ * stored at the address pointed to by the keyp parameter.
-+ */
-+static inline int
-+rdxtree_insert_alloc(struct rdxtree *tree, void *ptr, unsigned long long *keyp)
-+{
-+ return rdxtree_insert_alloc_common(tree, ptr, keyp, NULL);
-+}
-+
-+/*
-+ * Insert a pointer in a tree, for which a new key is allocated, and obtain
-+ * its slot.
-+ *
-+ * The ptr, keyp and slotp parameters must not be NULL. The newly allocated
-+ * key is stored at the address pointed to by the keyp parameter while the
-+ * slot of the inserted pointer is stored at the address pointed to by the
-+ * slotp parameter.
-+ */
-+static inline int
-+rdxtree_insert_alloc_slot(struct rdxtree *tree, void *ptr,
-+ unsigned long long *keyp, void ***slotp)
-+{
-+ return rdxtree_insert_alloc_common(tree, ptr, keyp, slotp);
-+}
-+
-+/*
-+ * Remove a pointer from a tree.
-+ *
-+ * The matching pointer is returned if successful, NULL otherwise.
-+ */
-+void * rdxtree_remove(struct rdxtree *tree, unsigned long long key);
-+
-+/*
-+ * Look up a pointer in a tree.
-+ *
-+ * The matching pointer is returned if successful, NULL otherwise.
-+ */
-+static inline void *
-+rdxtree_lookup(const struct rdxtree *tree, unsigned long long key)
-+{
-+ return rdxtree_lookup_common(tree, key, 0);
-+}
-+
-+/*
-+ * Look up a slot in a tree.
-+ *
-+ * A slot is a pointer to a stored pointer in a tree. It can be used as
-+ * a placeholder for fast replacements to avoid multiple lookups on the same
-+ * key.
-+ *
-+ * A slot for the matching pointer is returned if successful, NULL otherwise.
-+ *
-+ * See rdxtree_replace_slot().
-+ */
-+static inline void **
-+rdxtree_lookup_slot(const struct rdxtree *tree, unsigned long long key)
-+{
-+ return rdxtree_lookup_common(tree, key, 1);
-+}
-+
-+/*
-+ * Replace a pointer in a tree.
-+ *
-+ * The ptr parameter must not be NULL. The previous pointer is returned.
-+ *
-+ * See rdxtree_lookup_slot().
-+ */
-+void * rdxtree_replace_slot(void **slot, void *ptr);
-+
-+/*
-+ * Forge a loop to process all pointers of a tree.
-+ */
-+#define rdxtree_for_each(tree, iter, ptr) \
-+for (rdxtree_iter_init(iter), ptr = rdxtree_iter_next(tree, iter); \
-+ ptr != NULL; \
-+ ptr = rdxtree_iter_next(tree, iter))
-+
-+/*
-+ * Remove all pointers from a tree.
-+ *
-+ * The common way to destroy a tree and its pointers is to loop over all
-+ * the pointers using rdxtree_for_each(), freeing them, then call this
-+ * function.
-+ */
-+void rdxtree_remove_all(struct rdxtree *tree);
-+
-+#endif /* _RDXTREE_H */
-diff --git a/librdxtree/rdxtree_i.h b/librdxtree/rdxtree_i.h
-new file mode 100644
-index 0000000..4761beb
---- /dev/null
-+++ b/librdxtree/rdxtree_i.h
-@@ -0,0 +1,65 @@
-+/*
-+ * Copyright (c) 2013 Richard Braun.
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation, either version 3 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef _RDXTREE_I_H
-+#define _RDXTREE_I_H
-+
-+/*
-+ * Radix tree.
-+ */
-+struct rdxtree {
-+ unsigned int height;
-+ void *root;
-+};
-+
-+/*
-+ * Radix tree iterator.
-+ */
-+struct rdxtree_iter {
-+ void *node;
-+ void **slot;
-+};
-+
-+/*
-+ * Initialize an iterator.
-+ */
-+static inline void
-+rdxtree_iter_init(struct rdxtree_iter *iter)
-+{
-+ iter->node = NULL;
-+ iter->slot = NULL;
-+}
-+
-+int rdxtree_insert_common(struct rdxtree *tree, unsigned long long key,
-+ void *ptr, void ***slotp);
-+
-+int rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr,
-+ unsigned long long *keyp, void ***slotp);
-+
-+void * rdxtree_lookup_common(const struct rdxtree *tree, unsigned long long key,
-+ int get_slot);
-+
-+/*
-+ * Walk over pointers in a tree.
-+ *
-+ * Move the iterator to the next pointer in the given tree.
-+ *
-+ * The next pointer is returned if there is one, NULL otherwise.
-+ */
-+void * rdxtree_iter_next(struct rdxtree *tree, struct rdxtree_iter *iter);
-+
-+#endif /* _RDXTREE_I_H */
---
-2.0.0.rc2
-