xref: /freebsd/contrib/ldns/radix.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
117d15b25SDag-Erling Smørgrav /*
217d15b25SDag-Erling Smørgrav  * radix.c -- generic radix tree
317d15b25SDag-Erling Smørgrav  *
417d15b25SDag-Erling Smørgrav  * Taken from NSD4, modified for ldns
517d15b25SDag-Erling Smørgrav  *
617d15b25SDag-Erling Smørgrav  * Copyright (c) 2012, NLnet Labs. All rights reserved.
717d15b25SDag-Erling Smørgrav  *
817d15b25SDag-Erling Smørgrav  * This software is open source.
917d15b25SDag-Erling Smørgrav  *
1017d15b25SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
1117d15b25SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
1217d15b25SDag-Erling Smørgrav  * are met:
1317d15b25SDag-Erling Smørgrav  *
1417d15b25SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
1517d15b25SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
1617d15b25SDag-Erling Smørgrav  *
1717d15b25SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
1817d15b25SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
1917d15b25SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
2017d15b25SDag-Erling Smørgrav  *
2117d15b25SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
2217d15b25SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
2317d15b25SDag-Erling Smørgrav  * specific prior written permission.
2417d15b25SDag-Erling Smørgrav  *
2517d15b25SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26986ba33cSDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27986ba33cSDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28986ba33cSDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29986ba33cSDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30986ba33cSDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
31986ba33cSDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32986ba33cSDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33986ba33cSDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34986ba33cSDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35986ba33cSDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3617d15b25SDag-Erling Smørgrav  *
3717d15b25SDag-Erling Smørgrav  */
3817d15b25SDag-Erling Smørgrav 
3917d15b25SDag-Erling Smørgrav /**
4017d15b25SDag-Erling Smørgrav  * \file
4117d15b25SDag-Erling Smørgrav  * Implementation of a radix tree.
4217d15b25SDag-Erling Smørgrav  */
4317d15b25SDag-Erling Smørgrav 
4417d15b25SDag-Erling Smørgrav #include <ldns/config.h>
4517d15b25SDag-Erling Smørgrav #include <ldns/radix.h>
4617d15b25SDag-Erling Smørgrav #include <ldns/util.h>
4717d15b25SDag-Erling Smørgrav #include <stdlib.h>
4817d15b25SDag-Erling Smørgrav 
4917d15b25SDag-Erling Smørgrav /** Helper functions */
5017d15b25SDag-Erling Smørgrav static ldns_radix_node_t* ldns_radix_new_node(void* data, uint8_t* key,
5117d15b25SDag-Erling Smørgrav 	radix_strlen_t len);
5217d15b25SDag-Erling Smørgrav static int ldns_radix_find_prefix(ldns_radix_t* tree, uint8_t* key,
5317d15b25SDag-Erling Smørgrav 	radix_strlen_t len, ldns_radix_node_t** result, radix_strlen_t* pos);
5417d15b25SDag-Erling Smørgrav static int ldns_radix_array_space(ldns_radix_node_t* node, uint8_t byte);
5517d15b25SDag-Erling Smørgrav static int ldns_radix_array_grow(ldns_radix_node_t* node, unsigned need);
5617d15b25SDag-Erling Smørgrav static int ldns_radix_str_create(ldns_radix_array_t* array, uint8_t* key,
5717d15b25SDag-Erling Smørgrav 	radix_strlen_t pos, radix_strlen_t len);
5817d15b25SDag-Erling Smørgrav static int ldns_radix_prefix_remainder(radix_strlen_t prefix_len,
5917d15b25SDag-Erling Smørgrav 	uint8_t* longer_str, radix_strlen_t longer_len, uint8_t** split_str,
6017d15b25SDag-Erling Smørgrav 	radix_strlen_t* split_len);
6117d15b25SDag-Erling Smørgrav static int ldns_radix_array_split(ldns_radix_array_t* array, uint8_t* key,
6217d15b25SDag-Erling Smørgrav 	radix_strlen_t pos, radix_strlen_t len, ldns_radix_node_t* add);
6317d15b25SDag-Erling Smørgrav static int ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1,
6417d15b25SDag-Erling Smørgrav 	uint8_t* str2, radix_strlen_t len2);
6517d15b25SDag-Erling Smørgrav static radix_strlen_t ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1,
6617d15b25SDag-Erling Smørgrav 	uint8_t* str2, radix_strlen_t len2);
6717d15b25SDag-Erling Smørgrav static ldns_radix_node_t* ldns_radix_next_in_subtree(ldns_radix_node_t* node);
6817d15b25SDag-Erling Smørgrav static ldns_radix_node_t* ldns_radix_prev_from_index(ldns_radix_node_t* node,
6917d15b25SDag-Erling Smørgrav 	uint8_t index);
7017d15b25SDag-Erling Smørgrav static ldns_radix_node_t* ldns_radix_last_in_subtree_incl_self(
7117d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* node);
7217d15b25SDag-Erling Smørgrav static ldns_radix_node_t* ldns_radix_last_in_subtree(ldns_radix_node_t* node);
7317d15b25SDag-Erling Smørgrav static void ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node);
7417d15b25SDag-Erling Smørgrav static void ldns_radix_cleanup_onechild(ldns_radix_node_t* node);
7517d15b25SDag-Erling Smørgrav static void ldns_radix_cleanup_leaf(ldns_radix_node_t* node);
7617d15b25SDag-Erling Smørgrav static void ldns_radix_node_free(ldns_radix_node_t* node, void* arg);
7717d15b25SDag-Erling Smørgrav static void ldns_radix_node_array_free(ldns_radix_node_t* node);
7817d15b25SDag-Erling Smørgrav static void ldns_radix_node_array_free_front(ldns_radix_node_t* node);
7917d15b25SDag-Erling Smørgrav static void ldns_radix_node_array_free_end(ldns_radix_node_t* node);
8017d15b25SDag-Erling Smørgrav static void ldns_radix_array_reduce(ldns_radix_node_t* node);
8117d15b25SDag-Erling Smørgrav static void ldns_radix_self_or_prev(ldns_radix_node_t* node,
8217d15b25SDag-Erling Smørgrav 	ldns_radix_node_t** result);
8317d15b25SDag-Erling Smørgrav 
8417d15b25SDag-Erling Smørgrav 
8517d15b25SDag-Erling Smørgrav /**
8617d15b25SDag-Erling Smørgrav  * Create a new radix node.
8717d15b25SDag-Erling Smørgrav  *
8817d15b25SDag-Erling Smørgrav  */
8917d15b25SDag-Erling Smørgrav static ldns_radix_node_t*
ldns_radix_new_node(void * data,uint8_t * key,radix_strlen_t len)9017d15b25SDag-Erling Smørgrav ldns_radix_new_node(void* data, uint8_t* key, radix_strlen_t len)
9117d15b25SDag-Erling Smørgrav {
9217d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* node = LDNS_MALLOC(ldns_radix_node_t);
9317d15b25SDag-Erling Smørgrav 	if (!node) {
9417d15b25SDag-Erling Smørgrav 		return NULL;
9517d15b25SDag-Erling Smørgrav 	}
9617d15b25SDag-Erling Smørgrav 	node->data = data;
9717d15b25SDag-Erling Smørgrav 	node->key = key;
9817d15b25SDag-Erling Smørgrav 	node->klen = len;
9917d15b25SDag-Erling Smørgrav 	node->parent = NULL;
10017d15b25SDag-Erling Smørgrav 	node->parent_index = 0;
10117d15b25SDag-Erling Smørgrav 	node->len = 0;
10217d15b25SDag-Erling Smørgrav 	node->offset = 0;
10317d15b25SDag-Erling Smørgrav 	node->capacity = 0;
10417d15b25SDag-Erling Smørgrav 	node->array = NULL;
10517d15b25SDag-Erling Smørgrav 	return node;
10617d15b25SDag-Erling Smørgrav }
10717d15b25SDag-Erling Smørgrav 
10817d15b25SDag-Erling Smørgrav 
10917d15b25SDag-Erling Smørgrav /**
11017d15b25SDag-Erling Smørgrav  * Create a new radix tree.
11117d15b25SDag-Erling Smørgrav  *
11217d15b25SDag-Erling Smørgrav  */
11317d15b25SDag-Erling Smørgrav ldns_radix_t *
ldns_radix_create(void)11417d15b25SDag-Erling Smørgrav ldns_radix_create(void)
11517d15b25SDag-Erling Smørgrav {
11617d15b25SDag-Erling Smørgrav 	ldns_radix_t* tree;
11717d15b25SDag-Erling Smørgrav 
11817d15b25SDag-Erling Smørgrav 	/** Allocate memory for it */
11917d15b25SDag-Erling Smørgrav 	tree = (ldns_radix_t *) LDNS_MALLOC(ldns_radix_t);
12017d15b25SDag-Erling Smørgrav 	if (!tree) {
12117d15b25SDag-Erling Smørgrav 		return NULL;
12217d15b25SDag-Erling Smørgrav 	}
12317d15b25SDag-Erling Smørgrav 	/** Initialize it */
12417d15b25SDag-Erling Smørgrav 	ldns_radix_init(tree);
12517d15b25SDag-Erling Smørgrav 	return tree;
12617d15b25SDag-Erling Smørgrav }
12717d15b25SDag-Erling Smørgrav 
12817d15b25SDag-Erling Smørgrav 
12917d15b25SDag-Erling Smørgrav /**
13017d15b25SDag-Erling Smørgrav  * Initialize radix tree.
13117d15b25SDag-Erling Smørgrav  *
13217d15b25SDag-Erling Smørgrav  */
13317d15b25SDag-Erling Smørgrav void
ldns_radix_init(ldns_radix_t * tree)13417d15b25SDag-Erling Smørgrav ldns_radix_init(ldns_radix_t* tree)
13517d15b25SDag-Erling Smørgrav {
13617d15b25SDag-Erling Smørgrav 	/** Initialize it */
13717d15b25SDag-Erling Smørgrav 	if (tree) {
13817d15b25SDag-Erling Smørgrav 		tree->root = NULL;
13917d15b25SDag-Erling Smørgrav 		tree->count = 0;
14017d15b25SDag-Erling Smørgrav 	}
14117d15b25SDag-Erling Smørgrav 	return;
14217d15b25SDag-Erling Smørgrav }
14317d15b25SDag-Erling Smørgrav 
14417d15b25SDag-Erling Smørgrav 
14517d15b25SDag-Erling Smørgrav /**
14617d15b25SDag-Erling Smørgrav  * Free radix tree.
14717d15b25SDag-Erling Smørgrav  *
14817d15b25SDag-Erling Smørgrav  */
14917d15b25SDag-Erling Smørgrav void
ldns_radix_free(ldns_radix_t * tree)15017d15b25SDag-Erling Smørgrav ldns_radix_free(ldns_radix_t* tree)
15117d15b25SDag-Erling Smørgrav {
15217d15b25SDag-Erling Smørgrav 	if (tree) {
15317d15b25SDag-Erling Smørgrav 		if (tree->root) {
15417d15b25SDag-Erling Smørgrav 			ldns_radix_traverse_postorder(tree->root,
15517d15b25SDag-Erling Smørgrav 				ldns_radix_node_free, NULL);
15617d15b25SDag-Erling Smørgrav 		}
15717d15b25SDag-Erling Smørgrav 		LDNS_FREE(tree);
15817d15b25SDag-Erling Smørgrav 	}
15917d15b25SDag-Erling Smørgrav 	return;
16017d15b25SDag-Erling Smørgrav }
16117d15b25SDag-Erling Smørgrav 
16217d15b25SDag-Erling Smørgrav 
16317d15b25SDag-Erling Smørgrav /**
16417d15b25SDag-Erling Smørgrav  * Insert data into the tree.
16517d15b25SDag-Erling Smørgrav  *
16617d15b25SDag-Erling Smørgrav  */
16717d15b25SDag-Erling Smørgrav ldns_status
ldns_radix_insert(ldns_radix_t * tree,uint8_t * key,radix_strlen_t len,void * data)16817d15b25SDag-Erling Smørgrav ldns_radix_insert(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len,
16917d15b25SDag-Erling Smørgrav 	void* data)
17017d15b25SDag-Erling Smørgrav {
17117d15b25SDag-Erling Smørgrav 	radix_strlen_t pos = 0;
17217d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* add = NULL;
17317d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* prefix = NULL;
17417d15b25SDag-Erling Smørgrav 
17517d15b25SDag-Erling Smørgrav 	if (!tree || !key || !data) {
17617d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_NULL;
17717d15b25SDag-Erling Smørgrav 	}
17817d15b25SDag-Erling Smørgrav 	add = ldns_radix_new_node(data, key, len);
17917d15b25SDag-Erling Smørgrav 	if (!add) {
18017d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_MEM_ERR;
18117d15b25SDag-Erling Smørgrav 	}
18217d15b25SDag-Erling Smørgrav 	/** Search the trie until we can make no further process. */
18317d15b25SDag-Erling Smørgrav 	if (!ldns_radix_find_prefix(tree, key, len, &prefix, &pos)) {
18417d15b25SDag-Erling Smørgrav 		/** No prefix found */
18517d15b25SDag-Erling Smørgrav 		assert(tree->root == NULL);
18617d15b25SDag-Erling Smørgrav 		if (len == 0) {
18717d15b25SDag-Erling Smørgrav 			/**
18817d15b25SDag-Erling Smørgrav 			 * Example 1: The root:
18917d15b25SDag-Erling Smørgrav 			 * | [0]
19017d15b25SDag-Erling Smørgrav 			 **/
19117d15b25SDag-Erling Smørgrav 			tree->root = add;
19217d15b25SDag-Erling Smørgrav 		} else {
19317d15b25SDag-Erling Smørgrav 			/** Example 2: 'dns':
19417d15b25SDag-Erling Smørgrav 			 * | [0]
19517d15b25SDag-Erling Smørgrav 			 * --| [d+ns] dns
19617d15b25SDag-Erling Smørgrav 			 **/
19717d15b25SDag-Erling Smørgrav 			prefix = ldns_radix_new_node(NULL, (uint8_t*)"", 0);
19817d15b25SDag-Erling Smørgrav 			if (!prefix) {
19917d15b25SDag-Erling Smørgrav 				LDNS_FREE(add);
20017d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
20117d15b25SDag-Erling Smørgrav 			}
20217d15b25SDag-Erling Smørgrav 			/** Find some space in the array for the first byte */
20317d15b25SDag-Erling Smørgrav 			if (!ldns_radix_array_space(prefix, key[0])) {
20417d15b25SDag-Erling Smørgrav 				LDNS_FREE(add);
20517d15b25SDag-Erling Smørgrav 				LDNS_FREE(prefix->array);
20617d15b25SDag-Erling Smørgrav 				LDNS_FREE(prefix);
20717d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
20817d15b25SDag-Erling Smørgrav 			}
20917d15b25SDag-Erling Smørgrav 			/** Set relational pointers */
21017d15b25SDag-Erling Smørgrav 			add->parent = prefix;
21117d15b25SDag-Erling Smørgrav 			add->parent_index = 0;
21217d15b25SDag-Erling Smørgrav 			prefix->array[0].edge = add;
21317d15b25SDag-Erling Smørgrav 			if (len > 1) {
21417d15b25SDag-Erling Smørgrav 				/** Store the remainder of the prefix */
21517d15b25SDag-Erling Smørgrav 				if (!ldns_radix_prefix_remainder(1, key,
21617d15b25SDag-Erling Smørgrav 					len, &prefix->array[0].str,
21717d15b25SDag-Erling Smørgrav 					&prefix->array[0].len)) {
21817d15b25SDag-Erling Smørgrav 					LDNS_FREE(add);
21917d15b25SDag-Erling Smørgrav 					LDNS_FREE(prefix->array);
22017d15b25SDag-Erling Smørgrav 					LDNS_FREE(prefix);
22117d15b25SDag-Erling Smørgrav 					return LDNS_STATUS_MEM_ERR;
22217d15b25SDag-Erling Smørgrav 				}
22317d15b25SDag-Erling Smørgrav 			}
22417d15b25SDag-Erling Smørgrav 			tree->root = prefix;
22517d15b25SDag-Erling Smørgrav 		}
22617d15b25SDag-Erling Smørgrav 	} else if (pos == len) {
22717d15b25SDag-Erling Smørgrav 		/** Exact match found */
228*5afab0e5SDag-Erling Smørgrav 		LDNS_FREE(add);
22917d15b25SDag-Erling Smørgrav 		if (prefix->data) {
23017d15b25SDag-Erling Smørgrav 			/* Element already exists */
23117d15b25SDag-Erling Smørgrav 			return LDNS_STATUS_EXISTS_ERR;
23217d15b25SDag-Erling Smørgrav 		}
23317d15b25SDag-Erling Smørgrav 		prefix->data = data;
23417d15b25SDag-Erling Smørgrav 		prefix->key = key;
23517d15b25SDag-Erling Smørgrav 		prefix->klen = len; /* redundant */
23617d15b25SDag-Erling Smørgrav 	} else {
23717d15b25SDag-Erling Smørgrav 		/** Prefix found */
23817d15b25SDag-Erling Smørgrav 		uint8_t byte = key[pos];
23917d15b25SDag-Erling Smørgrav 		assert(pos < len);
24017d15b25SDag-Erling Smørgrav 		if (byte < prefix->offset ||
24117d15b25SDag-Erling Smørgrav 			(byte - prefix->offset) >= prefix->len) {
24217d15b25SDag-Erling Smørgrav 			/** Find some space in the array for the byte. */
24317d15b25SDag-Erling Smørgrav 			/**
24417d15b25SDag-Erling Smørgrav 			 * Example 3: 'ldns'
24517d15b25SDag-Erling Smørgrav 			 * | [0]
24617d15b25SDag-Erling Smørgrav 			 * --| [d+ns] dns
24717d15b25SDag-Erling Smørgrav 			 * --| [l+dns] ldns
24817d15b25SDag-Erling Smørgrav 			 **/
24917d15b25SDag-Erling Smørgrav 			if (!ldns_radix_array_space(prefix, byte)) {
25017d15b25SDag-Erling Smørgrav 				LDNS_FREE(add);
25117d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
25217d15b25SDag-Erling Smørgrav 			}
25317d15b25SDag-Erling Smørgrav 			assert(byte >= prefix->offset);
25417d15b25SDag-Erling Smørgrav 			assert((byte - prefix->offset) <= prefix->len);
25517d15b25SDag-Erling Smørgrav 			byte -= prefix->offset;
25617d15b25SDag-Erling Smørgrav 			if (pos+1 < len) {
25717d15b25SDag-Erling Smørgrav 				/** Create remainder of the string. */
25817d15b25SDag-Erling Smørgrav 				if (!ldns_radix_str_create(
25917d15b25SDag-Erling Smørgrav 					&prefix->array[byte], key, pos+1,
26017d15b25SDag-Erling Smørgrav 					len)) {
26117d15b25SDag-Erling Smørgrav 					LDNS_FREE(add);
26217d15b25SDag-Erling Smørgrav 					return LDNS_STATUS_MEM_ERR;
26317d15b25SDag-Erling Smørgrav 				}
26417d15b25SDag-Erling Smørgrav 			}
26517d15b25SDag-Erling Smørgrav 			/** Add new node. */
26617d15b25SDag-Erling Smørgrav 			add->parent = prefix;
26717d15b25SDag-Erling Smørgrav 			add->parent_index = byte;
26817d15b25SDag-Erling Smørgrav 			prefix->array[byte].edge = add;
26917d15b25SDag-Erling Smørgrav 		} else if (prefix->array[byte-prefix->offset].edge == NULL) {
27017d15b25SDag-Erling Smørgrav 			/** Use existing element. */
27117d15b25SDag-Erling Smørgrav 			/**
27217d15b25SDag-Erling Smørgrav 			 * Example 4: 'edns'
27317d15b25SDag-Erling Smørgrav 			 * | [0]
27417d15b25SDag-Erling Smørgrav 			 * --| [d+ns] dns
27517d15b25SDag-Erling Smørgrav 			 * --| [e+dns] edns
27617d15b25SDag-Erling Smørgrav 			 * --| [l+dns] ldns
27717d15b25SDag-Erling Smørgrav 			 **/
27817d15b25SDag-Erling Smørgrav 			byte -= prefix->offset;
27917d15b25SDag-Erling Smørgrav 			if (pos+1 < len) {
28017d15b25SDag-Erling Smørgrav 				/** Create remainder of the string. */
28117d15b25SDag-Erling Smørgrav 				if (!ldns_radix_str_create(
28217d15b25SDag-Erling Smørgrav 					&prefix->array[byte], key, pos+1,
28317d15b25SDag-Erling Smørgrav 					len)) {
28417d15b25SDag-Erling Smørgrav 					LDNS_FREE(add);
28517d15b25SDag-Erling Smørgrav 					return LDNS_STATUS_MEM_ERR;
28617d15b25SDag-Erling Smørgrav 				}
28717d15b25SDag-Erling Smørgrav 			}
28817d15b25SDag-Erling Smørgrav 			/** Add new node. */
28917d15b25SDag-Erling Smørgrav 			add->parent = prefix;
29017d15b25SDag-Erling Smørgrav 			add->parent_index = byte;
29117d15b25SDag-Erling Smørgrav 			prefix->array[byte].edge = add;
29217d15b25SDag-Erling Smørgrav 		} else {
29317d15b25SDag-Erling Smørgrav 			/**
29417d15b25SDag-Erling Smørgrav 			 * Use existing element, but it has a shared prefix,
29517d15b25SDag-Erling Smørgrav 			 * we need a split.
29617d15b25SDag-Erling Smørgrav 			 */
29717d15b25SDag-Erling Smørgrav 			if (!ldns_radix_array_split(&prefix->array[byte-(prefix->offset)],
29817d15b25SDag-Erling Smørgrav 				key, pos+1, len, add)) {
29917d15b25SDag-Erling Smørgrav 				LDNS_FREE(add);
30017d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
30117d15b25SDag-Erling Smørgrav 			}
30217d15b25SDag-Erling Smørgrav 		}
30317d15b25SDag-Erling Smørgrav 	}
30417d15b25SDag-Erling Smørgrav 
30517d15b25SDag-Erling Smørgrav 	tree->count ++;
30617d15b25SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
30717d15b25SDag-Erling Smørgrav }
30817d15b25SDag-Erling Smørgrav 
30917d15b25SDag-Erling Smørgrav 
31017d15b25SDag-Erling Smørgrav /**
31117d15b25SDag-Erling Smørgrav  * Delete data from the tree.
31217d15b25SDag-Erling Smørgrav  *
31317d15b25SDag-Erling Smørgrav  */
ldns_radix_delete(ldns_radix_t * tree,const uint8_t * key,radix_strlen_t len)314986ba33cSDag-Erling Smørgrav void* ldns_radix_delete(ldns_radix_t* tree, const uint8_t* key, radix_strlen_t len)
31517d15b25SDag-Erling Smørgrav {
31617d15b25SDag-Erling Smørgrav     ldns_radix_node_t* del = ldns_radix_search(tree, key, len);
31717d15b25SDag-Erling Smørgrav     void* data = NULL;
31817d15b25SDag-Erling Smørgrav     if (del) {
31917d15b25SDag-Erling Smørgrav         tree->count--;
32017d15b25SDag-Erling Smørgrav         data = del->data;
32117d15b25SDag-Erling Smørgrav         del->data = NULL;
32217d15b25SDag-Erling Smørgrav         ldns_radix_del_fix(tree, del);
32317d15b25SDag-Erling Smørgrav         return data;
32417d15b25SDag-Erling Smørgrav     }
32517d15b25SDag-Erling Smørgrav     return NULL;
32617d15b25SDag-Erling Smørgrav }
32717d15b25SDag-Erling Smørgrav 
32817d15b25SDag-Erling Smørgrav 
32917d15b25SDag-Erling Smørgrav /**
33017d15b25SDag-Erling Smørgrav  * Search data in the tree.
33117d15b25SDag-Erling Smørgrav  *
33217d15b25SDag-Erling Smørgrav  */
33317d15b25SDag-Erling Smørgrav ldns_radix_node_t*
ldns_radix_search(ldns_radix_t * tree,const uint8_t * key,radix_strlen_t len)334986ba33cSDag-Erling Smørgrav ldns_radix_search(ldns_radix_t* tree, const uint8_t* key, radix_strlen_t len)
33517d15b25SDag-Erling Smørgrav {
33617d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* node = NULL;
33717d15b25SDag-Erling Smørgrav 	radix_strlen_t pos = 0;
33817d15b25SDag-Erling Smørgrav 	uint8_t byte = 0;
33917d15b25SDag-Erling Smørgrav 
34017d15b25SDag-Erling Smørgrav 	if (!tree || !key) {
34117d15b25SDag-Erling Smørgrav 		return NULL;
34217d15b25SDag-Erling Smørgrav 	}
34317d15b25SDag-Erling Smørgrav 	node = tree->root;
34417d15b25SDag-Erling Smørgrav 	while (node) {
34517d15b25SDag-Erling Smørgrav 		if (pos == len) {
34617d15b25SDag-Erling Smørgrav 			return node->data?node:NULL;
34717d15b25SDag-Erling Smørgrav 		}
34817d15b25SDag-Erling Smørgrav 		byte = key[pos];
34917d15b25SDag-Erling Smørgrav 		if (byte < node->offset) {
35017d15b25SDag-Erling Smørgrav 			return NULL;
35117d15b25SDag-Erling Smørgrav 		}
35217d15b25SDag-Erling Smørgrav 		byte -= node->offset;
35317d15b25SDag-Erling Smørgrav 		if (byte >= node->len) {
35417d15b25SDag-Erling Smørgrav 			return NULL;
35517d15b25SDag-Erling Smørgrav 		}
35617d15b25SDag-Erling Smørgrav 		pos++;
35717d15b25SDag-Erling Smørgrav 		if (node->array[byte].len > 0) {
35817d15b25SDag-Erling Smørgrav 			/** Must match additional string. */
35917d15b25SDag-Erling Smørgrav 			if (pos + node->array[byte].len > len) {
36017d15b25SDag-Erling Smørgrav 				return NULL;
36117d15b25SDag-Erling Smørgrav 			}
36217d15b25SDag-Erling Smørgrav 			if (memcmp(&key[pos], node->array[byte].str,
36317d15b25SDag-Erling Smørgrav 				node->array[byte].len) != 0) {
36417d15b25SDag-Erling Smørgrav 				return NULL;
36517d15b25SDag-Erling Smørgrav 			}
36617d15b25SDag-Erling Smørgrav 			pos += node->array[byte].len;
36717d15b25SDag-Erling Smørgrav 		}
36817d15b25SDag-Erling Smørgrav 		node = node->array[byte].edge;
36917d15b25SDag-Erling Smørgrav 	}
37017d15b25SDag-Erling Smørgrav 	return NULL;
37117d15b25SDag-Erling Smørgrav }
37217d15b25SDag-Erling Smørgrav 
37317d15b25SDag-Erling Smørgrav 
37417d15b25SDag-Erling Smørgrav /**
37517d15b25SDag-Erling Smørgrav  * Search data in the tree, and if not found, find the closest smaller
37617d15b25SDag-Erling Smørgrav  * element in the tree.
37717d15b25SDag-Erling Smørgrav  *
37817d15b25SDag-Erling Smørgrav  */
37917d15b25SDag-Erling Smørgrav int
ldns_radix_find_less_equal(ldns_radix_t * tree,const uint8_t * key,radix_strlen_t len,ldns_radix_node_t ** result)380986ba33cSDag-Erling Smørgrav ldns_radix_find_less_equal(ldns_radix_t* tree, const uint8_t* key,
38117d15b25SDag-Erling Smørgrav 	radix_strlen_t len, ldns_radix_node_t** result)
38217d15b25SDag-Erling Smørgrav {
38317d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* node = NULL;
38417d15b25SDag-Erling Smørgrav 	radix_strlen_t pos = 0;
38517d15b25SDag-Erling Smørgrav 	uint8_t byte;
38617d15b25SDag-Erling Smørgrav 	int memcmp_res = 0;
38717d15b25SDag-Erling Smørgrav 
38817d15b25SDag-Erling Smørgrav 	if (!tree || !tree->root || !key) {
38917d15b25SDag-Erling Smørgrav 		*result = NULL;
39017d15b25SDag-Erling Smørgrav 		return 0;
39117d15b25SDag-Erling Smørgrav 	}
39217d15b25SDag-Erling Smørgrav 
39317d15b25SDag-Erling Smørgrav 	node = tree->root;
39417d15b25SDag-Erling Smørgrav 	while (pos < len) {
39517d15b25SDag-Erling Smørgrav 		byte = key[pos];
39617d15b25SDag-Erling Smørgrav 		if (byte < node->offset) {
39717d15b25SDag-Erling Smørgrav 			/**
39817d15b25SDag-Erling Smørgrav 			 * No exact match. The lesser is in this or the
39917d15b25SDag-Erling Smørgrav 			 * previous node.
40017d15b25SDag-Erling Smørgrav 			 */
40117d15b25SDag-Erling Smørgrav 			ldns_radix_self_or_prev(node, result);
40217d15b25SDag-Erling Smørgrav 			return 0;
40317d15b25SDag-Erling Smørgrav 		}
40417d15b25SDag-Erling Smørgrav 		byte -= node->offset;
40517d15b25SDag-Erling Smørgrav 		if (byte >= node->len) {
40617d15b25SDag-Erling Smørgrav 			/**
40717d15b25SDag-Erling Smørgrav 			 * No exact match. The lesser is in this node or the
40817d15b25SDag-Erling Smørgrav 			 * last of this array, or something before this node.
40917d15b25SDag-Erling Smørgrav 			 */
41017d15b25SDag-Erling Smørgrav 			*result = ldns_radix_last_in_subtree_incl_self(node);
41117d15b25SDag-Erling Smørgrav 			if (*result == NULL) {
41217d15b25SDag-Erling Smørgrav 				*result = ldns_radix_prev(node);
41317d15b25SDag-Erling Smørgrav 			}
41417d15b25SDag-Erling Smørgrav 			return 0;
41517d15b25SDag-Erling Smørgrav 		}
41617d15b25SDag-Erling Smørgrav 		pos++;
41717d15b25SDag-Erling Smørgrav 		if (!node->array[byte].edge) {
41817d15b25SDag-Erling Smørgrav 			/**
41917d15b25SDag-Erling Smørgrav 			 * No exact match. Find the previous in the array
42017d15b25SDag-Erling Smørgrav 			 * from this index.
42117d15b25SDag-Erling Smørgrav 			 */
42217d15b25SDag-Erling Smørgrav 			*result = ldns_radix_prev_from_index(node, byte);
42317d15b25SDag-Erling Smørgrav 			if (*result == NULL) {
42417d15b25SDag-Erling Smørgrav 				ldns_radix_self_or_prev(node, result);
42517d15b25SDag-Erling Smørgrav 			}
42617d15b25SDag-Erling Smørgrav 			return 0;
42717d15b25SDag-Erling Smørgrav 		}
42817d15b25SDag-Erling Smørgrav 		if (node->array[byte].len != 0) {
42917d15b25SDag-Erling Smørgrav 			/** Must match additional string. */
43017d15b25SDag-Erling Smørgrav 			if (pos + node->array[byte].len > len) {
43117d15b25SDag-Erling Smørgrav 				/** Additional string is longer than key. */
43217d15b25SDag-Erling Smørgrav 				if (memcmp(&key[pos], node->array[byte].str,
43317d15b25SDag-Erling Smørgrav 					len-pos) <= 0) {
43417d15b25SDag-Erling Smørgrav 					/** Key is before this node. */
43517d15b25SDag-Erling Smørgrav 					*result = ldns_radix_prev(
43617d15b25SDag-Erling Smørgrav 						node->array[byte].edge);
43717d15b25SDag-Erling Smørgrav 				} else {
43817d15b25SDag-Erling Smørgrav 					/** Key is after additional string. */
43917d15b25SDag-Erling Smørgrav 					*result = ldns_radix_last_in_subtree_incl_self(node->array[byte].edge);
44017d15b25SDag-Erling Smørgrav 					if (*result == NULL) {
44117d15b25SDag-Erling Smørgrav 						 *result = ldns_radix_prev(node->array[byte].edge);
44217d15b25SDag-Erling Smørgrav 					}
44317d15b25SDag-Erling Smørgrav 				}
44417d15b25SDag-Erling Smørgrav 				return 0;
44517d15b25SDag-Erling Smørgrav 			}
44617d15b25SDag-Erling Smørgrav 			memcmp_res = memcmp(&key[pos], node->array[byte].str,
44717d15b25SDag-Erling Smørgrav 				node->array[byte].len);
44817d15b25SDag-Erling Smørgrav 			if (memcmp_res < 0) {
44917d15b25SDag-Erling Smørgrav 				*result = ldns_radix_prev(
45017d15b25SDag-Erling Smørgrav 					node->array[byte].edge);
45117d15b25SDag-Erling Smørgrav 				return 0;
45217d15b25SDag-Erling Smørgrav 			} else if (memcmp_res > 0) {
45317d15b25SDag-Erling Smørgrav 				*result = ldns_radix_last_in_subtree_incl_self(node->array[byte].edge);
45417d15b25SDag-Erling Smørgrav 				if (*result == NULL) {
45517d15b25SDag-Erling Smørgrav 					 *result = ldns_radix_prev(node->array[byte].edge);
45617d15b25SDag-Erling Smørgrav 				}
45717d15b25SDag-Erling Smørgrav 				return 0;
45817d15b25SDag-Erling Smørgrav 			}
45917d15b25SDag-Erling Smørgrav 
46017d15b25SDag-Erling Smørgrav 			pos += node->array[byte].len;
46117d15b25SDag-Erling Smørgrav 		}
46217d15b25SDag-Erling Smørgrav 		node = node->array[byte].edge;
46317d15b25SDag-Erling Smørgrav 	}
46417d15b25SDag-Erling Smørgrav 	if (node->data) {
46517d15b25SDag-Erling Smørgrav 		/** Exact match. */
46617d15b25SDag-Erling Smørgrav 		*result = node;
46717d15b25SDag-Erling Smørgrav 		return 1;
46817d15b25SDag-Erling Smørgrav 	}
46917d15b25SDag-Erling Smørgrav 	/** There is a node which is an exact match, but has no element. */
47017d15b25SDag-Erling Smørgrav 	*result = ldns_radix_prev(node);
47117d15b25SDag-Erling Smørgrav 	return 0;
47217d15b25SDag-Erling Smørgrav }
47317d15b25SDag-Erling Smørgrav 
47417d15b25SDag-Erling Smørgrav 
47517d15b25SDag-Erling Smørgrav /**
47617d15b25SDag-Erling Smørgrav  * Get the first element in the tree.
47717d15b25SDag-Erling Smørgrav  *
47817d15b25SDag-Erling Smørgrav  */
47917d15b25SDag-Erling Smørgrav ldns_radix_node_t*
ldns_radix_first(const ldns_radix_t * tree)480986ba33cSDag-Erling Smørgrav ldns_radix_first(const ldns_radix_t* tree)
48117d15b25SDag-Erling Smørgrav {
48217d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* first = NULL;
48317d15b25SDag-Erling Smørgrav 	if (!tree || !tree->root) {
48417d15b25SDag-Erling Smørgrav 		return NULL;
48517d15b25SDag-Erling Smørgrav 	}
48617d15b25SDag-Erling Smørgrav 	first = tree->root;
48717d15b25SDag-Erling Smørgrav 	if (first->data) {
48817d15b25SDag-Erling Smørgrav 		return first;
48917d15b25SDag-Erling Smørgrav 	}
49017d15b25SDag-Erling Smørgrav 	return ldns_radix_next(first);
49117d15b25SDag-Erling Smørgrav }
49217d15b25SDag-Erling Smørgrav 
49317d15b25SDag-Erling Smørgrav 
49417d15b25SDag-Erling Smørgrav /**
49517d15b25SDag-Erling Smørgrav  * Get the last element in the tree.
49617d15b25SDag-Erling Smørgrav  *
49717d15b25SDag-Erling Smørgrav  */
49817d15b25SDag-Erling Smørgrav ldns_radix_node_t*
ldns_radix_last(const ldns_radix_t * tree)499986ba33cSDag-Erling Smørgrav ldns_radix_last(const ldns_radix_t* tree)
50017d15b25SDag-Erling Smørgrav {
50117d15b25SDag-Erling Smørgrav 	if (!tree || !tree->root) {
50217d15b25SDag-Erling Smørgrav 		return NULL;
50317d15b25SDag-Erling Smørgrav 	}
50417d15b25SDag-Erling Smørgrav 	return ldns_radix_last_in_subtree_incl_self(tree->root);
50517d15b25SDag-Erling Smørgrav }
50617d15b25SDag-Erling Smørgrav 
50717d15b25SDag-Erling Smørgrav 
50817d15b25SDag-Erling Smørgrav /**
50917d15b25SDag-Erling Smørgrav  * Next element.
51017d15b25SDag-Erling Smørgrav  *
51117d15b25SDag-Erling Smørgrav  */
51217d15b25SDag-Erling Smørgrav ldns_radix_node_t*
ldns_radix_next(ldns_radix_node_t * node)51317d15b25SDag-Erling Smørgrav ldns_radix_next(ldns_radix_node_t* node)
51417d15b25SDag-Erling Smørgrav {
51517d15b25SDag-Erling Smørgrav 	if (!node) {
51617d15b25SDag-Erling Smørgrav 		return NULL;
51717d15b25SDag-Erling Smørgrav 	}
51817d15b25SDag-Erling Smørgrav 	if (node->len) {
51917d15b25SDag-Erling Smørgrav 		/** Go down: most-left child is the next. */
52017d15b25SDag-Erling Smørgrav 		ldns_radix_node_t* next = ldns_radix_next_in_subtree(node);
52117d15b25SDag-Erling Smørgrav 		if (next) {
52217d15b25SDag-Erling Smørgrav 			return next;
52317d15b25SDag-Erling Smørgrav 		}
52417d15b25SDag-Erling Smørgrav 	}
52517d15b25SDag-Erling Smørgrav 	/** No elements in subtree, get to parent and go down next branch. */
52617d15b25SDag-Erling Smørgrav 	while (node->parent) {
52717d15b25SDag-Erling Smørgrav 		uint8_t index = node->parent_index;
52817d15b25SDag-Erling Smørgrav 		node = node->parent;
52917d15b25SDag-Erling Smørgrav 		index++;
53017d15b25SDag-Erling Smørgrav 		for (; index < node->len; index++) {
53117d15b25SDag-Erling Smørgrav 			if (node->array[index].edge) {
53217d15b25SDag-Erling Smørgrav 				ldns_radix_node_t* next;
53317d15b25SDag-Erling Smørgrav 				/** Node itself. */
53417d15b25SDag-Erling Smørgrav 				if (node->array[index].edge->data) {
53517d15b25SDag-Erling Smørgrav 					return node->array[index].edge;
53617d15b25SDag-Erling Smørgrav 				}
53717d15b25SDag-Erling Smørgrav 				/** Dive into subtree. */
53817d15b25SDag-Erling Smørgrav 				next = ldns_radix_next_in_subtree(node);
53917d15b25SDag-Erling Smørgrav 				if (next) {
54017d15b25SDag-Erling Smørgrav 					return next;
54117d15b25SDag-Erling Smørgrav 				}
54217d15b25SDag-Erling Smørgrav 			}
54317d15b25SDag-Erling Smørgrav 		}
54417d15b25SDag-Erling Smørgrav 	}
54517d15b25SDag-Erling Smørgrav 	return NULL;
54617d15b25SDag-Erling Smørgrav }
54717d15b25SDag-Erling Smørgrav 
54817d15b25SDag-Erling Smørgrav 
54917d15b25SDag-Erling Smørgrav /**
55017d15b25SDag-Erling Smørgrav  * Previous element.
55117d15b25SDag-Erling Smørgrav  *
55217d15b25SDag-Erling Smørgrav  */
55317d15b25SDag-Erling Smørgrav ldns_radix_node_t*
ldns_radix_prev(ldns_radix_node_t * node)55417d15b25SDag-Erling Smørgrav ldns_radix_prev(ldns_radix_node_t* node)
55517d15b25SDag-Erling Smørgrav {
55617d15b25SDag-Erling Smørgrav 	if (!node) {
55717d15b25SDag-Erling Smørgrav 		return NULL;
55817d15b25SDag-Erling Smørgrav 	}
55917d15b25SDag-Erling Smørgrav 
56017d15b25SDag-Erling Smørgrav 	/** Get to parent and go down previous branch. */
56117d15b25SDag-Erling Smørgrav 	while (node->parent) {
56217d15b25SDag-Erling Smørgrav 		uint8_t index = node->parent_index;
56317d15b25SDag-Erling Smørgrav 		ldns_radix_node_t* prev;
56417d15b25SDag-Erling Smørgrav 		node = node->parent;
56517d15b25SDag-Erling Smørgrav 		assert(node->len > 0);
56617d15b25SDag-Erling Smørgrav 		prev = ldns_radix_prev_from_index(node, index);
56717d15b25SDag-Erling Smørgrav 		if (prev) {
56817d15b25SDag-Erling Smørgrav 			return prev;
56917d15b25SDag-Erling Smørgrav 		}
57017d15b25SDag-Erling Smørgrav 		if (node->data) {
57117d15b25SDag-Erling Smørgrav 			return node;
57217d15b25SDag-Erling Smørgrav 		}
57317d15b25SDag-Erling Smørgrav 	}
57417d15b25SDag-Erling Smørgrav 	return NULL;
57517d15b25SDag-Erling Smørgrav }
57617d15b25SDag-Erling Smørgrav 
57717d15b25SDag-Erling Smørgrav 
57817d15b25SDag-Erling Smørgrav /**
57917d15b25SDag-Erling Smørgrav  * Print node.
58017d15b25SDag-Erling Smørgrav  *
58117d15b25SDag-Erling Smørgrav  */
58217d15b25SDag-Erling Smørgrav static void
ldns_radix_node_print(FILE * fd,ldns_radix_node_t * node,uint8_t i,uint8_t * str,radix_strlen_t len,unsigned d)58317d15b25SDag-Erling Smørgrav ldns_radix_node_print(FILE* fd, ldns_radix_node_t* node,
58417d15b25SDag-Erling Smørgrav 	uint8_t i, uint8_t* str, radix_strlen_t len, unsigned d)
58517d15b25SDag-Erling Smørgrav {
58617d15b25SDag-Erling Smørgrav 	uint8_t j;
58717d15b25SDag-Erling Smørgrav 	if (!node) {
58817d15b25SDag-Erling Smørgrav 		return;
58917d15b25SDag-Erling Smørgrav 	}
59017d15b25SDag-Erling Smørgrav 	for (j = 0; j < d; j++) {
59117d15b25SDag-Erling Smørgrav 		fprintf(fd, "--");
59217d15b25SDag-Erling Smørgrav 	}
59317d15b25SDag-Erling Smørgrav 	if (str) {
59417d15b25SDag-Erling Smørgrav 		radix_strlen_t l;
59517d15b25SDag-Erling Smørgrav 		fprintf(fd, "| [%u+", (unsigned) i);
59617d15b25SDag-Erling Smørgrav 		for (l=0; l < len; l++) {
59717d15b25SDag-Erling Smørgrav 			fprintf(fd, "%c", (char) str[l]);
59817d15b25SDag-Erling Smørgrav 		}
59917d15b25SDag-Erling Smørgrav 		fprintf(fd, "]%u", (unsigned) len);
60017d15b25SDag-Erling Smørgrav 	} else {
60117d15b25SDag-Erling Smørgrav 		fprintf(fd, "| [%u]", (unsigned) i);
60217d15b25SDag-Erling Smørgrav 	}
60317d15b25SDag-Erling Smørgrav 
60417d15b25SDag-Erling Smørgrav 	if (node->data) {
60517d15b25SDag-Erling Smørgrav 		fprintf(fd, " %s", (char*) node->data);
60617d15b25SDag-Erling Smørgrav 	}
60717d15b25SDag-Erling Smørgrav 	fprintf(fd, "\n");
60817d15b25SDag-Erling Smørgrav 
60917d15b25SDag-Erling Smørgrav 	for (j = 0; j < node->len; j++) {
61017d15b25SDag-Erling Smørgrav 		if (node->array[j].edge) {
61117d15b25SDag-Erling Smørgrav 			ldns_radix_node_print(fd, node->array[j].edge, j,
61217d15b25SDag-Erling Smørgrav 				node->array[j].str, node->array[j].len, d+1);
61317d15b25SDag-Erling Smørgrav 		}
61417d15b25SDag-Erling Smørgrav 	}
61517d15b25SDag-Erling Smørgrav 	return;
61617d15b25SDag-Erling Smørgrav }
61717d15b25SDag-Erling Smørgrav 
61817d15b25SDag-Erling Smørgrav 
61917d15b25SDag-Erling Smørgrav /**
62017d15b25SDag-Erling Smørgrav  * Print radix tree.
62117d15b25SDag-Erling Smørgrav  *
62217d15b25SDag-Erling Smørgrav  */
62317d15b25SDag-Erling Smørgrav void
ldns_radix_printf(FILE * fd,const ldns_radix_t * tree)624986ba33cSDag-Erling Smørgrav ldns_radix_printf(FILE* fd, const ldns_radix_t* tree)
62517d15b25SDag-Erling Smørgrav {
62617d15b25SDag-Erling Smørgrav 	if (!fd || !tree) {
62717d15b25SDag-Erling Smørgrav 		return;
62817d15b25SDag-Erling Smørgrav 	}
62917d15b25SDag-Erling Smørgrav 	if (!tree->root) {
63017d15b25SDag-Erling Smørgrav 		fprintf(fd, "; empty radix tree\n");
63117d15b25SDag-Erling Smørgrav 		return;
63217d15b25SDag-Erling Smørgrav 	}
63317d15b25SDag-Erling Smørgrav 	ldns_radix_node_print(fd, tree->root, 0, NULL, 0, 0);
63417d15b25SDag-Erling Smørgrav 	return;
63517d15b25SDag-Erling Smørgrav }
63617d15b25SDag-Erling Smørgrav 
63717d15b25SDag-Erling Smørgrav 
63817d15b25SDag-Erling Smørgrav /**
63917d15b25SDag-Erling Smørgrav  * Join two radix trees.
64017d15b25SDag-Erling Smørgrav  *
64117d15b25SDag-Erling Smørgrav  */
64217d15b25SDag-Erling Smørgrav ldns_status
ldns_radix_join(ldns_radix_t * tree1,ldns_radix_t * tree2)64317d15b25SDag-Erling Smørgrav ldns_radix_join(ldns_radix_t* tree1, ldns_radix_t* tree2)
64417d15b25SDag-Erling Smørgrav {
64517d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* cur_node, *next_node;
64617d15b25SDag-Erling Smørgrav 	ldns_status status;
64717d15b25SDag-Erling Smørgrav 	if (!tree2 || !tree2->root) {
64817d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
64917d15b25SDag-Erling Smørgrav 	}
65017d15b25SDag-Erling Smørgrav 	/** Add all elements from tree2 into tree1. */
65117d15b25SDag-Erling Smørgrav 
65217d15b25SDag-Erling Smørgrav 	cur_node = ldns_radix_first(tree2);
65317d15b25SDag-Erling Smørgrav 	while (cur_node) {
65417d15b25SDag-Erling Smørgrav 		status = LDNS_STATUS_NO_DATA;
65517d15b25SDag-Erling Smørgrav 		/** Insert current node into tree1 */
65617d15b25SDag-Erling Smørgrav 		if (cur_node->data) {
65717d15b25SDag-Erling Smørgrav 			status = ldns_radix_insert(tree1, cur_node->key,
65817d15b25SDag-Erling Smørgrav 				cur_node->klen, cur_node->data);
65917d15b25SDag-Erling Smørgrav 			/** Exist errors may occur */
66017d15b25SDag-Erling Smørgrav 			if (status != LDNS_STATUS_OK &&
66117d15b25SDag-Erling Smørgrav 			    status != LDNS_STATUS_EXISTS_ERR) {
66217d15b25SDag-Erling Smørgrav 				return status;
66317d15b25SDag-Erling Smørgrav 			}
66417d15b25SDag-Erling Smørgrav 		}
66517d15b25SDag-Erling Smørgrav 		next_node = ldns_radix_next(cur_node);
66617d15b25SDag-Erling Smørgrav 		if (status == LDNS_STATUS_OK) {
66717d15b25SDag-Erling Smørgrav 			(void) ldns_radix_delete(tree2, cur_node->key,
66817d15b25SDag-Erling Smørgrav 				cur_node->klen);
66917d15b25SDag-Erling Smørgrav 		}
67017d15b25SDag-Erling Smørgrav 		cur_node = next_node;
67117d15b25SDag-Erling Smørgrav 	}
67217d15b25SDag-Erling Smørgrav 
67317d15b25SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
67417d15b25SDag-Erling Smørgrav }
67517d15b25SDag-Erling Smørgrav 
67617d15b25SDag-Erling Smørgrav 
67717d15b25SDag-Erling Smørgrav /**
67817d15b25SDag-Erling Smørgrav  * Split a radix tree intwo.
67917d15b25SDag-Erling Smørgrav  *
68017d15b25SDag-Erling Smørgrav  */
68117d15b25SDag-Erling Smørgrav ldns_status
ldns_radix_split(ldns_radix_t * tree1,size_t num,ldns_radix_t ** tree2)68217d15b25SDag-Erling Smørgrav ldns_radix_split(ldns_radix_t* tree1, size_t num, ldns_radix_t** tree2)
68317d15b25SDag-Erling Smørgrav {
68417d15b25SDag-Erling Smørgrav 	size_t count = 0;
68517d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* cur_node;
68617d15b25SDag-Erling Smørgrav 	ldns_status status = LDNS_STATUS_OK;
68717d15b25SDag-Erling Smørgrav 	if (!tree1 || !tree1->root || num == 0) {
68817d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
68917d15b25SDag-Erling Smørgrav 	}
69017d15b25SDag-Erling Smørgrav 	if (!tree2) {
69117d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_NULL;
69217d15b25SDag-Erling Smørgrav 	}
69317d15b25SDag-Erling Smørgrav 	if (!*tree2) {
69417d15b25SDag-Erling Smørgrav 		*tree2 = ldns_radix_create();
69517d15b25SDag-Erling Smørgrav 		if (!*tree2) {
69617d15b25SDag-Erling Smørgrav 			return LDNS_STATUS_MEM_ERR;
69717d15b25SDag-Erling Smørgrav 		}
69817d15b25SDag-Erling Smørgrav 	}
69917d15b25SDag-Erling Smørgrav 	cur_node = ldns_radix_first(tree1);
70017d15b25SDag-Erling Smørgrav 	while (count < num && cur_node) {
70117d15b25SDag-Erling Smørgrav 		if (cur_node->data) {
70217d15b25SDag-Erling Smørgrav 			/** Delete current node from tree1. */
70317d15b25SDag-Erling Smørgrav 			uint8_t* cur_key = cur_node->key;
70417d15b25SDag-Erling Smørgrav 			radix_strlen_t cur_len = cur_node->klen;
70517d15b25SDag-Erling Smørgrav 			void* cur_data = ldns_radix_delete(tree1, cur_key,
70617d15b25SDag-Erling Smørgrav 				cur_len);
70717d15b25SDag-Erling Smørgrav 			/** Insert current node into tree2/ */
70817d15b25SDag-Erling Smørgrav 			if (!cur_data) {
70917d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_NO_DATA;
71017d15b25SDag-Erling Smørgrav 			}
71117d15b25SDag-Erling Smørgrav 			status = ldns_radix_insert(*tree2, cur_key, cur_len,
71217d15b25SDag-Erling Smørgrav 				cur_data);
71317d15b25SDag-Erling Smørgrav 			if (status != LDNS_STATUS_OK &&
71417d15b25SDag-Erling Smørgrav 			    status != LDNS_STATUS_EXISTS_ERR) {
71517d15b25SDag-Erling Smørgrav 				return status;
71617d15b25SDag-Erling Smørgrav 			}
71717d15b25SDag-Erling Smørgrav /*
71817d15b25SDag-Erling Smørgrav 			if (status == LDNS_STATUS_OK) {
71917d15b25SDag-Erling Smørgrav 				cur_node->key = NULL;
72017d15b25SDag-Erling Smørgrav 				cur_node->klen = 0;
72117d15b25SDag-Erling Smørgrav 			}
72217d15b25SDag-Erling Smørgrav */
72317d15b25SDag-Erling Smørgrav 			/** Update count; get first element from tree1 again. */
72417d15b25SDag-Erling Smørgrav 			count++;
72517d15b25SDag-Erling Smørgrav 			cur_node = ldns_radix_first(tree1);
72617d15b25SDag-Erling Smørgrav 		} else {
72717d15b25SDag-Erling Smørgrav 			cur_node = ldns_radix_next(cur_node);
72817d15b25SDag-Erling Smørgrav 		}
72917d15b25SDag-Erling Smørgrav 	}
73017d15b25SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
73117d15b25SDag-Erling Smørgrav }
73217d15b25SDag-Erling Smørgrav 
73317d15b25SDag-Erling Smørgrav 
73417d15b25SDag-Erling Smørgrav /**
73517d15b25SDag-Erling Smørgrav  * Call function for all nodes in the tree, such that leaf nodes are
73617d15b25SDag-Erling Smørgrav  * called before parent nodes.
73717d15b25SDag-Erling Smørgrav  *
73817d15b25SDag-Erling Smørgrav  */
73917d15b25SDag-Erling Smørgrav void
ldns_radix_traverse_postorder(ldns_radix_node_t * node,void (* func)(ldns_radix_node_t *,void *),void * arg)74017d15b25SDag-Erling Smørgrav ldns_radix_traverse_postorder(ldns_radix_node_t* node,
74117d15b25SDag-Erling Smørgrav 	void (*func)(ldns_radix_node_t*, void*), void* arg)
74217d15b25SDag-Erling Smørgrav {
74317d15b25SDag-Erling Smørgrav 	uint8_t i;
74417d15b25SDag-Erling Smørgrav 	if (!node) {
74517d15b25SDag-Erling Smørgrav 		return;
74617d15b25SDag-Erling Smørgrav 	}
74717d15b25SDag-Erling Smørgrav 	for (i=0; i < node->len; i++) {
74817d15b25SDag-Erling Smørgrav 		ldns_radix_traverse_postorder(node->array[i].edge,
74917d15b25SDag-Erling Smørgrav 			func, arg);
75017d15b25SDag-Erling Smørgrav 	}
75117d15b25SDag-Erling Smørgrav 	/** Call user function */
75217d15b25SDag-Erling Smørgrav 	(*func)(node, arg);
75317d15b25SDag-Erling Smørgrav 	return;
75417d15b25SDag-Erling Smørgrav }
75517d15b25SDag-Erling Smørgrav 
75617d15b25SDag-Erling Smørgrav 
75717d15b25SDag-Erling Smørgrav /** Static helper functions */
75817d15b25SDag-Erling Smørgrav 
75917d15b25SDag-Erling Smørgrav /**
76017d15b25SDag-Erling Smørgrav  * Find a prefix of the key.
76117d15b25SDag-Erling Smørgrav  * @param tree:   tree.
76217d15b25SDag-Erling Smørgrav  * @param key:    key.
76317d15b25SDag-Erling Smørgrav  * @param len:    length of key.
76417d15b25SDag-Erling Smørgrav  * @param result: the longest prefix, the entry itself if *pos==len,
76517d15b25SDag-Erling Smørgrav  *                otherwise an array entry.
76617d15b25SDag-Erling Smørgrav  * @param pos:    position in string where next unmatched byte is.
76717d15b25SDag-Erling Smørgrav  *                If *pos==len, an exact match is found.
76817d15b25SDag-Erling Smørgrav  *                If *pos== 0, a "" match was found.
76917d15b25SDag-Erling Smørgrav  * @return 0 (false) if no prefix found.
77017d15b25SDag-Erling Smørgrav  *
77117d15b25SDag-Erling Smørgrav  */
77217d15b25SDag-Erling Smørgrav static int
ldns_radix_find_prefix(ldns_radix_t * tree,uint8_t * key,radix_strlen_t len,ldns_radix_node_t ** result,radix_strlen_t * respos)77317d15b25SDag-Erling Smørgrav ldns_radix_find_prefix(ldns_radix_t* tree, uint8_t* key,
77417d15b25SDag-Erling Smørgrav 	radix_strlen_t len, ldns_radix_node_t** result, radix_strlen_t* respos)
77517d15b25SDag-Erling Smørgrav {
77617d15b25SDag-Erling Smørgrav 	/** Start searching at the root node */
77717d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* n = tree->root;
77817d15b25SDag-Erling Smørgrav 	radix_strlen_t pos = 0;
77917d15b25SDag-Erling Smørgrav 	uint8_t byte;
78017d15b25SDag-Erling Smørgrav 	*respos = 0;
78117d15b25SDag-Erling Smørgrav 	*result = n;
78217d15b25SDag-Erling Smørgrav         if (!n) {
78317d15b25SDag-Erling Smørgrav 		/** No root, no prefix found */
78417d15b25SDag-Erling Smørgrav 		return 0;
78517d15b25SDag-Erling Smørgrav 	}
78617d15b25SDag-Erling Smørgrav 	/** For each node, look if we can make further progress */
78717d15b25SDag-Erling Smørgrav 	while (n) {
78817d15b25SDag-Erling Smørgrav 		if (pos == len) {
78917d15b25SDag-Erling Smørgrav 			/** Exact match */
79017d15b25SDag-Erling Smørgrav 			return 1;
79117d15b25SDag-Erling Smørgrav 		}
79217d15b25SDag-Erling Smørgrav 		byte = key[pos];
79317d15b25SDag-Erling Smørgrav 		if (byte < n->offset) {
79417d15b25SDag-Erling Smørgrav 			/** key < node */
79517d15b25SDag-Erling Smørgrav 			return 1;
79617d15b25SDag-Erling Smørgrav 		}
79717d15b25SDag-Erling Smørgrav 		byte -= n->offset;
79817d15b25SDag-Erling Smørgrav 		if (byte >= n->len) {
79917d15b25SDag-Erling Smørgrav 			/** key > node */
80017d15b25SDag-Erling Smørgrav 			return 1;
80117d15b25SDag-Erling Smørgrav 		}
80217d15b25SDag-Erling Smørgrav 		/** So far, the trie matches */
80317d15b25SDag-Erling Smørgrav 		pos++;
80417d15b25SDag-Erling Smørgrav 		if (n->array[byte].len != 0) {
80517d15b25SDag-Erling Smørgrav 			/** Must match additional string */
80617d15b25SDag-Erling Smørgrav 			if (pos + n->array[byte].len > len) {
80717d15b25SDag-Erling Smørgrav 				return 1; /* no match at child node */
80817d15b25SDag-Erling Smørgrav 			}
80917d15b25SDag-Erling Smørgrav 			if (memcmp(&key[pos], n->array[byte].str,
81017d15b25SDag-Erling Smørgrav 				n->array[byte].len) != 0) {
81117d15b25SDag-Erling Smørgrav 				return 1; /* no match at child node */
81217d15b25SDag-Erling Smørgrav 			}
81317d15b25SDag-Erling Smørgrav 			pos += n->array[byte].len;
81417d15b25SDag-Erling Smørgrav 		}
81517d15b25SDag-Erling Smørgrav 		/** Continue searching prefix at this child node */
81617d15b25SDag-Erling Smørgrav 		n = n->array[byte].edge;
81717d15b25SDag-Erling Smørgrav 		if (!n) {
81817d15b25SDag-Erling Smørgrav 			return 1;
81917d15b25SDag-Erling Smørgrav 		}
82017d15b25SDag-Erling Smørgrav 		/** Update the prefix node */
82117d15b25SDag-Erling Smørgrav 		*respos = pos;
82217d15b25SDag-Erling Smørgrav 		*result = n;
82317d15b25SDag-Erling Smørgrav 	}
82417d15b25SDag-Erling Smørgrav 	/** Done */
82517d15b25SDag-Erling Smørgrav 	return 1;
82617d15b25SDag-Erling Smørgrav }
82717d15b25SDag-Erling Smørgrav 
82817d15b25SDag-Erling Smørgrav 
82917d15b25SDag-Erling Smørgrav /**
83017d15b25SDag-Erling Smørgrav  * Make space in the node's array for another byte.
83117d15b25SDag-Erling Smørgrav  * @param node: node.
83217d15b25SDag-Erling Smørgrav  * @param byte: byte.
83317d15b25SDag-Erling Smørgrav  * @return 1 if successful, 0 otherwise.
83417d15b25SDag-Erling Smørgrav  *
83517d15b25SDag-Erling Smørgrav  */
83617d15b25SDag-Erling Smørgrav static int
ldns_radix_array_space(ldns_radix_node_t * node,uint8_t byte)83717d15b25SDag-Erling Smørgrav ldns_radix_array_space(ldns_radix_node_t* node, uint8_t byte)
83817d15b25SDag-Erling Smørgrav {
83917d15b25SDag-Erling Smørgrav 	/** Is there an array? */
84017d15b25SDag-Erling Smørgrav 	if (!node->array) {
84117d15b25SDag-Erling Smørgrav 		assert(node->capacity == 0);
84217d15b25SDag-Erling Smørgrav 		/** No array, create new array */
84317d15b25SDag-Erling Smørgrav 		node->array = LDNS_MALLOC(ldns_radix_array_t);
84417d15b25SDag-Erling Smørgrav 		if (!node->array) {
84517d15b25SDag-Erling Smørgrav 			return 0;
84617d15b25SDag-Erling Smørgrav 		}
84717d15b25SDag-Erling Smørgrav 		memset(&node->array[0], 0, sizeof(ldns_radix_array_t));
84817d15b25SDag-Erling Smørgrav 		node->len = 1;
84917d15b25SDag-Erling Smørgrav 		node->capacity = 1;
85017d15b25SDag-Erling Smørgrav 		node->offset = byte;
85117d15b25SDag-Erling Smørgrav 		return 1;
85217d15b25SDag-Erling Smørgrav 	}
85317d15b25SDag-Erling Smørgrav 	/** Array exist */
85417d15b25SDag-Erling Smørgrav 	assert(node->array != NULL);
85517d15b25SDag-Erling Smørgrav 	assert(node->capacity > 0);
85617d15b25SDag-Erling Smørgrav 
85717d15b25SDag-Erling Smørgrav 	if (node->len == 0) {
85817d15b25SDag-Erling Smørgrav 		/** Unused array */
85917d15b25SDag-Erling Smørgrav 		node->len = 1;
86017d15b25SDag-Erling Smørgrav 		node->offset = byte;
86117d15b25SDag-Erling Smørgrav 	} else if (byte < node->offset) {
86217d15b25SDag-Erling Smørgrav 		/** Byte is below the offset */
86317d15b25SDag-Erling Smørgrav 		uint8_t index;
86417d15b25SDag-Erling Smørgrav 		uint16_t need = node->offset - byte;
86517d15b25SDag-Erling Smørgrav 		/** Is there enough capacity? */
86617d15b25SDag-Erling Smørgrav 		if (node->len + need > node->capacity) {
86717d15b25SDag-Erling Smørgrav 			/** Not enough capacity, grow array */
86817d15b25SDag-Erling Smørgrav 			if (!ldns_radix_array_grow(node,
86917d15b25SDag-Erling Smørgrav 				(unsigned) (node->len + need))) {
87017d15b25SDag-Erling Smørgrav 				return 0; /* failed to grow array */
87117d15b25SDag-Erling Smørgrav 			}
87217d15b25SDag-Erling Smørgrav 		}
87317d15b25SDag-Erling Smørgrav 		/** Move items to the end */
87417d15b25SDag-Erling Smørgrav 		memmove(&node->array[need], &node->array[0],
87517d15b25SDag-Erling Smørgrav 			node->len*sizeof(ldns_radix_array_t));
87617d15b25SDag-Erling Smørgrav 		/** Fix parent index */
87717d15b25SDag-Erling Smørgrav 		for (index = 0; index < node->len; index++) {
87817d15b25SDag-Erling Smørgrav 			if (node->array[index+need].edge) {
87917d15b25SDag-Erling Smørgrav 				node->array[index+need].edge->parent_index =
88017d15b25SDag-Erling Smørgrav 					index + need;
88117d15b25SDag-Erling Smørgrav 			}
88217d15b25SDag-Erling Smørgrav 		}
88317d15b25SDag-Erling Smørgrav 		/** Zero the first */
88417d15b25SDag-Erling Smørgrav 		memset(&node->array[0], 0, need*sizeof(ldns_radix_array_t));
88517d15b25SDag-Erling Smørgrav 		node->len += need;
88617d15b25SDag-Erling Smørgrav 		node->offset = byte;
88717d15b25SDag-Erling Smørgrav 	} else if (byte - node->offset >= node->len) {
88817d15b25SDag-Erling Smørgrav 		/** Byte does not fit in array */
88917d15b25SDag-Erling Smørgrav 		uint16_t need = (byte - node->offset) - node->len + 1;
89017d15b25SDag-Erling Smørgrav 		/** Is there enough capacity? */
89117d15b25SDag-Erling Smørgrav 		if (node->len + need > node->capacity) {
89217d15b25SDag-Erling Smørgrav 			/** Not enough capacity, grow array */
89317d15b25SDag-Erling Smørgrav 			if (!ldns_radix_array_grow(node,
89417d15b25SDag-Erling Smørgrav 				(unsigned) (node->len + need))) {
89517d15b25SDag-Erling Smørgrav 				return 0; /* failed to grow array */
89617d15b25SDag-Erling Smørgrav 			}
89717d15b25SDag-Erling Smørgrav 		}
89817d15b25SDag-Erling Smørgrav 		/** Zero the added items */
89917d15b25SDag-Erling Smørgrav 		memset(&node->array[node->len], 0,
90017d15b25SDag-Erling Smørgrav 			need*sizeof(ldns_radix_array_t));
90117d15b25SDag-Erling Smørgrav 		node->len += need;
90217d15b25SDag-Erling Smørgrav 	}
90317d15b25SDag-Erling Smørgrav 	return 1;
90417d15b25SDag-Erling Smørgrav }
90517d15b25SDag-Erling Smørgrav 
90617d15b25SDag-Erling Smørgrav 
90717d15b25SDag-Erling Smørgrav /**
90817d15b25SDag-Erling Smørgrav  * Grow the array.
90917d15b25SDag-Erling Smørgrav  * @param node: node.
91017d15b25SDag-Erling Smørgrav  * @param need: number of elements the array at least need to grow.
91117d15b25SDag-Erling Smørgrav  *              Can't be bigger than 256.
91217d15b25SDag-Erling Smørgrav  * @return: 0 if failed, 1 if was successful.
91317d15b25SDag-Erling Smørgrav  *
91417d15b25SDag-Erling Smørgrav  */
91517d15b25SDag-Erling Smørgrav static int
ldns_radix_array_grow(ldns_radix_node_t * node,unsigned need)91617d15b25SDag-Erling Smørgrav ldns_radix_array_grow(ldns_radix_node_t* node, unsigned need)
91717d15b25SDag-Erling Smørgrav {
91817d15b25SDag-Erling Smørgrav 	unsigned size = ((unsigned)node->capacity)*2;
91917d15b25SDag-Erling Smørgrav 	ldns_radix_array_t* a = NULL;
92017d15b25SDag-Erling Smørgrav 	if (need > size) {
92117d15b25SDag-Erling Smørgrav 		size = need;
92217d15b25SDag-Erling Smørgrav 	}
92317d15b25SDag-Erling Smørgrav 	if (size > 256) {
92417d15b25SDag-Erling Smørgrav 		size = 256;
92517d15b25SDag-Erling Smørgrav 	}
92617d15b25SDag-Erling Smørgrav 	a = LDNS_XMALLOC(ldns_radix_array_t, size);
92717d15b25SDag-Erling Smørgrav 	if (!a) {
92817d15b25SDag-Erling Smørgrav 		return 0;
92917d15b25SDag-Erling Smørgrav 	}
93017d15b25SDag-Erling Smørgrav 	assert(node->len <= node->capacity);
93117d15b25SDag-Erling Smørgrav 	assert(node->capacity < size);
93217d15b25SDag-Erling Smørgrav 	memcpy(&a[0], &node->array[0], node->len*sizeof(ldns_radix_array_t));
93317d15b25SDag-Erling Smørgrav 	LDNS_FREE(node->array);
93417d15b25SDag-Erling Smørgrav 	node->array = a;
93517d15b25SDag-Erling Smørgrav 	node->capacity = size;
93617d15b25SDag-Erling Smørgrav 	return 1;
93717d15b25SDag-Erling Smørgrav }
93817d15b25SDag-Erling Smørgrav 
93917d15b25SDag-Erling Smørgrav 
94017d15b25SDag-Erling Smørgrav /**
94117d15b25SDag-Erling Smørgrav  * Create a prefix in the array string.
94217d15b25SDag-Erling Smørgrav  * @param array: array.
94317d15b25SDag-Erling Smørgrav  * @param key:   key.
94417d15b25SDag-Erling Smørgrav  * @param pos:   start position in key.
94517d15b25SDag-Erling Smørgrav  * @param len:   length of key.
94617d15b25SDag-Erling Smørgrav  * @return 0 if failed, 1 if was successful.
94717d15b25SDag-Erling Smørgrav  *
94817d15b25SDag-Erling Smørgrav  */
94917d15b25SDag-Erling Smørgrav static int
ldns_radix_str_create(ldns_radix_array_t * array,uint8_t * key,radix_strlen_t pos,radix_strlen_t len)95017d15b25SDag-Erling Smørgrav ldns_radix_str_create(ldns_radix_array_t* array, uint8_t* key,
95117d15b25SDag-Erling Smørgrav 	radix_strlen_t pos, radix_strlen_t len)
95217d15b25SDag-Erling Smørgrav {
95317d15b25SDag-Erling Smørgrav 	array->str = LDNS_XMALLOC(uint8_t, (len-pos));
95417d15b25SDag-Erling Smørgrav 	if (!array->str) {
95517d15b25SDag-Erling Smørgrav 		return 0;
95617d15b25SDag-Erling Smørgrav 	}
95717d15b25SDag-Erling Smørgrav 	memmove(array->str, key+pos, len-pos);
95817d15b25SDag-Erling Smørgrav 	array->len = (len-pos);
95917d15b25SDag-Erling Smørgrav 	return 1;
96017d15b25SDag-Erling Smørgrav }
96117d15b25SDag-Erling Smørgrav 
96217d15b25SDag-Erling Smørgrav 
96317d15b25SDag-Erling Smørgrav /**
96417d15b25SDag-Erling Smørgrav  * Allocate remainder from prefixes for a split.
96517d15b25SDag-Erling Smørgrav  * @param prefixlen:  length of prefix.
96617d15b25SDag-Erling Smørgrav  * @param longer_str: the longer string.
96717d15b25SDag-Erling Smørgrav  * @param longer_len: the longer string length.
96817d15b25SDag-Erling Smørgrav  * @param split_str:  the split string.
96917d15b25SDag-Erling Smørgrav  * @param split_len:  the split string length.
97017d15b25SDag-Erling Smørgrav  * @return 0 if failed, 1 if successful.
97117d15b25SDag-Erling Smørgrav  *
97217d15b25SDag-Erling Smørgrav  */
97317d15b25SDag-Erling Smørgrav static int
ldns_radix_prefix_remainder(radix_strlen_t prefix_len,uint8_t * longer_str,radix_strlen_t longer_len,uint8_t ** split_str,radix_strlen_t * split_len)97417d15b25SDag-Erling Smørgrav ldns_radix_prefix_remainder(radix_strlen_t prefix_len,
97517d15b25SDag-Erling Smørgrav 	uint8_t* longer_str, radix_strlen_t longer_len,
97617d15b25SDag-Erling Smørgrav 	uint8_t** split_str, radix_strlen_t* split_len)
97717d15b25SDag-Erling Smørgrav {
97817d15b25SDag-Erling Smørgrav 	*split_len = longer_len - prefix_len;
97917d15b25SDag-Erling Smørgrav 	*split_str = LDNS_XMALLOC(uint8_t, (*split_len));
98017d15b25SDag-Erling Smørgrav 	if (!*split_str) {
98117d15b25SDag-Erling Smørgrav 		return 0;
98217d15b25SDag-Erling Smørgrav 	}
98317d15b25SDag-Erling Smørgrav 	memmove(*split_str, longer_str+prefix_len, longer_len-prefix_len);
98417d15b25SDag-Erling Smørgrav 	return 1;
98517d15b25SDag-Erling Smørgrav }
98617d15b25SDag-Erling Smørgrav 
98717d15b25SDag-Erling Smørgrav 
98817d15b25SDag-Erling Smørgrav /**
98917d15b25SDag-Erling Smørgrav  * Create a split when two nodes have a shared prefix.
99017d15b25SDag-Erling Smørgrav  * @param array: array.
99117d15b25SDag-Erling Smørgrav  * @param key:   key.
99217d15b25SDag-Erling Smørgrav  * @param pos:   start position in key.
99317d15b25SDag-Erling Smørgrav  * @param len:   length of the key.
99417d15b25SDag-Erling Smørgrav  * @param add:   node to be added.
99517d15b25SDag-Erling Smørgrav  * @return 0 if failed, 1 if was successful.
99617d15b25SDag-Erling Smørgrav  *
99717d15b25SDag-Erling Smørgrav  */
99817d15b25SDag-Erling Smørgrav static int
ldns_radix_array_split(ldns_radix_array_t * array,uint8_t * key,radix_strlen_t pos,radix_strlen_t len,ldns_radix_node_t * add)99917d15b25SDag-Erling Smørgrav ldns_radix_array_split(ldns_radix_array_t* array, uint8_t* key,
100017d15b25SDag-Erling Smørgrav 	radix_strlen_t pos, radix_strlen_t len, ldns_radix_node_t* add)
100117d15b25SDag-Erling Smørgrav {
100217d15b25SDag-Erling Smørgrav 	uint8_t* str_to_add = key + pos;
100317d15b25SDag-Erling Smørgrav 	radix_strlen_t strlen_to_add = len - pos;
100417d15b25SDag-Erling Smørgrav 
100517d15b25SDag-Erling Smørgrav 	if (ldns_radix_str_is_prefix(str_to_add, strlen_to_add,
100617d15b25SDag-Erling Smørgrav 		array->str, array->len)) {
100717d15b25SDag-Erling Smørgrav 		/** The string to add is a prefix of the existing string */
100817d15b25SDag-Erling Smørgrav 		uint8_t* split_str = NULL, *dup_str = NULL;
100917d15b25SDag-Erling Smørgrav 		radix_strlen_t split_len = 0;
101017d15b25SDag-Erling Smørgrav 		/**
101117d15b25SDag-Erling Smørgrav 		 * Example 5: 'ld'
101217d15b25SDag-Erling Smørgrav 		 * | [0]
101317d15b25SDag-Erling Smørgrav 		 * --| [d+ns] dns
101417d15b25SDag-Erling Smørgrav 		 * --| [e+dns] edns
101517d15b25SDag-Erling Smørgrav 		 * --| [l+d] ld
101617d15b25SDag-Erling Smørgrav 		 * ----| [n+s] ldns
101717d15b25SDag-Erling Smørgrav 		 **/
101817d15b25SDag-Erling Smørgrav 		assert(strlen_to_add < array->len);
101917d15b25SDag-Erling Smørgrav 		/** Store the remainder in the split string */
102017d15b25SDag-Erling Smørgrav 		if (array->len - strlen_to_add > 1) {
102117d15b25SDag-Erling Smørgrav 			if (!ldns_radix_prefix_remainder(strlen_to_add+1,
102217d15b25SDag-Erling Smørgrav 				array->str, array->len, &split_str,
102317d15b25SDag-Erling Smørgrav 				&split_len)) {
102417d15b25SDag-Erling Smørgrav 				return 0;
102517d15b25SDag-Erling Smørgrav 			}
102617d15b25SDag-Erling Smørgrav 		}
102717d15b25SDag-Erling Smørgrav 		/** Duplicate the string to add */
102817d15b25SDag-Erling Smørgrav 		if (strlen_to_add != 0) {
102917d15b25SDag-Erling Smørgrav 			dup_str = LDNS_XMALLOC(uint8_t, strlen_to_add);
103017d15b25SDag-Erling Smørgrav 			if (!dup_str) {
103117d15b25SDag-Erling Smørgrav 				LDNS_FREE(split_str);
103217d15b25SDag-Erling Smørgrav 				return 0;
103317d15b25SDag-Erling Smørgrav 			}
103417d15b25SDag-Erling Smørgrav 			memcpy(dup_str, str_to_add, strlen_to_add);
103517d15b25SDag-Erling Smørgrav 		}
103617d15b25SDag-Erling Smørgrav 		/** Make space in array for the new node */
103717d15b25SDag-Erling Smørgrav 		if (!ldns_radix_array_space(add,
103817d15b25SDag-Erling Smørgrav 			array->str[strlen_to_add])) {
103917d15b25SDag-Erling Smørgrav 			LDNS_FREE(split_str);
104017d15b25SDag-Erling Smørgrav 			LDNS_FREE(dup_str);
104117d15b25SDag-Erling Smørgrav 			return 0;
104217d15b25SDag-Erling Smørgrav 		}
104317d15b25SDag-Erling Smørgrav 		/**
104417d15b25SDag-Erling Smørgrav 		 * The added node should go direct under the existing parent.
104517d15b25SDag-Erling Smørgrav 		 * The existing node should go under the added node.
104617d15b25SDag-Erling Smørgrav 		 */
104717d15b25SDag-Erling Smørgrav 		add->parent = array->edge->parent;
104817d15b25SDag-Erling Smørgrav 		add->parent_index = array->edge->parent_index;
104917d15b25SDag-Erling Smørgrav 		add->array[0].edge = array->edge;
105017d15b25SDag-Erling Smørgrav 		add->array[0].str = split_str;
105117d15b25SDag-Erling Smørgrav 		add->array[0].len = split_len;
105217d15b25SDag-Erling Smørgrav 		array->edge->parent = add;
105317d15b25SDag-Erling Smørgrav 		array->edge->parent_index = 0;
105417d15b25SDag-Erling Smørgrav 		LDNS_FREE(array->str);
105517d15b25SDag-Erling Smørgrav 		array->edge = add;
105617d15b25SDag-Erling Smørgrav 		array->str = dup_str;
105717d15b25SDag-Erling Smørgrav 		array->len = strlen_to_add;
105817d15b25SDag-Erling Smørgrav 	} else if (ldns_radix_str_is_prefix(array->str, array->len,
105917d15b25SDag-Erling Smørgrav 		str_to_add, strlen_to_add)) {
106017d15b25SDag-Erling Smørgrav 		/** The existing string is a prefix of the string to add */
106117d15b25SDag-Erling Smørgrav 		/**
106217d15b25SDag-Erling Smørgrav 		 * Example 6: 'dns-ng'
106317d15b25SDag-Erling Smørgrav 		 * | [0]
106417d15b25SDag-Erling Smørgrav 		 * --| [d+ns] dns
106517d15b25SDag-Erling Smørgrav 		 * ----| [-+ng] dns-ng
106617d15b25SDag-Erling Smørgrav 		 * --| [e+dns] edns
106717d15b25SDag-Erling Smørgrav 		 * --| [l+d] ld
106817d15b25SDag-Erling Smørgrav 		 * ----| [n+s] ldns
106917d15b25SDag-Erling Smørgrav 		 **/
107017d15b25SDag-Erling Smørgrav 		uint8_t* split_str = NULL;
107117d15b25SDag-Erling Smørgrav 		radix_strlen_t split_len = 0;
107217d15b25SDag-Erling Smørgrav 		assert(array->len < strlen_to_add);
107317d15b25SDag-Erling Smørgrav 		if (strlen_to_add - array->len > 1) {
107417d15b25SDag-Erling Smørgrav 			if (!ldns_radix_prefix_remainder(array->len+1,
107517d15b25SDag-Erling Smørgrav 				str_to_add, strlen_to_add, &split_str,
107617d15b25SDag-Erling Smørgrav 				&split_len)) {
107717d15b25SDag-Erling Smørgrav 				return 0;
107817d15b25SDag-Erling Smørgrav 			}
107917d15b25SDag-Erling Smørgrav 		}
108017d15b25SDag-Erling Smørgrav 		/** Make space in array for the new node */
108117d15b25SDag-Erling Smørgrav 		if (!ldns_radix_array_space(array->edge,
108217d15b25SDag-Erling Smørgrav 			str_to_add[array->len])) {
108317d15b25SDag-Erling Smørgrav 			LDNS_FREE(split_str);
108417d15b25SDag-Erling Smørgrav 			return 0;
108517d15b25SDag-Erling Smørgrav 		}
108617d15b25SDag-Erling Smørgrav 		/**
108717d15b25SDag-Erling Smørgrav 		 * The added node should go direct under the existing node.
108817d15b25SDag-Erling Smørgrav 		 */
108917d15b25SDag-Erling Smørgrav 		add->parent = array->edge;
109017d15b25SDag-Erling Smørgrav 		add->parent_index = str_to_add[array->len] -
109117d15b25SDag-Erling Smørgrav 							array->edge->offset;
109217d15b25SDag-Erling Smørgrav 		array->edge->array[add->parent_index].edge = add;
109317d15b25SDag-Erling Smørgrav 		array->edge->array[add->parent_index].str = split_str;
109417d15b25SDag-Erling Smørgrav 		array->edge->array[add->parent_index].len = split_len;
109517d15b25SDag-Erling Smørgrav 	} else {
109617d15b25SDag-Erling Smørgrav 		/** Create a new split node. */
109717d15b25SDag-Erling Smørgrav 		/**
109817d15b25SDag-Erling Smørgrav 		 * Example 7: 'dndns'
109917d15b25SDag-Erling Smørgrav 		 * | [0]
110017d15b25SDag-Erling Smørgrav 		 * --| [d+n]
110117d15b25SDag-Erling Smørgrav 		 * ----| [d+ns] dndns
110217d15b25SDag-Erling Smørgrav 		 * ----| [s] dns
110317d15b25SDag-Erling Smørgrav 		 * ------| [-+ng] dns-ng
110417d15b25SDag-Erling Smørgrav 		 * --| [e+dns] edns
110517d15b25SDag-Erling Smørgrav 		 * --| [l+d] ld
110617d15b25SDag-Erling Smørgrav 		 * ----| [n+s] ldns
110717d15b25SDag-Erling Smørgrav 		 **/
110817d15b25SDag-Erling Smørgrav 		ldns_radix_node_t* common = NULL;
110917d15b25SDag-Erling Smørgrav 		uint8_t* common_str = NULL, *s1 = NULL, *s2 = NULL;
111017d15b25SDag-Erling Smørgrav 		radix_strlen_t common_len = 0, l1 = 0, l2 = 0;
111117d15b25SDag-Erling Smørgrav 		common_len = ldns_radix_str_common(array->str, array->len,
111217d15b25SDag-Erling Smørgrav 			str_to_add, strlen_to_add);
111317d15b25SDag-Erling Smørgrav 		assert(common_len < array->len);
111417d15b25SDag-Erling Smørgrav 		assert(common_len < strlen_to_add);
111517d15b25SDag-Erling Smørgrav 		/** Create the new common node. */
111617d15b25SDag-Erling Smørgrav 		common = ldns_radix_new_node(NULL, (uint8_t*)"", 0);
111717d15b25SDag-Erling Smørgrav 		if (!common) {
111817d15b25SDag-Erling Smørgrav 			return 0;
111917d15b25SDag-Erling Smørgrav 		}
112017d15b25SDag-Erling Smørgrav 		if (array->len - common_len > 1) {
112117d15b25SDag-Erling Smørgrav 			if (!ldns_radix_prefix_remainder(common_len+1,
112217d15b25SDag-Erling Smørgrav 				array->str, array->len, &s1, &l1)) {
1123*5afab0e5SDag-Erling Smørgrav 				LDNS_FREE(common);
112417d15b25SDag-Erling Smørgrav 				return 0;
112517d15b25SDag-Erling Smørgrav 			}
112617d15b25SDag-Erling Smørgrav 		}
112717d15b25SDag-Erling Smørgrav 		if (strlen_to_add - common_len > 1) {
112817d15b25SDag-Erling Smørgrav 			if (!ldns_radix_prefix_remainder(common_len+1,
112917d15b25SDag-Erling Smørgrav 				str_to_add, strlen_to_add, &s2, &l2)) {
1130*5afab0e5SDag-Erling Smørgrav 				LDNS_FREE(common);
1131*5afab0e5SDag-Erling Smørgrav 				LDNS_FREE(s1);
113217d15b25SDag-Erling Smørgrav 				return 0;
113317d15b25SDag-Erling Smørgrav 			}
113417d15b25SDag-Erling Smørgrav 		}
113517d15b25SDag-Erling Smørgrav 		/** Create the shared prefix. */
113617d15b25SDag-Erling Smørgrav 		if (common_len > 0) {
113717d15b25SDag-Erling Smørgrav 			common_str = LDNS_XMALLOC(uint8_t, common_len);
113817d15b25SDag-Erling Smørgrav 			if (!common_str) {
113917d15b25SDag-Erling Smørgrav 				LDNS_FREE(common);
114017d15b25SDag-Erling Smørgrav 				LDNS_FREE(s1);
114117d15b25SDag-Erling Smørgrav 				LDNS_FREE(s2);
114217d15b25SDag-Erling Smørgrav 				return 0;
114317d15b25SDag-Erling Smørgrav 			}
114417d15b25SDag-Erling Smørgrav 			memcpy(common_str, str_to_add, common_len);
114517d15b25SDag-Erling Smørgrav 		}
114617d15b25SDag-Erling Smørgrav 		/** Make space in the common node array. */
114717d15b25SDag-Erling Smørgrav 		if (!ldns_radix_array_space(common, array->str[common_len]) ||
114817d15b25SDag-Erling Smørgrav 		    !ldns_radix_array_space(common, str_to_add[common_len])) {
114917d15b25SDag-Erling Smørgrav 			LDNS_FREE(common->array);
115017d15b25SDag-Erling Smørgrav 			LDNS_FREE(common);
115117d15b25SDag-Erling Smørgrav 			LDNS_FREE(common_str);
115217d15b25SDag-Erling Smørgrav 			LDNS_FREE(s1);
115317d15b25SDag-Erling Smørgrav 			LDNS_FREE(s2);
115417d15b25SDag-Erling Smørgrav 			return 0;
115517d15b25SDag-Erling Smørgrav 		}
115617d15b25SDag-Erling Smørgrav 		/**
115717d15b25SDag-Erling Smørgrav 		 * The common node should go direct under the parent node.
115817d15b25SDag-Erling Smørgrav 		 * The added and existing nodes go under the common node.
115917d15b25SDag-Erling Smørgrav 		 */
116017d15b25SDag-Erling Smørgrav 		common->parent = array->edge->parent;
116117d15b25SDag-Erling Smørgrav 		common->parent_index = array->edge->parent_index;
116217d15b25SDag-Erling Smørgrav 		array->edge->parent = common;
116317d15b25SDag-Erling Smørgrav 		array->edge->parent_index = array->str[common_len] -
116417d15b25SDag-Erling Smørgrav 								common->offset;
116517d15b25SDag-Erling Smørgrav 		add->parent = common;
116617d15b25SDag-Erling Smørgrav 		add->parent_index = str_to_add[common_len] - common->offset;
116717d15b25SDag-Erling Smørgrav 		common->array[array->edge->parent_index].edge = array->edge;
116817d15b25SDag-Erling Smørgrav 		common->array[array->edge->parent_index].str = s1;
116917d15b25SDag-Erling Smørgrav 		common->array[array->edge->parent_index].len = l1;
117017d15b25SDag-Erling Smørgrav 		common->array[add->parent_index].edge = add;
117117d15b25SDag-Erling Smørgrav 		common->array[add->parent_index].str = s2;
117217d15b25SDag-Erling Smørgrav 		common->array[add->parent_index].len = l2;
117317d15b25SDag-Erling Smørgrav 		LDNS_FREE(array->str);
117417d15b25SDag-Erling Smørgrav 		array->edge = common;
117517d15b25SDag-Erling Smørgrav 		array->str = common_str;
117617d15b25SDag-Erling Smørgrav 		array->len = common_len;
117717d15b25SDag-Erling Smørgrav 	}
117817d15b25SDag-Erling Smørgrav 	return 1;
117917d15b25SDag-Erling Smørgrav }
118017d15b25SDag-Erling Smørgrav 
118117d15b25SDag-Erling Smørgrav 
118217d15b25SDag-Erling Smørgrav /**
118317d15b25SDag-Erling Smørgrav  * Check if one string prefix of other string.
118417d15b25SDag-Erling Smørgrav  * @param str1: one string.
118517d15b25SDag-Erling Smørgrav  * @param len1: one string length.
118617d15b25SDag-Erling Smørgrav  * @param str2: other string.
118717d15b25SDag-Erling Smørgrav  * @param len2: other string length.
118817d15b25SDag-Erling Smørgrav  * @return 1 if prefix, 0 otherwise.
118917d15b25SDag-Erling Smørgrav  *
119017d15b25SDag-Erling Smørgrav  */
119117d15b25SDag-Erling Smørgrav static int
ldns_radix_str_is_prefix(uint8_t * str1,radix_strlen_t len1,uint8_t * str2,radix_strlen_t len2)119217d15b25SDag-Erling Smørgrav ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1,
119317d15b25SDag-Erling Smørgrav 	uint8_t* str2, radix_strlen_t len2)
119417d15b25SDag-Erling Smørgrav {
119517d15b25SDag-Erling Smørgrav 	if (len1 == 0) {
119617d15b25SDag-Erling Smørgrav 		return 1; /* empty prefix is also a prefix */
119717d15b25SDag-Erling Smørgrav 	}
119817d15b25SDag-Erling Smørgrav 	if (len1 > len2) {
119917d15b25SDag-Erling Smørgrav 		return 0; /* len1 is longer so str1 cannot be a prefix */
120017d15b25SDag-Erling Smørgrav 	}
120117d15b25SDag-Erling Smørgrav 	return (memcmp(str1, str2, len1) == 0);
120217d15b25SDag-Erling Smørgrav }
120317d15b25SDag-Erling Smørgrav 
120417d15b25SDag-Erling Smørgrav 
120517d15b25SDag-Erling Smørgrav /**
120617d15b25SDag-Erling Smørgrav  * Return the number of bytes in common for the two strings.
120717d15b25SDag-Erling Smørgrav  * @param str1: one string.
120817d15b25SDag-Erling Smørgrav  * @param len1: one string length.
120917d15b25SDag-Erling Smørgrav  * @param str2: other string.
121017d15b25SDag-Erling Smørgrav  * @param len2: other string length.
121117d15b25SDag-Erling Smørgrav  * @return length of substring that the two strings have in common.
121217d15b25SDag-Erling Smørgrav  *
121317d15b25SDag-Erling Smørgrav  */
121417d15b25SDag-Erling Smørgrav static radix_strlen_t
ldns_radix_str_common(uint8_t * str1,radix_strlen_t len1,uint8_t * str2,radix_strlen_t len2)121517d15b25SDag-Erling Smørgrav ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1,
121617d15b25SDag-Erling Smørgrav 	uint8_t* str2, radix_strlen_t len2)
121717d15b25SDag-Erling Smørgrav {
121817d15b25SDag-Erling Smørgrav 	radix_strlen_t i, max = (len1<len2)?len1:len2;
121917d15b25SDag-Erling Smørgrav 	for (i=0; i<max; i++) {
122017d15b25SDag-Erling Smørgrav 		if (str1[i] != str2[i]) {
122117d15b25SDag-Erling Smørgrav 			return i;
122217d15b25SDag-Erling Smørgrav 		}
122317d15b25SDag-Erling Smørgrav 	}
122417d15b25SDag-Erling Smørgrav 	return max;
122517d15b25SDag-Erling Smørgrav }
122617d15b25SDag-Erling Smørgrav 
122717d15b25SDag-Erling Smørgrav 
122817d15b25SDag-Erling Smørgrav /**
122917d15b25SDag-Erling Smørgrav  * Find the next element in the subtree of this node.
123017d15b25SDag-Erling Smørgrav  * @param node: node.
123117d15b25SDag-Erling Smørgrav  * @return: node with next element.
123217d15b25SDag-Erling Smørgrav  *
123317d15b25SDag-Erling Smørgrav  */
123417d15b25SDag-Erling Smørgrav static ldns_radix_node_t*
ldns_radix_next_in_subtree(ldns_radix_node_t * node)123517d15b25SDag-Erling Smørgrav ldns_radix_next_in_subtree(ldns_radix_node_t* node)
123617d15b25SDag-Erling Smørgrav {
123717d15b25SDag-Erling Smørgrav 	uint16_t i;
123817d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* next;
123917d15b25SDag-Erling Smørgrav 	/** Try every subnode. */
124017d15b25SDag-Erling Smørgrav 	for (i = 0; i < node->len; i++) {
124117d15b25SDag-Erling Smørgrav 		if (node->array[i].edge) {
124217d15b25SDag-Erling Smørgrav 			/** Node itself. */
124317d15b25SDag-Erling Smørgrav 			if (node->array[i].edge->data) {
124417d15b25SDag-Erling Smørgrav 				return node->array[i].edge;
124517d15b25SDag-Erling Smørgrav 			}
124617d15b25SDag-Erling Smørgrav 			/** Dive into subtree. */
124717d15b25SDag-Erling Smørgrav 			next = ldns_radix_next_in_subtree(node->array[i].edge);
124817d15b25SDag-Erling Smørgrav 			if (next) {
124917d15b25SDag-Erling Smørgrav 				return next;
125017d15b25SDag-Erling Smørgrav 			}
125117d15b25SDag-Erling Smørgrav 		}
125217d15b25SDag-Erling Smørgrav 	}
125317d15b25SDag-Erling Smørgrav 	return NULL;
125417d15b25SDag-Erling Smørgrav }
125517d15b25SDag-Erling Smørgrav 
125617d15b25SDag-Erling Smørgrav 
125717d15b25SDag-Erling Smørgrav /**
125817d15b25SDag-Erling Smørgrav  * Find the previous element in the array of this node, from index.
125917d15b25SDag-Erling Smørgrav  * @param node: node.
126017d15b25SDag-Erling Smørgrav  * @param index: index.
126117d15b25SDag-Erling Smørgrav  * @return previous node from index.
126217d15b25SDag-Erling Smørgrav  *
126317d15b25SDag-Erling Smørgrav  */
126417d15b25SDag-Erling Smørgrav static ldns_radix_node_t*
ldns_radix_prev_from_index(ldns_radix_node_t * node,uint8_t index)126517d15b25SDag-Erling Smørgrav ldns_radix_prev_from_index(ldns_radix_node_t* node, uint8_t index)
126617d15b25SDag-Erling Smørgrav {
126717d15b25SDag-Erling Smørgrav 	uint8_t i = index;
126817d15b25SDag-Erling Smørgrav 	while (i > 0) {
126917d15b25SDag-Erling Smørgrav 		i--;
127017d15b25SDag-Erling Smørgrav 		if (node->array[i].edge) {
127117d15b25SDag-Erling Smørgrav 			ldns_radix_node_t* prev =
127217d15b25SDag-Erling Smørgrav 				ldns_radix_last_in_subtree_incl_self(node);
127317d15b25SDag-Erling Smørgrav 			if (prev) {
127417d15b25SDag-Erling Smørgrav 				return prev;
127517d15b25SDag-Erling Smørgrav 			}
127617d15b25SDag-Erling Smørgrav 		}
127717d15b25SDag-Erling Smørgrav 	}
127817d15b25SDag-Erling Smørgrav 	return NULL;
127917d15b25SDag-Erling Smørgrav }
128017d15b25SDag-Erling Smørgrav 
128117d15b25SDag-Erling Smørgrav 
128217d15b25SDag-Erling Smørgrav /**
128317d15b25SDag-Erling Smørgrav  * Find last node in subtree, or this node (if have data).
128417d15b25SDag-Erling Smørgrav  * @param node: node.
128517d15b25SDag-Erling Smørgrav  * @return last node in subtree, or this node, or NULL.
128617d15b25SDag-Erling Smørgrav  *
128717d15b25SDag-Erling Smørgrav  */
128817d15b25SDag-Erling Smørgrav static ldns_radix_node_t*
ldns_radix_last_in_subtree_incl_self(ldns_radix_node_t * node)128917d15b25SDag-Erling Smørgrav ldns_radix_last_in_subtree_incl_self(ldns_radix_node_t* node)
129017d15b25SDag-Erling Smørgrav {
129117d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* last = ldns_radix_last_in_subtree(node);
129217d15b25SDag-Erling Smørgrav 	if (last) {
129317d15b25SDag-Erling Smørgrav 		return last;
129417d15b25SDag-Erling Smørgrav 	} else if (node->data) {
129517d15b25SDag-Erling Smørgrav 		return node;
129617d15b25SDag-Erling Smørgrav 	}
129717d15b25SDag-Erling Smørgrav 	return NULL;
129817d15b25SDag-Erling Smørgrav }
129917d15b25SDag-Erling Smørgrav 
130017d15b25SDag-Erling Smørgrav 
130117d15b25SDag-Erling Smørgrav /**
130217d15b25SDag-Erling Smørgrav  * Find last node in subtree.
130317d15b25SDag-Erling Smørgrav  * @param node: node.
130417d15b25SDag-Erling Smørgrav  * @return last node in subtree.
130517d15b25SDag-Erling Smørgrav  *
130617d15b25SDag-Erling Smørgrav  */
130717d15b25SDag-Erling Smørgrav static ldns_radix_node_t*
ldns_radix_last_in_subtree(ldns_radix_node_t * node)130817d15b25SDag-Erling Smørgrav ldns_radix_last_in_subtree(ldns_radix_node_t* node)
130917d15b25SDag-Erling Smørgrav {
131017d15b25SDag-Erling Smørgrav 	int i;
131117d15b25SDag-Erling Smørgrav 	/** Look for the most right leaf node. */
131217d15b25SDag-Erling Smørgrav 	for (i=(int)(node->len)-1; i >= 0; i--) {
131317d15b25SDag-Erling Smørgrav 		if (node->array[i].edge) {
131417d15b25SDag-Erling Smørgrav 			/** Keep looking for the most right leaf node. */
131517d15b25SDag-Erling Smørgrav 			if (node->array[i].edge->len > 0) {
131617d15b25SDag-Erling Smørgrav 				ldns_radix_node_t* last =
131717d15b25SDag-Erling Smørgrav 					ldns_radix_last_in_subtree(
131817d15b25SDag-Erling Smørgrav 					node->array[i].edge);
131917d15b25SDag-Erling Smørgrav 				if (last) {
132017d15b25SDag-Erling Smørgrav 					return last;
132117d15b25SDag-Erling Smørgrav 				}
132217d15b25SDag-Erling Smørgrav 			}
132317d15b25SDag-Erling Smørgrav 			/** Could this be the most right leaf node? */
132417d15b25SDag-Erling Smørgrav 			if (node->array[i].edge->data) {
132517d15b25SDag-Erling Smørgrav 				return node->array[i].edge;
132617d15b25SDag-Erling Smørgrav 			}
132717d15b25SDag-Erling Smørgrav 		}
132817d15b25SDag-Erling Smørgrav 	}
132917d15b25SDag-Erling Smørgrav 	return NULL;
133017d15b25SDag-Erling Smørgrav }
133117d15b25SDag-Erling Smørgrav 
133217d15b25SDag-Erling Smørgrav 
133317d15b25SDag-Erling Smørgrav /**
133417d15b25SDag-Erling Smørgrav  * Fix tree after deleting element.
133517d15b25SDag-Erling Smørgrav  * @param tree: tree.
133617d15b25SDag-Erling Smørgrav  * @param node: node with deleted element.
133717d15b25SDag-Erling Smørgrav  *
133817d15b25SDag-Erling Smørgrav  */
133917d15b25SDag-Erling Smørgrav static void
ldns_radix_del_fix(ldns_radix_t * tree,ldns_radix_node_t * node)134017d15b25SDag-Erling Smørgrav ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node)
134117d15b25SDag-Erling Smørgrav {
134217d15b25SDag-Erling Smørgrav 	while (node) {
134317d15b25SDag-Erling Smørgrav 		if (node->data) {
134417d15b25SDag-Erling Smørgrav 			/** Thou should not delete nodes with data attached. */
134517d15b25SDag-Erling Smørgrav 			return;
134617d15b25SDag-Erling Smørgrav 		} else if (node->len == 1 && node->parent) {
134717d15b25SDag-Erling Smørgrav 			/** Node with one child is fold back into. */
134817d15b25SDag-Erling Smørgrav 			ldns_radix_cleanup_onechild(node);
134917d15b25SDag-Erling Smørgrav 			return;
135017d15b25SDag-Erling Smørgrav 		} else if (node->len == 0) {
135117d15b25SDag-Erling Smørgrav 			/** Leaf node. */
135217d15b25SDag-Erling Smørgrav 			ldns_radix_node_t* parent = node->parent;
135317d15b25SDag-Erling Smørgrav 			if (!parent) {
135417d15b25SDag-Erling Smørgrav 				/** The root is a leaf node. */
135517d15b25SDag-Erling Smørgrav 				ldns_radix_node_free(node, NULL);
135617d15b25SDag-Erling Smørgrav 				tree->root = NULL;
135717d15b25SDag-Erling Smørgrav 				return;
135817d15b25SDag-Erling Smørgrav 			}
135917d15b25SDag-Erling Smørgrav 			/** Cleanup leaf node and continue with parent. */
136017d15b25SDag-Erling Smørgrav 			ldns_radix_cleanup_leaf(node);
136117d15b25SDag-Erling Smørgrav 			node = parent;
136217d15b25SDag-Erling Smørgrav 		} else {
136317d15b25SDag-Erling Smørgrav 			/**
136417d15b25SDag-Erling Smørgrav 			 * Node cannot be deleted, because it has edge nodes
136517d15b25SDag-Erling Smørgrav 			 * and no parent to fix up to.
136617d15b25SDag-Erling Smørgrav 			 */
136717d15b25SDag-Erling Smørgrav 			return;
136817d15b25SDag-Erling Smørgrav 		}
136917d15b25SDag-Erling Smørgrav 	}
137017d15b25SDag-Erling Smørgrav 	/** Not reached. */
137117d15b25SDag-Erling Smørgrav 	return;
137217d15b25SDag-Erling Smørgrav }
137317d15b25SDag-Erling Smørgrav 
137417d15b25SDag-Erling Smørgrav 
137517d15b25SDag-Erling Smørgrav /**
137617d15b25SDag-Erling Smørgrav  * Clean up a node with one child.
137717d15b25SDag-Erling Smørgrav  * @param node: node with one child.
137817d15b25SDag-Erling Smørgrav  *
137917d15b25SDag-Erling Smørgrav  */
138017d15b25SDag-Erling Smørgrav static void
ldns_radix_cleanup_onechild(ldns_radix_node_t * node)138117d15b25SDag-Erling Smørgrav ldns_radix_cleanup_onechild(ldns_radix_node_t* node)
138217d15b25SDag-Erling Smørgrav {
138317d15b25SDag-Erling Smørgrav 	uint8_t* join_str;
138417d15b25SDag-Erling Smørgrav 	radix_strlen_t join_len;
138517d15b25SDag-Erling Smørgrav 	uint8_t parent_index = node->parent_index;
138617d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* child = node->array[0].edge;
138717d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* parent = node->parent;
138817d15b25SDag-Erling Smørgrav 
138917d15b25SDag-Erling Smørgrav 	/** Node has one child, merge the child node into the parent node. */
139017d15b25SDag-Erling Smørgrav 	assert(parent_index < parent->len);
139117d15b25SDag-Erling Smørgrav 	join_len = parent->array[parent_index].len + node->array[0].len + 1;
139217d15b25SDag-Erling Smørgrav 
139317d15b25SDag-Erling Smørgrav 	join_str = LDNS_XMALLOC(uint8_t, join_len);
139417d15b25SDag-Erling Smørgrav 	if (!join_str) {
139517d15b25SDag-Erling Smørgrav 		/**
139617d15b25SDag-Erling Smørgrav 		 * Cleanup failed due to out of memory.
139717d15b25SDag-Erling Smørgrav 		 * This tree is now inefficient, with the empty node still
139817d15b25SDag-Erling Smørgrav 		 * existing, but it is still valid.
139917d15b25SDag-Erling Smørgrav 		 */
140017d15b25SDag-Erling Smørgrav 		return;
140117d15b25SDag-Erling Smørgrav 	}
140217d15b25SDag-Erling Smørgrav 
140317d15b25SDag-Erling Smørgrav 	memcpy(join_str, parent->array[parent_index].str,
140417d15b25SDag-Erling Smørgrav 		parent->array[parent_index].len);
140517d15b25SDag-Erling Smørgrav 	join_str[parent->array[parent_index].len] = child->parent_index +
140617d15b25SDag-Erling Smørgrav 		node->offset;
140717d15b25SDag-Erling Smørgrav 	memmove(join_str + parent->array[parent_index].len+1,
140817d15b25SDag-Erling Smørgrav 		node->array[0].str, node->array[0].len);
140917d15b25SDag-Erling Smørgrav 
141017d15b25SDag-Erling Smørgrav 	LDNS_FREE(parent->array[parent_index].str);
141117d15b25SDag-Erling Smørgrav 	parent->array[parent_index].str = join_str;
141217d15b25SDag-Erling Smørgrav 	parent->array[parent_index].len = join_len;
141317d15b25SDag-Erling Smørgrav 	parent->array[parent_index].edge = child;
141417d15b25SDag-Erling Smørgrav 	child->parent = parent;
141517d15b25SDag-Erling Smørgrav 	child->parent_index = parent_index;
141617d15b25SDag-Erling Smørgrav 	ldns_radix_node_free(node, NULL);
141717d15b25SDag-Erling Smørgrav 	return;
141817d15b25SDag-Erling Smørgrav }
141917d15b25SDag-Erling Smørgrav 
142017d15b25SDag-Erling Smørgrav 
142117d15b25SDag-Erling Smørgrav /**
142217d15b25SDag-Erling Smørgrav  * Clean up a leaf node.
142317d15b25SDag-Erling Smørgrav  * @param node: leaf node.
142417d15b25SDag-Erling Smørgrav  *
142517d15b25SDag-Erling Smørgrav  */
142617d15b25SDag-Erling Smørgrav static void
ldns_radix_cleanup_leaf(ldns_radix_node_t * node)142717d15b25SDag-Erling Smørgrav ldns_radix_cleanup_leaf(ldns_radix_node_t* node)
142817d15b25SDag-Erling Smørgrav {
142917d15b25SDag-Erling Smørgrav 	uint8_t parent_index = node->parent_index;
143017d15b25SDag-Erling Smørgrav 	ldns_radix_node_t* parent = node->parent;
143117d15b25SDag-Erling Smørgrav 	/** Delete lead node and fix parent array. */
143217d15b25SDag-Erling Smørgrav 	assert(parent_index < parent->len);
143317d15b25SDag-Erling Smørgrav 	ldns_radix_node_free(node, NULL);
143417d15b25SDag-Erling Smørgrav 	LDNS_FREE(parent->array[parent_index].str);
143517d15b25SDag-Erling Smørgrav 	parent->array[parent_index].str = NULL;
143617d15b25SDag-Erling Smørgrav 	parent->array[parent_index].len = 0;
143717d15b25SDag-Erling Smørgrav 	parent->array[parent_index].edge = NULL;
143817d15b25SDag-Erling Smørgrav 	/** Fix array in parent. */
143917d15b25SDag-Erling Smørgrav 	if (parent->len == 1) {
144017d15b25SDag-Erling Smørgrav 		ldns_radix_node_array_free(parent);
144117d15b25SDag-Erling Smørgrav 	} else if (parent_index == 0) {
144217d15b25SDag-Erling Smørgrav 		ldns_radix_node_array_free_front(parent);
144317d15b25SDag-Erling Smørgrav 	} else {
144417d15b25SDag-Erling Smørgrav 		ldns_radix_node_array_free_end(parent);
144517d15b25SDag-Erling Smørgrav 	}
144617d15b25SDag-Erling Smørgrav 	return;
144717d15b25SDag-Erling Smørgrav }
144817d15b25SDag-Erling Smørgrav 
144917d15b25SDag-Erling Smørgrav 
145017d15b25SDag-Erling Smørgrav /**
145117d15b25SDag-Erling Smørgrav  * Free a radix node.
145217d15b25SDag-Erling Smørgrav  * @param node: node.
145317d15b25SDag-Erling Smørgrav  * @param arg: user argument.
145417d15b25SDag-Erling Smørgrav  *
145517d15b25SDag-Erling Smørgrav  */
145617d15b25SDag-Erling Smørgrav static void
ldns_radix_node_free(ldns_radix_node_t * node,void * arg)145717d15b25SDag-Erling Smørgrav ldns_radix_node_free(ldns_radix_node_t* node, void* arg)
145817d15b25SDag-Erling Smørgrav {
145917d15b25SDag-Erling Smørgrav 	uint16_t i;
146017d15b25SDag-Erling Smørgrav 	(void) arg;
146117d15b25SDag-Erling Smørgrav 	if (!node) {
146217d15b25SDag-Erling Smørgrav 		return;
146317d15b25SDag-Erling Smørgrav 	}
146417d15b25SDag-Erling Smørgrav 	for (i=0; i < node->len; i++) {
146517d15b25SDag-Erling Smørgrav 		LDNS_FREE(node->array[i].str);
146617d15b25SDag-Erling Smørgrav 	}
146717d15b25SDag-Erling Smørgrav 	node->key = NULL;
146817d15b25SDag-Erling Smørgrav 	node->klen = 0;
146917d15b25SDag-Erling Smørgrav 	LDNS_FREE(node->array);
147017d15b25SDag-Erling Smørgrav 	LDNS_FREE(node);
147117d15b25SDag-Erling Smørgrav 	return;
147217d15b25SDag-Erling Smørgrav }
147317d15b25SDag-Erling Smørgrav 
147417d15b25SDag-Erling Smørgrav 
147517d15b25SDag-Erling Smørgrav /**
147617d15b25SDag-Erling Smørgrav  * Free select edge array.
147717d15b25SDag-Erling Smørgrav  * @param node: node.
147817d15b25SDag-Erling Smørgrav  *
147917d15b25SDag-Erling Smørgrav  */
148017d15b25SDag-Erling Smørgrav static void
ldns_radix_node_array_free(ldns_radix_node_t * node)148117d15b25SDag-Erling Smørgrav ldns_radix_node_array_free(ldns_radix_node_t* node)
148217d15b25SDag-Erling Smørgrav {
148317d15b25SDag-Erling Smørgrav 	node->offset = 0;
148417d15b25SDag-Erling Smørgrav 	node->len = 0;
148517d15b25SDag-Erling Smørgrav 	LDNS_FREE(node->array);
148617d15b25SDag-Erling Smørgrav 	node->array = NULL;
148717d15b25SDag-Erling Smørgrav 	node->capacity = 0;
148817d15b25SDag-Erling Smørgrav 	return;
148917d15b25SDag-Erling Smørgrav }
149017d15b25SDag-Erling Smørgrav 
149117d15b25SDag-Erling Smørgrav 
149217d15b25SDag-Erling Smørgrav /**
149317d15b25SDag-Erling Smørgrav  * Free front of select edge array.
149417d15b25SDag-Erling Smørgrav  * @param node: node.
149517d15b25SDag-Erling Smørgrav  *
149617d15b25SDag-Erling Smørgrav  */
149717d15b25SDag-Erling Smørgrav static void
ldns_radix_node_array_free_front(ldns_radix_node_t * node)149817d15b25SDag-Erling Smørgrav ldns_radix_node_array_free_front(ldns_radix_node_t* node)
149917d15b25SDag-Erling Smørgrav {
150017d15b25SDag-Erling Smørgrav 	uint16_t i, n = 0;
150117d15b25SDag-Erling Smørgrav 	/** Remove until a non NULL entry. */
150217d15b25SDag-Erling Smørgrav    	while (n < node->len && node->array[n].edge == NULL) {
150317d15b25SDag-Erling Smørgrav 		n++;
150417d15b25SDag-Erling Smørgrav 	}
150517d15b25SDag-Erling Smørgrav 	if (n == 0) {
150617d15b25SDag-Erling Smørgrav 		return;
150717d15b25SDag-Erling Smørgrav 	}
150817d15b25SDag-Erling Smørgrav 	if (n == node->len) {
150917d15b25SDag-Erling Smørgrav 		ldns_radix_node_array_free(node);
151017d15b25SDag-Erling Smørgrav 		return;
151117d15b25SDag-Erling Smørgrav 	}
151217d15b25SDag-Erling Smørgrav 	assert(n < node->len);
151317d15b25SDag-Erling Smørgrav 	assert((int) n <= (255 - (int) node->offset));
151417d15b25SDag-Erling Smørgrav 	memmove(&node->array[0], &node->array[n],
151517d15b25SDag-Erling Smørgrav 		(node->len - n)*sizeof(ldns_radix_array_t));
151617d15b25SDag-Erling Smørgrav 	node->offset += n;
151717d15b25SDag-Erling Smørgrav 	node->len -= n;
151817d15b25SDag-Erling Smørgrav 	for (i=0; i < node->len; i++) {
151917d15b25SDag-Erling Smørgrav 		if (node->array[i].edge) {
152017d15b25SDag-Erling Smørgrav 			node->array[i].edge->parent_index = i;
152117d15b25SDag-Erling Smørgrav 		}
152217d15b25SDag-Erling Smørgrav 	}
152317d15b25SDag-Erling Smørgrav 	ldns_radix_array_reduce(node);
152417d15b25SDag-Erling Smørgrav 	return;
152517d15b25SDag-Erling Smørgrav }
152617d15b25SDag-Erling Smørgrav 
152717d15b25SDag-Erling Smørgrav 
152817d15b25SDag-Erling Smørgrav /**
152917d15b25SDag-Erling Smørgrav  * Free front of select edge array.
153017d15b25SDag-Erling Smørgrav  * @param node: node.
153117d15b25SDag-Erling Smørgrav  *
153217d15b25SDag-Erling Smørgrav  */
153317d15b25SDag-Erling Smørgrav static void
ldns_radix_node_array_free_end(ldns_radix_node_t * node)153417d15b25SDag-Erling Smørgrav ldns_radix_node_array_free_end(ldns_radix_node_t* node)
153517d15b25SDag-Erling Smørgrav {
153617d15b25SDag-Erling Smørgrav 	uint16_t n = 0;
153717d15b25SDag-Erling Smørgrav 	/** Shorten array. */
153817d15b25SDag-Erling Smørgrav 	while (n < node->len && node->array[node->len-1-n].edge == NULL) {
153917d15b25SDag-Erling Smørgrav 		n++;
154017d15b25SDag-Erling Smørgrav 	}
154117d15b25SDag-Erling Smørgrav 	if (n == 0) {
154217d15b25SDag-Erling Smørgrav 		return;
154317d15b25SDag-Erling Smørgrav 	}
154417d15b25SDag-Erling Smørgrav 	if (n == node->len) {
154517d15b25SDag-Erling Smørgrav 		ldns_radix_node_array_free(node);
154617d15b25SDag-Erling Smørgrav 		return;
154717d15b25SDag-Erling Smørgrav 	}
154817d15b25SDag-Erling Smørgrav 	assert(n < node->len);
154917d15b25SDag-Erling Smørgrav 	node->len -= n;
155017d15b25SDag-Erling Smørgrav 	ldns_radix_array_reduce(node);
155117d15b25SDag-Erling Smørgrav 	return;
155217d15b25SDag-Erling Smørgrav }
155317d15b25SDag-Erling Smørgrav 
155417d15b25SDag-Erling Smørgrav 
155517d15b25SDag-Erling Smørgrav /**
155617d15b25SDag-Erling Smørgrav  * Reduce the capacity of the array if needed.
155717d15b25SDag-Erling Smørgrav  * @param node: node.
155817d15b25SDag-Erling Smørgrav  *
155917d15b25SDag-Erling Smørgrav  */
156017d15b25SDag-Erling Smørgrav static void
ldns_radix_array_reduce(ldns_radix_node_t * node)156117d15b25SDag-Erling Smørgrav ldns_radix_array_reduce(ldns_radix_node_t* node)
156217d15b25SDag-Erling Smørgrav {
156317d15b25SDag-Erling Smørgrav 	if (node->len <= node->capacity/2 && node->len != node->capacity) {
156417d15b25SDag-Erling Smørgrav 		ldns_radix_array_t* a = LDNS_XMALLOC(ldns_radix_array_t,
156517d15b25SDag-Erling Smørgrav 								node->len);
156617d15b25SDag-Erling Smørgrav 		if (!a) {
156717d15b25SDag-Erling Smørgrav 			return;
156817d15b25SDag-Erling Smørgrav 		}
156917d15b25SDag-Erling Smørgrav 		memcpy(a, node->array, sizeof(ldns_radix_array_t)*node->len);
157017d15b25SDag-Erling Smørgrav 		LDNS_FREE(node->array);
157117d15b25SDag-Erling Smørgrav 		node->array = a;
157217d15b25SDag-Erling Smørgrav 		node->capacity = node->len;
157317d15b25SDag-Erling Smørgrav 	}
157417d15b25SDag-Erling Smørgrav 	return;
157517d15b25SDag-Erling Smørgrav }
157617d15b25SDag-Erling Smørgrav 
157717d15b25SDag-Erling Smørgrav 
157817d15b25SDag-Erling Smørgrav /**
157917d15b25SDag-Erling Smørgrav  * Return this element if it exists, the previous otherwise.
158017d15b25SDag-Erling Smørgrav  * @param node: from this node.
158117d15b25SDag-Erling Smørgrav  * @param result: result node.
158217d15b25SDag-Erling Smørgrav  *
158317d15b25SDag-Erling Smørgrav  */
158417d15b25SDag-Erling Smørgrav static void
ldns_radix_self_or_prev(ldns_radix_node_t * node,ldns_radix_node_t ** result)158517d15b25SDag-Erling Smørgrav ldns_radix_self_or_prev(ldns_radix_node_t* node, ldns_radix_node_t** result)
158617d15b25SDag-Erling Smørgrav {
158717d15b25SDag-Erling Smørgrav 	if (node->data) {
158817d15b25SDag-Erling Smørgrav 		*result = node;
158917d15b25SDag-Erling Smørgrav 	} else {
159017d15b25SDag-Erling Smørgrav 		*result = ldns_radix_prev(node);
159117d15b25SDag-Erling Smørgrav 	}
159217d15b25SDag-Erling Smørgrav 	return;
159317d15b25SDag-Erling Smørgrav }
1594