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 26*986ba33cSDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27*986ba33cSDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28*986ba33cSDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29*986ba33cSDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30*986ba33cSDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31*986ba33cSDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32*986ba33cSDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33*986ba33cSDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34*986ba33cSDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35*986ba33cSDag-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* 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 * 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 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 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 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 */ 22817d15b25SDag-Erling Smørgrav if (prefix->data) { 22917d15b25SDag-Erling Smørgrav /* Element already exists */ 23017d15b25SDag-Erling Smørgrav LDNS_FREE(add); 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 */ 314*986ba33cSDag-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* 334*986ba33cSDag-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 380*986ba33cSDag-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* 480*986ba33cSDag-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* 499*986ba33cSDag-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* 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* 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 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 624*986ba33cSDag-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 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 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 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 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 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 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 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 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 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)) { 112317d15b25SDag-Erling Smørgrav return 0; 112417d15b25SDag-Erling Smørgrav } 112517d15b25SDag-Erling Smørgrav } 112617d15b25SDag-Erling Smørgrav if (strlen_to_add - common_len > 1) { 112717d15b25SDag-Erling Smørgrav if (!ldns_radix_prefix_remainder(common_len+1, 112817d15b25SDag-Erling Smørgrav str_to_add, strlen_to_add, &s2, &l2)) { 112917d15b25SDag-Erling Smørgrav return 0; 113017d15b25SDag-Erling Smørgrav } 113117d15b25SDag-Erling Smørgrav } 113217d15b25SDag-Erling Smørgrav /** Create the shared prefix. */ 113317d15b25SDag-Erling Smørgrav if (common_len > 0) { 113417d15b25SDag-Erling Smørgrav common_str = LDNS_XMALLOC(uint8_t, common_len); 113517d15b25SDag-Erling Smørgrav if (!common_str) { 113617d15b25SDag-Erling Smørgrav LDNS_FREE(common); 113717d15b25SDag-Erling Smørgrav LDNS_FREE(s1); 113817d15b25SDag-Erling Smørgrav LDNS_FREE(s2); 113917d15b25SDag-Erling Smørgrav return 0; 114017d15b25SDag-Erling Smørgrav } 114117d15b25SDag-Erling Smørgrav memcpy(common_str, str_to_add, common_len); 114217d15b25SDag-Erling Smørgrav } 114317d15b25SDag-Erling Smørgrav /** Make space in the common node array. */ 114417d15b25SDag-Erling Smørgrav if (!ldns_radix_array_space(common, array->str[common_len]) || 114517d15b25SDag-Erling Smørgrav !ldns_radix_array_space(common, str_to_add[common_len])) { 114617d15b25SDag-Erling Smørgrav LDNS_FREE(common->array); 114717d15b25SDag-Erling Smørgrav LDNS_FREE(common); 114817d15b25SDag-Erling Smørgrav LDNS_FREE(common_str); 114917d15b25SDag-Erling Smørgrav LDNS_FREE(s1); 115017d15b25SDag-Erling Smørgrav LDNS_FREE(s2); 115117d15b25SDag-Erling Smørgrav return 0; 115217d15b25SDag-Erling Smørgrav } 115317d15b25SDag-Erling Smørgrav /** 115417d15b25SDag-Erling Smørgrav * The common node should go direct under the parent node. 115517d15b25SDag-Erling Smørgrav * The added and existing nodes go under the common node. 115617d15b25SDag-Erling Smørgrav */ 115717d15b25SDag-Erling Smørgrav common->parent = array->edge->parent; 115817d15b25SDag-Erling Smørgrav common->parent_index = array->edge->parent_index; 115917d15b25SDag-Erling Smørgrav array->edge->parent = common; 116017d15b25SDag-Erling Smørgrav array->edge->parent_index = array->str[common_len] - 116117d15b25SDag-Erling Smørgrav common->offset; 116217d15b25SDag-Erling Smørgrav add->parent = common; 116317d15b25SDag-Erling Smørgrav add->parent_index = str_to_add[common_len] - common->offset; 116417d15b25SDag-Erling Smørgrav common->array[array->edge->parent_index].edge = array->edge; 116517d15b25SDag-Erling Smørgrav common->array[array->edge->parent_index].str = s1; 116617d15b25SDag-Erling Smørgrav common->array[array->edge->parent_index].len = l1; 116717d15b25SDag-Erling Smørgrav common->array[add->parent_index].edge = add; 116817d15b25SDag-Erling Smørgrav common->array[add->parent_index].str = s2; 116917d15b25SDag-Erling Smørgrav common->array[add->parent_index].len = l2; 117017d15b25SDag-Erling Smørgrav LDNS_FREE(array->str); 117117d15b25SDag-Erling Smørgrav array->edge = common; 117217d15b25SDag-Erling Smørgrav array->str = common_str; 117317d15b25SDag-Erling Smørgrav array->len = common_len; 117417d15b25SDag-Erling Smørgrav } 117517d15b25SDag-Erling Smørgrav return 1; 117617d15b25SDag-Erling Smørgrav } 117717d15b25SDag-Erling Smørgrav 117817d15b25SDag-Erling Smørgrav 117917d15b25SDag-Erling Smørgrav /** 118017d15b25SDag-Erling Smørgrav * Check if one string prefix of other string. 118117d15b25SDag-Erling Smørgrav * @param str1: one string. 118217d15b25SDag-Erling Smørgrav * @param len1: one string length. 118317d15b25SDag-Erling Smørgrav * @param str2: other string. 118417d15b25SDag-Erling Smørgrav * @param len2: other string length. 118517d15b25SDag-Erling Smørgrav * @return 1 if prefix, 0 otherwise. 118617d15b25SDag-Erling Smørgrav * 118717d15b25SDag-Erling Smørgrav */ 118817d15b25SDag-Erling Smørgrav static int 118917d15b25SDag-Erling Smørgrav ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1, 119017d15b25SDag-Erling Smørgrav uint8_t* str2, radix_strlen_t len2) 119117d15b25SDag-Erling Smørgrav { 119217d15b25SDag-Erling Smørgrav if (len1 == 0) { 119317d15b25SDag-Erling Smørgrav return 1; /* empty prefix is also a prefix */ 119417d15b25SDag-Erling Smørgrav } 119517d15b25SDag-Erling Smørgrav if (len1 > len2) { 119617d15b25SDag-Erling Smørgrav return 0; /* len1 is longer so str1 cannot be a prefix */ 119717d15b25SDag-Erling Smørgrav } 119817d15b25SDag-Erling Smørgrav return (memcmp(str1, str2, len1) == 0); 119917d15b25SDag-Erling Smørgrav } 120017d15b25SDag-Erling Smørgrav 120117d15b25SDag-Erling Smørgrav 120217d15b25SDag-Erling Smørgrav /** 120317d15b25SDag-Erling Smørgrav * Return the number of bytes in common for the two strings. 120417d15b25SDag-Erling Smørgrav * @param str1: one string. 120517d15b25SDag-Erling Smørgrav * @param len1: one string length. 120617d15b25SDag-Erling Smørgrav * @param str2: other string. 120717d15b25SDag-Erling Smørgrav * @param len2: other string length. 120817d15b25SDag-Erling Smørgrav * @return length of substring that the two strings have in common. 120917d15b25SDag-Erling Smørgrav * 121017d15b25SDag-Erling Smørgrav */ 121117d15b25SDag-Erling Smørgrav static radix_strlen_t 121217d15b25SDag-Erling Smørgrav ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1, 121317d15b25SDag-Erling Smørgrav uint8_t* str2, radix_strlen_t len2) 121417d15b25SDag-Erling Smørgrav { 121517d15b25SDag-Erling Smørgrav radix_strlen_t i, max = (len1<len2)?len1:len2; 121617d15b25SDag-Erling Smørgrav for (i=0; i<max; i++) { 121717d15b25SDag-Erling Smørgrav if (str1[i] != str2[i]) { 121817d15b25SDag-Erling Smørgrav return i; 121917d15b25SDag-Erling Smørgrav } 122017d15b25SDag-Erling Smørgrav } 122117d15b25SDag-Erling Smørgrav return max; 122217d15b25SDag-Erling Smørgrav } 122317d15b25SDag-Erling Smørgrav 122417d15b25SDag-Erling Smørgrav 122517d15b25SDag-Erling Smørgrav /** 122617d15b25SDag-Erling Smørgrav * Find the next element in the subtree of this node. 122717d15b25SDag-Erling Smørgrav * @param node: node. 122817d15b25SDag-Erling Smørgrav * @return: node with next element. 122917d15b25SDag-Erling Smørgrav * 123017d15b25SDag-Erling Smørgrav */ 123117d15b25SDag-Erling Smørgrav static ldns_radix_node_t* 123217d15b25SDag-Erling Smørgrav ldns_radix_next_in_subtree(ldns_radix_node_t* node) 123317d15b25SDag-Erling Smørgrav { 123417d15b25SDag-Erling Smørgrav uint16_t i; 123517d15b25SDag-Erling Smørgrav ldns_radix_node_t* next; 123617d15b25SDag-Erling Smørgrav /** Try every subnode. */ 123717d15b25SDag-Erling Smørgrav for (i = 0; i < node->len; i++) { 123817d15b25SDag-Erling Smørgrav if (node->array[i].edge) { 123917d15b25SDag-Erling Smørgrav /** Node itself. */ 124017d15b25SDag-Erling Smørgrav if (node->array[i].edge->data) { 124117d15b25SDag-Erling Smørgrav return node->array[i].edge; 124217d15b25SDag-Erling Smørgrav } 124317d15b25SDag-Erling Smørgrav /** Dive into subtree. */ 124417d15b25SDag-Erling Smørgrav next = ldns_radix_next_in_subtree(node->array[i].edge); 124517d15b25SDag-Erling Smørgrav if (next) { 124617d15b25SDag-Erling Smørgrav return next; 124717d15b25SDag-Erling Smørgrav } 124817d15b25SDag-Erling Smørgrav } 124917d15b25SDag-Erling Smørgrav } 125017d15b25SDag-Erling Smørgrav return NULL; 125117d15b25SDag-Erling Smørgrav } 125217d15b25SDag-Erling Smørgrav 125317d15b25SDag-Erling Smørgrav 125417d15b25SDag-Erling Smørgrav /** 125517d15b25SDag-Erling Smørgrav * Find the previous element in the array of this node, from index. 125617d15b25SDag-Erling Smørgrav * @param node: node. 125717d15b25SDag-Erling Smørgrav * @param index: index. 125817d15b25SDag-Erling Smørgrav * @return previous node from index. 125917d15b25SDag-Erling Smørgrav * 126017d15b25SDag-Erling Smørgrav */ 126117d15b25SDag-Erling Smørgrav static ldns_radix_node_t* 126217d15b25SDag-Erling Smørgrav ldns_radix_prev_from_index(ldns_radix_node_t* node, uint8_t index) 126317d15b25SDag-Erling Smørgrav { 126417d15b25SDag-Erling Smørgrav uint8_t i = index; 126517d15b25SDag-Erling Smørgrav while (i > 0) { 126617d15b25SDag-Erling Smørgrav i--; 126717d15b25SDag-Erling Smørgrav if (node->array[i].edge) { 126817d15b25SDag-Erling Smørgrav ldns_radix_node_t* prev = 126917d15b25SDag-Erling Smørgrav ldns_radix_last_in_subtree_incl_self(node); 127017d15b25SDag-Erling Smørgrav if (prev) { 127117d15b25SDag-Erling Smørgrav return prev; 127217d15b25SDag-Erling Smørgrav } 127317d15b25SDag-Erling Smørgrav } 127417d15b25SDag-Erling Smørgrav } 127517d15b25SDag-Erling Smørgrav return NULL; 127617d15b25SDag-Erling Smørgrav } 127717d15b25SDag-Erling Smørgrav 127817d15b25SDag-Erling Smørgrav 127917d15b25SDag-Erling Smørgrav /** 128017d15b25SDag-Erling Smørgrav * Find last node in subtree, or this node (if have data). 128117d15b25SDag-Erling Smørgrav * @param node: node. 128217d15b25SDag-Erling Smørgrav * @return last node in subtree, or this node, or NULL. 128317d15b25SDag-Erling Smørgrav * 128417d15b25SDag-Erling Smørgrav */ 128517d15b25SDag-Erling Smørgrav static ldns_radix_node_t* 128617d15b25SDag-Erling Smørgrav ldns_radix_last_in_subtree_incl_self(ldns_radix_node_t* node) 128717d15b25SDag-Erling Smørgrav { 128817d15b25SDag-Erling Smørgrav ldns_radix_node_t* last = ldns_radix_last_in_subtree(node); 128917d15b25SDag-Erling Smørgrav if (last) { 129017d15b25SDag-Erling Smørgrav return last; 129117d15b25SDag-Erling Smørgrav } else if (node->data) { 129217d15b25SDag-Erling Smørgrav return node; 129317d15b25SDag-Erling Smørgrav } 129417d15b25SDag-Erling Smørgrav return NULL; 129517d15b25SDag-Erling Smørgrav } 129617d15b25SDag-Erling Smørgrav 129717d15b25SDag-Erling Smørgrav 129817d15b25SDag-Erling Smørgrav /** 129917d15b25SDag-Erling Smørgrav * Find last node in subtree. 130017d15b25SDag-Erling Smørgrav * @param node: node. 130117d15b25SDag-Erling Smørgrav * @return last node in subtree. 130217d15b25SDag-Erling Smørgrav * 130317d15b25SDag-Erling Smørgrav */ 130417d15b25SDag-Erling Smørgrav static ldns_radix_node_t* 130517d15b25SDag-Erling Smørgrav ldns_radix_last_in_subtree(ldns_radix_node_t* node) 130617d15b25SDag-Erling Smørgrav { 130717d15b25SDag-Erling Smørgrav int i; 130817d15b25SDag-Erling Smørgrav /** Look for the most right leaf node. */ 130917d15b25SDag-Erling Smørgrav for (i=(int)(node->len)-1; i >= 0; i--) { 131017d15b25SDag-Erling Smørgrav if (node->array[i].edge) { 131117d15b25SDag-Erling Smørgrav /** Keep looking for the most right leaf node. */ 131217d15b25SDag-Erling Smørgrav if (node->array[i].edge->len > 0) { 131317d15b25SDag-Erling Smørgrav ldns_radix_node_t* last = 131417d15b25SDag-Erling Smørgrav ldns_radix_last_in_subtree( 131517d15b25SDag-Erling Smørgrav node->array[i].edge); 131617d15b25SDag-Erling Smørgrav if (last) { 131717d15b25SDag-Erling Smørgrav return last; 131817d15b25SDag-Erling Smørgrav } 131917d15b25SDag-Erling Smørgrav } 132017d15b25SDag-Erling Smørgrav /** Could this be the most right leaf node? */ 132117d15b25SDag-Erling Smørgrav if (node->array[i].edge->data) { 132217d15b25SDag-Erling Smørgrav return node->array[i].edge; 132317d15b25SDag-Erling Smørgrav } 132417d15b25SDag-Erling Smørgrav } 132517d15b25SDag-Erling Smørgrav } 132617d15b25SDag-Erling Smørgrav return NULL; 132717d15b25SDag-Erling Smørgrav } 132817d15b25SDag-Erling Smørgrav 132917d15b25SDag-Erling Smørgrav 133017d15b25SDag-Erling Smørgrav /** 133117d15b25SDag-Erling Smørgrav * Fix tree after deleting element. 133217d15b25SDag-Erling Smørgrav * @param tree: tree. 133317d15b25SDag-Erling Smørgrav * @param node: node with deleted element. 133417d15b25SDag-Erling Smørgrav * 133517d15b25SDag-Erling Smørgrav */ 133617d15b25SDag-Erling Smørgrav static void 133717d15b25SDag-Erling Smørgrav ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node) 133817d15b25SDag-Erling Smørgrav { 133917d15b25SDag-Erling Smørgrav while (node) { 134017d15b25SDag-Erling Smørgrav if (node->data) { 134117d15b25SDag-Erling Smørgrav /** Thou should not delete nodes with data attached. */ 134217d15b25SDag-Erling Smørgrav return; 134317d15b25SDag-Erling Smørgrav } else if (node->len == 1 && node->parent) { 134417d15b25SDag-Erling Smørgrav /** Node with one child is fold back into. */ 134517d15b25SDag-Erling Smørgrav ldns_radix_cleanup_onechild(node); 134617d15b25SDag-Erling Smørgrav return; 134717d15b25SDag-Erling Smørgrav } else if (node->len == 0) { 134817d15b25SDag-Erling Smørgrav /** Leaf node. */ 134917d15b25SDag-Erling Smørgrav ldns_radix_node_t* parent = node->parent; 135017d15b25SDag-Erling Smørgrav if (!parent) { 135117d15b25SDag-Erling Smørgrav /** The root is a leaf node. */ 135217d15b25SDag-Erling Smørgrav ldns_radix_node_free(node, NULL); 135317d15b25SDag-Erling Smørgrav tree->root = NULL; 135417d15b25SDag-Erling Smørgrav return; 135517d15b25SDag-Erling Smørgrav } 135617d15b25SDag-Erling Smørgrav /** Cleanup leaf node and continue with parent. */ 135717d15b25SDag-Erling Smørgrav ldns_radix_cleanup_leaf(node); 135817d15b25SDag-Erling Smørgrav node = parent; 135917d15b25SDag-Erling Smørgrav } else { 136017d15b25SDag-Erling Smørgrav /** 136117d15b25SDag-Erling Smørgrav * Node cannot be deleted, because it has edge nodes 136217d15b25SDag-Erling Smørgrav * and no parent to fix up to. 136317d15b25SDag-Erling Smørgrav */ 136417d15b25SDag-Erling Smørgrav return; 136517d15b25SDag-Erling Smørgrav } 136617d15b25SDag-Erling Smørgrav } 136717d15b25SDag-Erling Smørgrav /** Not reached. */ 136817d15b25SDag-Erling Smørgrav return; 136917d15b25SDag-Erling Smørgrav } 137017d15b25SDag-Erling Smørgrav 137117d15b25SDag-Erling Smørgrav 137217d15b25SDag-Erling Smørgrav /** 137317d15b25SDag-Erling Smørgrav * Clean up a node with one child. 137417d15b25SDag-Erling Smørgrav * @param node: node with one child. 137517d15b25SDag-Erling Smørgrav * 137617d15b25SDag-Erling Smørgrav */ 137717d15b25SDag-Erling Smørgrav static void 137817d15b25SDag-Erling Smørgrav ldns_radix_cleanup_onechild(ldns_radix_node_t* node) 137917d15b25SDag-Erling Smørgrav { 138017d15b25SDag-Erling Smørgrav uint8_t* join_str; 138117d15b25SDag-Erling Smørgrav radix_strlen_t join_len; 138217d15b25SDag-Erling Smørgrav uint8_t parent_index = node->parent_index; 138317d15b25SDag-Erling Smørgrav ldns_radix_node_t* child = node->array[0].edge; 138417d15b25SDag-Erling Smørgrav ldns_radix_node_t* parent = node->parent; 138517d15b25SDag-Erling Smørgrav 138617d15b25SDag-Erling Smørgrav /** Node has one child, merge the child node into the parent node. */ 138717d15b25SDag-Erling Smørgrav assert(parent_index < parent->len); 138817d15b25SDag-Erling Smørgrav join_len = parent->array[parent_index].len + node->array[0].len + 1; 138917d15b25SDag-Erling Smørgrav 139017d15b25SDag-Erling Smørgrav join_str = LDNS_XMALLOC(uint8_t, join_len); 139117d15b25SDag-Erling Smørgrav if (!join_str) { 139217d15b25SDag-Erling Smørgrav /** 139317d15b25SDag-Erling Smørgrav * Cleanup failed due to out of memory. 139417d15b25SDag-Erling Smørgrav * This tree is now inefficient, with the empty node still 139517d15b25SDag-Erling Smørgrav * existing, but it is still valid. 139617d15b25SDag-Erling Smørgrav */ 139717d15b25SDag-Erling Smørgrav return; 139817d15b25SDag-Erling Smørgrav } 139917d15b25SDag-Erling Smørgrav 140017d15b25SDag-Erling Smørgrav memcpy(join_str, parent->array[parent_index].str, 140117d15b25SDag-Erling Smørgrav parent->array[parent_index].len); 140217d15b25SDag-Erling Smørgrav join_str[parent->array[parent_index].len] = child->parent_index + 140317d15b25SDag-Erling Smørgrav node->offset; 140417d15b25SDag-Erling Smørgrav memmove(join_str + parent->array[parent_index].len+1, 140517d15b25SDag-Erling Smørgrav node->array[0].str, node->array[0].len); 140617d15b25SDag-Erling Smørgrav 140717d15b25SDag-Erling Smørgrav LDNS_FREE(parent->array[parent_index].str); 140817d15b25SDag-Erling Smørgrav parent->array[parent_index].str = join_str; 140917d15b25SDag-Erling Smørgrav parent->array[parent_index].len = join_len; 141017d15b25SDag-Erling Smørgrav parent->array[parent_index].edge = child; 141117d15b25SDag-Erling Smørgrav child->parent = parent; 141217d15b25SDag-Erling Smørgrav child->parent_index = parent_index; 141317d15b25SDag-Erling Smørgrav ldns_radix_node_free(node, NULL); 141417d15b25SDag-Erling Smørgrav return; 141517d15b25SDag-Erling Smørgrav } 141617d15b25SDag-Erling Smørgrav 141717d15b25SDag-Erling Smørgrav 141817d15b25SDag-Erling Smørgrav /** 141917d15b25SDag-Erling Smørgrav * Clean up a leaf node. 142017d15b25SDag-Erling Smørgrav * @param node: leaf node. 142117d15b25SDag-Erling Smørgrav * 142217d15b25SDag-Erling Smørgrav */ 142317d15b25SDag-Erling Smørgrav static void 142417d15b25SDag-Erling Smørgrav ldns_radix_cleanup_leaf(ldns_radix_node_t* node) 142517d15b25SDag-Erling Smørgrav { 142617d15b25SDag-Erling Smørgrav uint8_t parent_index = node->parent_index; 142717d15b25SDag-Erling Smørgrav ldns_radix_node_t* parent = node->parent; 142817d15b25SDag-Erling Smørgrav /** Delete lead node and fix parent array. */ 142917d15b25SDag-Erling Smørgrav assert(parent_index < parent->len); 143017d15b25SDag-Erling Smørgrav ldns_radix_node_free(node, NULL); 143117d15b25SDag-Erling Smørgrav LDNS_FREE(parent->array[parent_index].str); 143217d15b25SDag-Erling Smørgrav parent->array[parent_index].str = NULL; 143317d15b25SDag-Erling Smørgrav parent->array[parent_index].len = 0; 143417d15b25SDag-Erling Smørgrav parent->array[parent_index].edge = NULL; 143517d15b25SDag-Erling Smørgrav /** Fix array in parent. */ 143617d15b25SDag-Erling Smørgrav if (parent->len == 1) { 143717d15b25SDag-Erling Smørgrav ldns_radix_node_array_free(parent); 143817d15b25SDag-Erling Smørgrav } else if (parent_index == 0) { 143917d15b25SDag-Erling Smørgrav ldns_radix_node_array_free_front(parent); 144017d15b25SDag-Erling Smørgrav } else { 144117d15b25SDag-Erling Smørgrav ldns_radix_node_array_free_end(parent); 144217d15b25SDag-Erling Smørgrav } 144317d15b25SDag-Erling Smørgrav return; 144417d15b25SDag-Erling Smørgrav } 144517d15b25SDag-Erling Smørgrav 144617d15b25SDag-Erling Smørgrav 144717d15b25SDag-Erling Smørgrav /** 144817d15b25SDag-Erling Smørgrav * Free a radix node. 144917d15b25SDag-Erling Smørgrav * @param node: node. 145017d15b25SDag-Erling Smørgrav * @param arg: user argument. 145117d15b25SDag-Erling Smørgrav * 145217d15b25SDag-Erling Smørgrav */ 145317d15b25SDag-Erling Smørgrav static void 145417d15b25SDag-Erling Smørgrav ldns_radix_node_free(ldns_radix_node_t* node, void* arg) 145517d15b25SDag-Erling Smørgrav { 145617d15b25SDag-Erling Smørgrav uint16_t i; 145717d15b25SDag-Erling Smørgrav (void) arg; 145817d15b25SDag-Erling Smørgrav if (!node) { 145917d15b25SDag-Erling Smørgrav return; 146017d15b25SDag-Erling Smørgrav } 146117d15b25SDag-Erling Smørgrav for (i=0; i < node->len; i++) { 146217d15b25SDag-Erling Smørgrav LDNS_FREE(node->array[i].str); 146317d15b25SDag-Erling Smørgrav } 146417d15b25SDag-Erling Smørgrav node->key = NULL; 146517d15b25SDag-Erling Smørgrav node->klen = 0; 146617d15b25SDag-Erling Smørgrav LDNS_FREE(node->array); 146717d15b25SDag-Erling Smørgrav LDNS_FREE(node); 146817d15b25SDag-Erling Smørgrav return; 146917d15b25SDag-Erling Smørgrav } 147017d15b25SDag-Erling Smørgrav 147117d15b25SDag-Erling Smørgrav 147217d15b25SDag-Erling Smørgrav /** 147317d15b25SDag-Erling Smørgrav * Free select edge array. 147417d15b25SDag-Erling Smørgrav * @param node: node. 147517d15b25SDag-Erling Smørgrav * 147617d15b25SDag-Erling Smørgrav */ 147717d15b25SDag-Erling Smørgrav static void 147817d15b25SDag-Erling Smørgrav ldns_radix_node_array_free(ldns_radix_node_t* node) 147917d15b25SDag-Erling Smørgrav { 148017d15b25SDag-Erling Smørgrav node->offset = 0; 148117d15b25SDag-Erling Smørgrav node->len = 0; 148217d15b25SDag-Erling Smørgrav LDNS_FREE(node->array); 148317d15b25SDag-Erling Smørgrav node->array = NULL; 148417d15b25SDag-Erling Smørgrav node->capacity = 0; 148517d15b25SDag-Erling Smørgrav return; 148617d15b25SDag-Erling Smørgrav } 148717d15b25SDag-Erling Smørgrav 148817d15b25SDag-Erling Smørgrav 148917d15b25SDag-Erling Smørgrav /** 149017d15b25SDag-Erling Smørgrav * Free front of select edge array. 149117d15b25SDag-Erling Smørgrav * @param node: node. 149217d15b25SDag-Erling Smørgrav * 149317d15b25SDag-Erling Smørgrav */ 149417d15b25SDag-Erling Smørgrav static void 149517d15b25SDag-Erling Smørgrav ldns_radix_node_array_free_front(ldns_radix_node_t* node) 149617d15b25SDag-Erling Smørgrav { 149717d15b25SDag-Erling Smørgrav uint16_t i, n = 0; 149817d15b25SDag-Erling Smørgrav /** Remove until a non NULL entry. */ 149917d15b25SDag-Erling Smørgrav while (n < node->len && node->array[n].edge == NULL) { 150017d15b25SDag-Erling Smørgrav n++; 150117d15b25SDag-Erling Smørgrav } 150217d15b25SDag-Erling Smørgrav if (n == 0) { 150317d15b25SDag-Erling Smørgrav return; 150417d15b25SDag-Erling Smørgrav } 150517d15b25SDag-Erling Smørgrav if (n == node->len) { 150617d15b25SDag-Erling Smørgrav ldns_radix_node_array_free(node); 150717d15b25SDag-Erling Smørgrav return; 150817d15b25SDag-Erling Smørgrav } 150917d15b25SDag-Erling Smørgrav assert(n < node->len); 151017d15b25SDag-Erling Smørgrav assert((int) n <= (255 - (int) node->offset)); 151117d15b25SDag-Erling Smørgrav memmove(&node->array[0], &node->array[n], 151217d15b25SDag-Erling Smørgrav (node->len - n)*sizeof(ldns_radix_array_t)); 151317d15b25SDag-Erling Smørgrav node->offset += n; 151417d15b25SDag-Erling Smørgrav node->len -= n; 151517d15b25SDag-Erling Smørgrav for (i=0; i < node->len; i++) { 151617d15b25SDag-Erling Smørgrav if (node->array[i].edge) { 151717d15b25SDag-Erling Smørgrav node->array[i].edge->parent_index = i; 151817d15b25SDag-Erling Smørgrav } 151917d15b25SDag-Erling Smørgrav } 152017d15b25SDag-Erling Smørgrav ldns_radix_array_reduce(node); 152117d15b25SDag-Erling Smørgrav return; 152217d15b25SDag-Erling Smørgrav } 152317d15b25SDag-Erling Smørgrav 152417d15b25SDag-Erling Smørgrav 152517d15b25SDag-Erling Smørgrav /** 152617d15b25SDag-Erling Smørgrav * Free front of select edge array. 152717d15b25SDag-Erling Smørgrav * @param node: node. 152817d15b25SDag-Erling Smørgrav * 152917d15b25SDag-Erling Smørgrav */ 153017d15b25SDag-Erling Smørgrav static void 153117d15b25SDag-Erling Smørgrav ldns_radix_node_array_free_end(ldns_radix_node_t* node) 153217d15b25SDag-Erling Smørgrav { 153317d15b25SDag-Erling Smørgrav uint16_t n = 0; 153417d15b25SDag-Erling Smørgrav /** Shorten array. */ 153517d15b25SDag-Erling Smørgrav while (n < node->len && node->array[node->len-1-n].edge == NULL) { 153617d15b25SDag-Erling Smørgrav n++; 153717d15b25SDag-Erling Smørgrav } 153817d15b25SDag-Erling Smørgrav if (n == 0) { 153917d15b25SDag-Erling Smørgrav return; 154017d15b25SDag-Erling Smørgrav } 154117d15b25SDag-Erling Smørgrav if (n == node->len) { 154217d15b25SDag-Erling Smørgrav ldns_radix_node_array_free(node); 154317d15b25SDag-Erling Smørgrav return; 154417d15b25SDag-Erling Smørgrav } 154517d15b25SDag-Erling Smørgrav assert(n < node->len); 154617d15b25SDag-Erling Smørgrav node->len -= n; 154717d15b25SDag-Erling Smørgrav ldns_radix_array_reduce(node); 154817d15b25SDag-Erling Smørgrav return; 154917d15b25SDag-Erling Smørgrav } 155017d15b25SDag-Erling Smørgrav 155117d15b25SDag-Erling Smørgrav 155217d15b25SDag-Erling Smørgrav /** 155317d15b25SDag-Erling Smørgrav * Reduce the capacity of the array if needed. 155417d15b25SDag-Erling Smørgrav * @param node: node. 155517d15b25SDag-Erling Smørgrav * 155617d15b25SDag-Erling Smørgrav */ 155717d15b25SDag-Erling Smørgrav static void 155817d15b25SDag-Erling Smørgrav ldns_radix_array_reduce(ldns_radix_node_t* node) 155917d15b25SDag-Erling Smørgrav { 156017d15b25SDag-Erling Smørgrav if (node->len <= node->capacity/2 && node->len != node->capacity) { 156117d15b25SDag-Erling Smørgrav ldns_radix_array_t* a = LDNS_XMALLOC(ldns_radix_array_t, 156217d15b25SDag-Erling Smørgrav node->len); 156317d15b25SDag-Erling Smørgrav if (!a) { 156417d15b25SDag-Erling Smørgrav return; 156517d15b25SDag-Erling Smørgrav } 156617d15b25SDag-Erling Smørgrav memcpy(a, node->array, sizeof(ldns_radix_array_t)*node->len); 156717d15b25SDag-Erling Smørgrav LDNS_FREE(node->array); 156817d15b25SDag-Erling Smørgrav node->array = a; 156917d15b25SDag-Erling Smørgrav node->capacity = node->len; 157017d15b25SDag-Erling Smørgrav } 157117d15b25SDag-Erling Smørgrav return; 157217d15b25SDag-Erling Smørgrav } 157317d15b25SDag-Erling Smørgrav 157417d15b25SDag-Erling Smørgrav 157517d15b25SDag-Erling Smørgrav /** 157617d15b25SDag-Erling Smørgrav * Return this element if it exists, the previous otherwise. 157717d15b25SDag-Erling Smørgrav * @param node: from this node. 157817d15b25SDag-Erling Smørgrav * @param result: result node. 157917d15b25SDag-Erling Smørgrav * 158017d15b25SDag-Erling Smørgrav */ 158117d15b25SDag-Erling Smørgrav static void 158217d15b25SDag-Erling Smørgrav ldns_radix_self_or_prev(ldns_radix_node_t* node, ldns_radix_node_t** result) 158317d15b25SDag-Erling Smørgrav { 158417d15b25SDag-Erling Smørgrav if (node->data) { 158517d15b25SDag-Erling Smørgrav *result = node; 158617d15b25SDag-Erling Smørgrav } else { 158717d15b25SDag-Erling Smørgrav *result = ldns_radix_prev(node); 158817d15b25SDag-Erling Smørgrav } 158917d15b25SDag-Erling Smørgrav return; 159017d15b25SDag-Erling Smørgrav } 1591