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