2018-09-11 13:11:35 +03:00
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
2024-05-31 17:21:24 +03:00
//
2018-09-11 13:11:35 +03:00
// This file is part of LVM2.
//
// This copyrighted material is made available to anyone wishing to use,
// modify, copy, or redistribute it subject to the terms and conditions
// of the GNU Lesser General Public License v.2.1.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# include "radix-tree.h"
# include "base/memory/container_of.h"
# include "base/memory/zalloc.h"
# include <assert.h>
# include <stdlib.h>
# include <stdio.h>
2024-06-02 01:23:14 +03:00
# include <ctype.h>
2018-09-11 13:11:35 +03:00
//----------------------------------------------------------------
// This implementation is based around nested binary trees. Very
// simple (and hopefully correct).
struct node {
struct node * left ;
struct node * right ;
uint8_t key ;
struct node * center ;
bool has_value ;
union radix_value value ;
} ;
struct radix_tree {
radix_value_dtr dtr ;
void * dtr_context ;
2024-06-02 01:23:14 +03:00
unsigned nr_entries ;
2018-09-11 13:11:35 +03:00
struct node * root ;
} ;
2024-05-31 17:21:24 +03:00
struct radix_tree * radix_tree_create ( radix_value_dtr dtr , void * dtr_context )
2018-09-11 13:11:35 +03:00
{
struct radix_tree * rt = zalloc ( sizeof ( * rt ) ) ;
if ( rt ) {
rt - > dtr = dtr ;
rt - > dtr_context = dtr_context ;
}
return rt ;
}
// Returns the number of entries in the tree
static unsigned _destroy_tree ( struct node * n , radix_value_dtr dtr , void * context )
{
unsigned r ;
if ( ! n )
return 0 ;
r = _destroy_tree ( n - > left , dtr , context ) ;
r + = _destroy_tree ( n - > right , dtr , context ) ;
r + = _destroy_tree ( n - > center , dtr , context ) ;
if ( n - > has_value ) {
if ( dtr )
dtr ( context , n - > value ) ;
r + + ;
}
free ( n ) ;
return r ;
}
void radix_tree_destroy ( struct radix_tree * rt )
{
_destroy_tree ( rt - > root , rt - > dtr , rt - > dtr_context ) ;
free ( rt ) ;
}
static unsigned _count ( struct node * n )
{
unsigned r ;
if ( ! n )
return 0 ;
r = _count ( n - > left ) ;
r + = _count ( n - > right ) ;
r + = _count ( n - > center ) ;
if ( n - > has_value )
r + + ;
return r ;
}
unsigned radix_tree_size ( struct radix_tree * rt )
{
return _count ( rt - > root ) ;
}
2024-05-31 22:46:19 +03:00
static struct node * * _lookup ( struct node * * pn , const uint8_t * kb , const uint8_t * ke )
2018-09-11 13:11:35 +03:00
{
struct node * n = * pn ;
if ( ! n | | ( kb = = ke ) )
return pn ;
if ( * kb < n - > key )
return _lookup ( & n - > left , kb , ke ) ;
else if ( * kb > n - > key )
return _lookup ( & n - > right , kb , ke ) ;
else
return _lookup ( & n - > center , kb + 1 , ke ) ;
}
2024-05-31 22:46:19 +03:00
static bool _insert ( struct node * * pn , const uint8_t * kb , const uint8_t * ke , union radix_value v )
2018-09-11 13:11:35 +03:00
{
struct node * n = * pn ;
if ( ! n ) {
n = zalloc ( sizeof ( * n ) ) ;
if ( ! n )
return false ;
n - > key = * kb ;
* pn = n ;
}
if ( kb = = ke ) {
n - > has_value = true ;
n - > value = v ;
return true ;
}
if ( * kb < n - > key )
return _insert ( & n - > left , kb , ke , v ) ;
else if ( * kb > n - > key )
return _insert ( & n - > right , kb , ke , v ) ;
else
return _insert ( & n - > center , kb + 1 , ke , v ) ;
}
2024-05-31 22:46:19 +03:00
bool radix_tree_insert ( struct radix_tree * rt , const void * key , size_t keylen ,
2024-05-31 17:21:24 +03:00
union radix_value v )
2018-09-11 13:11:35 +03:00
{
2024-05-31 22:46:19 +03:00
const uint8_t * kb = key ;
const uint8_t * ke = kb + keylen ;
2024-06-02 01:23:14 +03:00
if ( ! _insert ( & rt - > root , kb , ke , v ) )
return false ;
rt - > nr_entries + + ;
return true ;
2018-09-11 13:11:35 +03:00
}
2024-05-31 22:46:19 +03:00
bool radix_tree_remove ( struct radix_tree * rt , const void * key , size_t keylen )
2018-09-11 13:11:35 +03:00
{
2024-05-31 22:46:19 +03:00
const uint8_t * kb = key ;
const uint8_t * ke = kb + keylen ;
2018-09-11 13:11:35 +03:00
struct node * * pn = _lookup ( & rt - > root , kb , ke ) ;
struct node * n = * pn ;
if ( ! n | | ! n - > has_value )
return false ;
2024-06-02 01:23:14 +03:00
rt - > nr_entries - - ;
2024-05-31 17:21:24 +03:00
if ( rt - > dtr )
rt - > dtr ( rt - > dtr_context , n - > value ) ;
2018-09-11 13:11:35 +03:00
2024-05-31 17:21:24 +03:00
if ( n - > left | | n - > center | | n - > right ) {
n - > has_value = false ;
return true ;
2018-09-11 13:11:35 +03:00
}
2024-05-31 17:21:24 +03:00
// FIXME: delete parent if this was the last entry
free ( n ) ;
* pn = NULL ;
return true ;
2018-09-11 13:11:35 +03:00
}
2024-05-31 22:46:19 +03:00
unsigned radix_tree_remove_prefix ( struct radix_tree * rt , const void * key , size_t keylen )
2018-09-11 13:11:35 +03:00
{
2024-05-31 22:46:19 +03:00
const uint8_t * kb = key ;
const uint8_t * ke = kb + keylen ;
2018-09-11 13:11:35 +03:00
struct node * * pn ;
unsigned count ;
pn = _lookup ( & rt - > root , kb , ke ) ;
if ( * pn ) {
count = _destroy_tree ( * pn , rt - > dtr , rt - > dtr_context ) ;
* pn = NULL ;
}
return count ;
}
2024-05-31 22:46:19 +03:00
bool radix_tree_lookup ( struct radix_tree * rt , const void * key , size_t keylen ,
2024-05-31 17:21:24 +03:00
union radix_value * result )
2018-09-11 13:11:35 +03:00
{
2024-05-31 22:46:19 +03:00
const uint8_t * kb = key ;
const uint8_t * ke = kb + keylen ;
2018-09-11 13:11:35 +03:00
struct node * * pn = _lookup ( & rt - > root , kb , ke ) ;
struct node * n = * pn ;
if ( n & & n - > has_value ) {
* result = n - > value ;
return true ;
2024-05-31 17:21:24 +03:00
}
return false ;
2018-09-11 13:11:35 +03:00
}
static void _iterate ( struct node * n , struct radix_tree_iterator * it )
{
if ( ! n )
return ;
_iterate ( n - > left , it ) ;
if ( n - > has_value )
// FIXME: fill out the key
2024-05-31 22:46:19 +03:00
it - > visit ( it , NULL , 0 , n - > value ) ;
2018-09-11 13:11:35 +03:00
_iterate ( n - > center , it ) ;
_iterate ( n - > right , it ) ;
}
2024-05-31 22:46:19 +03:00
void radix_tree_iterate ( struct radix_tree * rt , const void * key , size_t keylen ,
2018-09-11 13:11:35 +03:00
struct radix_tree_iterator * it )
{
2024-05-31 22:46:19 +03:00
const uint8_t * kb = key ;
const uint8_t * ke = kb + keylen ;
2018-09-11 13:11:35 +03:00
if ( kb = = ke )
_iterate ( rt - > root , it ) ;
else {
struct node * * pn = _lookup ( & rt - > root , kb , ke ) ;
struct node * n = * pn ;
if ( n ) {
if ( n - > has_value )
2024-05-31 22:46:19 +03:00
it - > visit ( it , NULL , 0 , n - > value ) ;
2018-09-11 13:11:35 +03:00
_iterate ( n - > center , it ) ;
}
}
}
bool radix_tree_is_well_formed ( struct radix_tree * rt )
{
return true ;
}
2024-06-02 01:23:14 +03:00
static void _dump ( FILE * out , struct node * n , unsigned indent )
{
unsigned i ;
if ( ! n )
return ;
_dump ( out , n - > left , indent + 1 ) ;
for ( i = 0 ; i < 2 * indent ; i + + )
fprintf ( out , " " ) ;
if ( n - > has_value ) {
fprintf ( out , " value: %llu \n " , n - > value . n ) ;
} else {
fprintf ( out , " key: '%c' [0x%02x] %u \n " ,
isprint ( n - > key ) ? n - > key : ' ' , n - > key , indent ) ;
}
_dump ( out , n - > center , indent + 1 ) ;
_dump ( out , n - > right , indent + 1 ) ;
}
2018-09-11 13:11:35 +03:00
void radix_tree_dump ( struct radix_tree * rt , FILE * out )
{
2024-06-02 01:23:14 +03:00
_dump ( out , rt - > root , 0 ) ;
2018-09-11 13:11:35 +03:00
}
//----------------------------------------------------------------