5 kx
5 kx /**********************************************************************
5 kx
5 kx Copyright 2019 Andrey V.Kosteltsev
5 kx
9 kx Licensed under the Radix cross Linux License, Version 1.0 .
5 kx you may not use this file except in compliance with the License.
5 kx You may obtain a copy of the License at
5 kx
9 kx https://radix-linux.su/licenses/LICENSE-1.0-en_US.txt
5 kx
5 kx Unless required by applicable law or agreed to in writing, software
5 kx distributed under the License is distributed on an "AS IS" BASIS,
5 kx WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
5 kx implied.
5 kx
5 kx **********************************************************************/
5 kx
5 kx #include <config.h>
5 kx
5 kx #include <stdlib.h>
5 kx #include <stdio.h>
5 kx #include <string.h>
5 kx #include <stddef.h>
5 kx #include <linux/limits.h>
5 kx
5 kx #include <msglog.h>
5 kx
5 kx #include <btree.h>
5 kx
5 kx struct btree *__btree_alloc( void *data )
5 kx {
5 kx struct btree *node = NULL;
5 kx
5 kx node = (struct btree *)malloc( sizeof( struct btree ) );
5 kx if( !node ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx bzero( (void *)node, sizeof( struct btree ) );
5 kx node->left = node->right = node;
5 kx
5 kx if( data ) node->data = data;
5 kx
5 kx return node;
5 kx }
5 kx
5 kx struct btree *btree_insert_left( struct btree *tree, struct btree *node )
5 kx {
5 kx if( !tree ) return node;
5 kx if( !node ) return tree;
5 kx
5 kx node->left = tree->left;
5 kx node->ltag = tree->ltag;
5 kx tree->left = node;
5 kx tree->ltag = 1;
5 kx node->right = tree;
5 kx node->rtag = 0;
5 kx
5 kx node->parent = tree;
5 kx
5 kx if( node->ltag )
5 kx {
5 kx node->left->right = node;
5 kx }
5 kx
5 kx return node;
5 kx }
5 kx
5 kx struct btree *btree_insert_right( struct btree *tree, struct btree *node )
5 kx {
5 kx if( !tree ) return node;
5 kx if( !node ) return tree;
5 kx
5 kx node->right = tree->right;
5 kx node->rtag = tree->rtag;
5 kx tree->right = node;
5 kx tree->rtag = 1;
5 kx node->left = tree;
5 kx node->ltag = 0;
5 kx
5 kx node->parent = tree;
5 kx
5 kx if( node->rtag )
5 kx {
5 kx node->right->left = node;
5 kx }
5 kx
5 kx return node;
5 kx }
5 kx
5 kx
5 kx static struct btree *__next_preorder( struct btree *node )
5 kx {
5 kx struct btree *next = node;
5 kx
5 kx if( !next ) return next;
5 kx
5 kx if( next->ltag )
5 kx return next->left;
5 kx
5 kx if( next->rtag )
5 kx return next->right;
5 kx
5 kx while( !next->rtag && next != next->right )
5 kx next = next->right;
5 kx
5 kx if( next->ltag && next->rtag )
5 kx next = next->right;
5 kx
5 kx return next;
5 kx }
5 kx
5 kx void btree_preorder_traversal( struct btree *root, TREE_FUNC func, void *user_data )
5 kx {
5 kx struct btree *next = root;
5 kx
5 kx if( !next ) return;
5 kx
5 kx do
5 kx {
5 kx if( func ) { func( next->data, user_data ); }
5 kx
5 kx next = __next_preorder( next );
5 kx
5 kx if( next == root || next == root->right ) break;
5 kx
5 kx } while( next );
5 kx
5 kx if( next == root ) return;
5 kx
5 kx do
5 kx {
5 kx if( func ) { func( next->data, user_data ); }
5 kx
5 kx next = __next_preorder( next );
5 kx
5 kx if( next == root || next == root->right ) break;
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx
5 kx static struct btree *__next_postorder( struct btree *node )
5 kx {
5 kx struct btree *next = NULL;
5 kx
5 kx if( !node ) return next;
5 kx
5 kx next = node->right;
5 kx
5 kx if( !node->rtag )
5 kx return next;
5 kx
5 kx while( next->ltag )
5 kx next = next->left;
5 kx
5 kx return next;
5 kx }
5 kx
5 kx void btree_postorder_traversal( struct btree *root, TREE_FUNC func, void *user_data )
5 kx {
5 kx struct btree *next = root;
5 kx
5 kx if( !next ) return;
5 kx
5 kx while( next->ltag )
5 kx next = next->left;
5 kx
5 kx for( ; next ; next = __next_postorder( next ) )
5 kx {
5 kx if( func ) { func( next->data, user_data ); }
5 kx
5 kx if( next == root ) break;
5 kx }
5 kx
5 kx next = __next_postorder( next );
5 kx
5 kx for( ; next ; next = __next_postorder( next ) )
5 kx {
5 kx if( next == root ) break;
5 kx
5 kx if( func ) { func( next->data, user_data ); }
5 kx }
5 kx
5 kx }
5 kx
5 kx
5 kx static struct btree *__start_endorder( struct btree *node )
5 kx {
5 kx struct btree *next = node;
5 kx
5 kx if( !next ) return next;
5 kx
5 kx do
5 kx {
5 kx while( next->ltag )
5 kx next = next->left;
5 kx
5 kx if( !next->rtag )
5 kx return next;
5 kx else
5 kx next = next->right;
5 kx
5 kx while( next->ltag )
5 kx next = next->left;
5 kx
5 kx } while( next->rtag );
5 kx
5 kx return next;
5 kx }
5 kx
5 kx static struct btree *__next_endorder( struct btree *node )
5 kx {
5 kx struct btree *next = node;
5 kx
5 kx if( !next ) return next;
5 kx
5 kx if( next->parent->rtag && (next != next->parent->right) )
5 kx next = __start_endorder( next->parent->right );
5 kx else
5 kx next = next->parent;
5 kx
5 kx return next;
5 kx }
5 kx
5 kx void btree_endorder_traversal( struct btree *root, TREE_FUNC func, void *user_data )
5 kx {
5 kx struct btree *next = root;
5 kx
5 kx if( !next ) return;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx if( func ) { func( next->data, user_data ); }
5 kx
5 kx if( next == root ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx
5 kx #if ! defined( max )
5 kx #define max(a,b) \
5 kx ({ typeof (a) _a = (a); \
5 kx typeof (b) _b = (b); \
5 kx _a > _b ? _a : _b; })
5 kx #endif
5 kx
5 kx /************************************
5 kx Tree height and width calculation:
5 kx ─────────────────────────────────
5 kx
5 kx height:
5 kx ┬
5 kx A │ 1
5 kx | \ ├
5 kx B D │ 2
5 kx | | ├
5 kx C E │ 3
5 kx | | \ ├
5 kx K H F │ 4
5 kx | \ ├
5 kx J G │ 5
5 kx ├──┬──┬──┬──┼
5 kx width: 1 2 3 4
5 kx
5 kx ************************************/
5 kx
5 kx int btree_height( struct btree *root )
5 kx {
5 kx struct btree *next = root;
5 kx int height = 0;
5 kx
5 kx if( !next ) return height;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx struct btree *p = next;
5 kx int h = 0;
5 kx
5 kx while( p->parent ) { ++h; p = p->parent; }
5 kx height = max( height, h );
5 kx
5 kx if( next == root ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx
5 kx return height + 1;
5 kx }
5 kx
5 kx int btree_width( struct btree *root )
5 kx {
5 kx int ret = 0, lw = 0, rw = 0;
5 kx struct btree *next = NULL, *left = NULL, *right = NULL;
5 kx
5 kx if( !root ) return ret;
5 kx
5 kx left = next = ( root->ltag ) ? root->left : NULL;
5 kx
5 kx if( next )
5 kx {
5 kx ++lw;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx if( next->ltag && next->rtag )
5 kx ++lw;
5 kx
5 kx if( next == left ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx right = next = ( root->rtag ) ? root->right : NULL;
5 kx
5 kx if( next )
5 kx {
5 kx ++rw;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx if( next->ltag && next->rtag )
5 kx ++rw;
5 kx
5 kx if( next == right ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx ret = lw + rw;
5 kx
5 kx return (ret) ? ret : 1;
5 kx }
5 kx
5 kx int btree_left_width( struct btree *root )
5 kx {
5 kx int lw = 0;
5 kx struct btree *next = NULL, *left = NULL;
5 kx
5 kx if( !root ) return lw;
5 kx
5 kx left = next = ( root->ltag ) ? root->left : NULL;
5 kx
5 kx if( next )
5 kx {
5 kx ++lw;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx if( next->ltag && next->rtag )
5 kx ++lw;
5 kx
5 kx if( next == left ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx return (lw) ? lw : 1;
5 kx }
5 kx
5 kx int btree_right_width( struct btree *root )
5 kx {
5 kx int rw = 0;
5 kx struct btree *next = NULL, *right = NULL;
5 kx
5 kx if( !root ) return rw;
5 kx
5 kx right = next = ( root->rtag ) ? root->right : NULL;
5 kx
5 kx if( next )
5 kx {
5 kx ++rw;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx if( next->ltag && next->rtag )
5 kx ++rw;
5 kx
5 kx if( next == right ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx return (rw) ? rw : 1;
5 kx }
5 kx
5 kx
5 kx struct btree *btree_detach( struct btree *node )
5 kx {
5 kx struct btree *parent = node->parent;
5 kx
5 kx if( !node ) return node;
5 kx
5 kx if( parent->right == node )
5 kx {
5 kx struct btree *rlink = node;
5 kx
5 kx while( rlink->rtag )
5 kx rlink = rlink->right;
5 kx rlink = rlink->right;
5 kx
5 kx parent->right = rlink;
5 kx parent->rtag = 0;
5 kx }
5 kx else
5 kx {
5 kx struct btree *llink = node;
5 kx
5 kx while( llink->ltag )
5 kx llink = llink->left;
5 kx llink = llink->left;
5 kx
5 kx parent->left = llink;
5 kx parent->ltag = 0;
5 kx }
5 kx
5 kx return node;
5 kx }
5 kx
5 kx
5 kx void __btree_free( struct btree *root )
5 kx {
5 kx struct btree *next = root;
5 kx
5 kx if( !next ) return;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx struct btree *tmp = next;
5 kx
5 kx if( next == root )
5 kx {
5 kx free( tmp );
5 kx break;
5 kx }
5 kx next = __next_endorder( next );
5 kx free( tmp );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx void btree_free( struct btree *root, TREE_FUNC free_func )
5 kx {
5 kx btree_endorder_traversal( root, free_func, NULL );
5 kx __btree_free( root );
5 kx }
5 kx
5 kx
5 kx /*******************************************************************
5 kx Stack functions:
5 kx */
5 kx struct btree_stack *btree_stack_alloc( const size_t n, const size_t u )
5 kx {
5 kx struct btree_stack *stack = NULL;
5 kx
5 kx if( !n || !u ) return stack;
5 kx
5 kx stack = (struct btree_stack *)malloc( sizeof( struct btree_stack ) );
5 kx if( !stack ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)stack, sizeof( struct btree_stack ) );
5 kx
5 kx stack->__mem_size = n * u;
5 kx stack->__unit_size = u;
5 kx
5 kx stack->__mem = malloc( stack->__mem_size );
5 kx if( !stack->__mem ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx bzero( stack->__mem, stack->__mem_size );
5 kx stack->__cur_brk = stack->__mem;
5 kx
5 kx return stack;
5 kx }
5 kx
5 kx void btree_stack_free( struct btree_stack **pstack )
5 kx {
5 kx struct btree_stack *stack = NULL;
5 kx
5 kx if( !pstack ) return;
5 kx
5 kx stack = *pstack;
5 kx
5 kx if( !stack ) return;
5 kx if( stack->__mem ) free( stack->__mem );
5 kx
5 kx free( stack );
5 kx
5 kx *pstack = (struct btree_stack *)NULL;
5 kx }
5 kx
5 kx int btree_stack_is_empty( struct btree_stack *stack )
5 kx {
5 kx if( !stack ) return 1;
5 kx if( stack->__mem == stack->__cur_brk ) return 1;
5 kx return 0;
5 kx }
5 kx
5 kx int btree_stack_depth( struct btree_stack *stack )
5 kx {
5 kx if( !stack ) return -1;
5 kx if( btree_stack_is_empty( stack ) )
5 kx return 0;
5 kx
5 kx return (stack->__cur_brk - stack->__mem) / stack->__unit_size;
5 kx }
5 kx
5 kx static int __stack_brk( struct btree_stack *stack, void *end_d )
5 kx {
5 kx void *ptr = NULL;
5 kx
5 kx if( !stack ) return -1;
5 kx
5 kx ptr = stack->__mem;
5 kx if( !ptr ) return -1;
5 kx
5 kx if( end_d < ptr )
5 kx {
5 kx return -1;
5 kx }
5 kx if( end_d > ptr + stack->__mem_size )
5 kx {
5 kx size_t size = stack->__mem_size + stack->__mem_size;
5 kx
5 kx if( (end_d - (ptr + stack->__mem_size)) < stack->__mem_size )
5 kx {
5 kx ptrdiff_t offset = stack->__cur_brk - stack->__mem;
5 kx stack->__mem = realloc( stack->__mem, size );
5 kx if( !stack->__mem ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx stack->__mem_size = size;
5 kx stack->__cur_brk = stack->__mem + offset;
5 kx ptr = stack->__mem;
5 kx return 0;
5 kx }
5 kx else
5 kx return -1;
5 kx }
5 kx
5 kx /*
5 kx __cur_brk = end_d;
5 kx
5 kx The function __stack_brk() only checks boundaries of
5 kx memory. The value of __cur_brk is set by __stack_sbrk()
5 kx function.
5 kx *********************************************************/
5 kx
5 kx return 0;
5 kx
5 kx } /* End of __stack_brk() */
5 kx
5 kx static void *__stack_sbrk( struct btree_stack *stack, int incr )
5 kx {
5 kx void *ptr = NULL;
5 kx int rc;
5 kx
5 kx if( !stack ) return ptr;
5 kx
5 kx ptr = stack->__cur_brk;
5 kx
5 kx if( incr == 0 ) return( ptr );
5 kx
5 kx rc = __stack_brk( stack, ptr + incr );
5 kx if( rc == -1 )
5 kx {
5 kx /* errno is set into __mpu_brk() */
5 kx return NULL;
5 kx }
5 kx
5 kx ptr = stack->__cur_brk;
5 kx stack->__cur_brk = ptr + (int)incr;
5 kx
5 kx return ptr;
5 kx
5 kx } /* End of __stack_sbrk() */
5 kx
5 kx
5 kx int btree_stack_push( struct btree_stack *stack, const void *unit )
5 kx {
5 kx void *uptr, *ptr = NULL;
5 kx
5 kx if( !stack ) return -1;
5 kx
5 kx ptr = __stack_sbrk( stack, stack->__unit_size );
5 kx
5 kx if( ptr )
5 kx {
5 kx uptr = memcpy( ptr, unit, stack->__unit_size );
5 kx if( !uptr )
5 kx {
5 kx return -1;
5 kx }
5 kx }
5 kx else
5 kx {
5 kx return -1;
5 kx }
5 kx
5 kx return 0;
5 kx }
5 kx
5 kx int btree_stack_pop( struct btree_stack *stack, void *unit )
5 kx {
5 kx void *uptr, *ptr = NULL;
5 kx
5 kx if( !stack ) return -1;
5 kx
5 kx ptr = __stack_sbrk( stack, -(int)stack->__unit_size );
5 kx
5 kx if( ptr )
5 kx {
5 kx ptr -= stack->__unit_size;
5 kx uptr = memcpy( unit, (const void *)ptr, stack->__unit_size );
5 kx if( !uptr )
5 kx {
5 kx bzero( unit, stack->__unit_size );
5 kx return -1;
5 kx }
5 kx }
5 kx else
5 kx {
5 kx bzero( unit, stack->__unit_size );
5 kx return -1;
5 kx }
5 kx
5 kx return 0;
5 kx }
5 kx /*
5 kx End of stack functions.
5 kx *******************************************************************/
5 kx
5 kx static void btree_print_line( const char *line, int indent, const struct _bctx *ctx )
5 kx {
5 kx char *p, buf[PATH_MAX*2];
5 kx int depth = 0, max_depth = PATH_MAX + PATH_MAX / 2;
5 kx
5 kx if( !line || !ctx ) return;
5 kx
5 kx if( !indent )
5 kx {
5 kx buf[0] = '\0';
5 kx p = (char *)&buf[0];
5 kx depth = 0;
5 kx }
5 kx else
5 kx {
5 kx buf[0] = ' ';
5 kx buf[1] = '\0';
5 kx p = (char *)&buf[1];
5 kx depth = ctx->indent;
5 kx }
5 kx
5 kx if( depth < 1 ) depth = 0;
5 kx if( depth > max_depth ) depth = max_depth;
5 kx
5 kx while( depth )
5 kx {
5 kx (void)sprintf( p, " " ); --depth; ++p; *p = '\0';
5 kx }
5 kx
5 kx (void)sprintf( p, "%s", line );
5 kx
5 kx fprintf( ctx->output, (char *)&buf[0] );
5 kx fflush( ctx->output );
5 kx }
5 kx
5 kx
5 kx static void __btree_clean_prn_flags( struct btree *root )
5 kx {
5 kx struct btree *next = root;
5 kx
5 kx if( !next ) return;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx next->lprn = 0;
5 kx next->rprn = 0;
5 kx
5 kx if( next == root ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx void btree_print_json( FILE *output, struct btree *root, TREE_FUNC func )
5 kx {
5 kx struct btree *next = root;
5 kx struct _bctx ctx;
5 kx
5 kx struct btree_stack *stack;
5 kx struct btree_stack *lstack;
5 kx
5 kx if( !output || !next || !func ) return;
5 kx
5 kx bzero( (void *)&ctx, sizeof(struct _bctx) );
5 kx
5 kx stack = btree_stack_alloc( (const size_t)btree_height(next), sizeof(struct _bctx) );
5 kx
5 kx ctx.output = output;
5 kx ctx.node = next;
5 kx ctx.indent = 0;
5 kx
5 kx __btree_clean_prn_flags( root );
5 kx
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx
5 kx do
5 kx {
5 kx
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx
5 kx func( next->data, (void *)&ctx );
5 kx
5 kx if( ctx.node->ltag || ctx.node->rtag )
5 kx {
5 kx btree_print_line( ",\n", 0, &ctx );
5 kx btree_print_line( "\"children\": [\n", 1, &ctx );
5 kx btree_print_line( " {\n", 1, &ctx );
5 kx ctx.indent += 2;
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx }
5 kx else
5 kx {
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx
5 kx if( !ctx.node->ltag && !ctx.node->rtag )
5 kx {
5 kx if( ctx.node->parent )
5 kx {
5 kx struct _bctx cctx;
5 kx
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx
5 kx memcpy( (void *)&cctx, (const void *)&ctx, sizeof(struct _bctx) );
5 kx
5 kx if( (ctx.node->lprn == ctx.node->ltag) && (ctx.node->rprn == ctx.node->rtag) )
5 kx {
5 kx if( ctx.node->parent->ltag && ctx.node->parent->left == ctx.node )
5 kx ctx.node->parent->lprn = 1;
5 kx if( ctx.node->parent->rtag && ctx.node->parent->right == ctx.node )
5 kx ctx.node->parent->rprn = 1;
5 kx }
5 kx
5 kx if( btree_stack_depth( stack ) > 0 )
5 kx {
5 kx struct btree_stack *pstack = btree_stack_alloc( (const size_t)btree_height(root), sizeof(struct _bctx) );
5 kx struct _bctx pctx;
5 kx
5 kx do
5 kx {
5 kx btree_stack_pop( stack, (void *)&pctx );
5 kx
5 kx if( (cctx.node->lprn == cctx.node->ltag) && (cctx.node->rprn == cctx.node->rtag) )
5 kx {
5 kx if( cctx.node->parent && cctx.node->parent->ltag && cctx.node->parent->left == cctx.node )
5 kx {
5 kx cctx.node->parent->lprn = 1;
5 kx
5 kx if( cctx.node->parent->rtag )
5 kx {
5 kx if( !cctx.node->ltag && !cctx.node->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx --ctx.indent;
5 kx btree_print_line( "},\n", 1, &ctx );
5 kx btree_print_line( "{\n", 1, &ctx );
5 kx }
5 kx else
5 kx {
5 kx if( !cctx.node->ltag && !cctx.node->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx --ctx.indent;
5 kx btree_print_line( "}\n", 1, &ctx );
5 kx --ctx.indent;
5 kx btree_print_line( "]\n", 1, &ctx );
5 kx }
5 kx }
5 kx if( cctx.node->parent && cctx.node->parent->rtag && cctx.node->parent->right == cctx.node )
5 kx {
5 kx cctx.node->parent->rprn = 1;
5 kx
5 kx if( !cctx.node->ltag && !cctx.node->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx --ctx.indent;
5 kx btree_print_line( "}\n", 1, &ctx );
5 kx --ctx.indent;
5 kx btree_print_line( "]\n", 1, &ctx );
5 kx }
5 kx
5 kx }
5 kx
5 kx memcpy( (void *)&cctx, (const void *)&pctx, sizeof(struct _bctx) );
5 kx
5 kx if( (pctx.node->ltag && (pctx.node->lprn < pctx.node->ltag)) || (pctx.node->rtag && (pctx.node->rprn < pctx.node->rtag)) )
5 kx {
5 kx btree_stack_push( pstack, (const void *)&pctx );
5 kx }
5 kx
5 kx } while( !btree_stack_is_empty( stack ) );
5 kx
5 kx while( btree_stack_pop( pstack, (void *)&pctx ) == 0 )
5 kx {
5 kx btree_stack_push( stack, (const void *)&pctx );
5 kx }
5 kx
5 kx btree_stack_free( &pstack );
5 kx }
5 kx else
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx
5 kx } /* End if( parent ) */
5 kx else
5 kx {
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx }
5 kx
5 kx } /* End if( no children ) */
5 kx
5 kx } /* End if( any child ) */
5 kx
5 kx
5 kx next = __next_preorder( next );
5 kx
5 kx
5 kx if( next != root )
5 kx {
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx
5 kx ctx.output = output;
5 kx ctx.node = next;
5 kx
5 kx if( btree_stack_push( stack, (const void *)&ctx ) == -1 ) FATAL_ERROR( "btree stack is destroyed" );
5 kx }
5 kx
5 kx if( next == root || next == root->right ) break;
5 kx
5 kx } while( next );
5 kx
5 kx
5 kx if( next == root )
5 kx {
5 kx struct _bctx ctx;
5 kx
5 kx ctx.output = output;
5 kx ctx.node = root;
5 kx ctx.indent = 2;
5 kx
5 kx /* If we in root node then there is no right subtree */
5 kx if( !root->ltag && !root->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx
5 kx if( root->ltag && (root->lprn < root->ltag) )
5 kx {
5 kx root->lprn = 1;
5 kx
5 kx --ctx.indent;
5 kx btree_print_line( "}\n", 1, &ctx );
5 kx --ctx.indent;
5 kx btree_print_line( "]\n", 1, &ctx );
5 kx }
5 kx }
5 kx
5 kx if( next == root )
5 kx {
5 kx btree_stack_free( &stack );
5 kx return;
5 kx }
5 kx
5 kx do
5 kx {
5 kx
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx
5 kx func( next->data, (void *)&ctx );
5 kx
5 kx if( ctx.node->ltag || ctx.node->rtag )
5 kx {
5 kx btree_print_line( ",\n", 0, &ctx );
5 kx btree_print_line( "\"children\": [\n", 1, &ctx );
5 kx btree_print_line( " {\n", 1, &ctx );
5 kx ctx.indent += 2;
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx }
5 kx else
5 kx {
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx
5 kx if( !ctx.node->ltag && !ctx.node->rtag )
5 kx {
5 kx if( ctx.node->parent )
5 kx {
5 kx struct _bctx cctx;
5 kx
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx
5 kx memcpy( (void *)&cctx, (const void *)&ctx, sizeof(struct _bctx) );
5 kx
5 kx if( (ctx.node->lprn == ctx.node->ltag) && (ctx.node->rprn == ctx.node->rtag) )
5 kx {
5 kx if( ctx.node->parent->ltag && ctx.node->parent->left == ctx.node )
5 kx ctx.node->parent->lprn = 1;
5 kx if( ctx.node->parent->rtag && ctx.node->parent->right == ctx.node )
5 kx ctx.node->parent->rprn = 1;
5 kx }
5 kx
5 kx if( btree_stack_depth( stack ) > 0 )
5 kx {
5 kx struct btree_stack *pstack = btree_stack_alloc( (const size_t)btree_height(root), sizeof(struct _bctx) );
5 kx struct _bctx pctx;
5 kx
5 kx do
5 kx {
5 kx btree_stack_pop( stack, (void *)&pctx );
5 kx
5 kx if( (cctx.node->lprn == cctx.node->ltag) && (cctx.node->rprn == cctx.node->rtag) )
5 kx {
5 kx if( cctx.node->parent && cctx.node->parent->ltag && cctx.node->parent->left == cctx.node )
5 kx {
5 kx cctx.node->parent->lprn = 1;
5 kx
5 kx if( cctx.node->parent->rtag )
5 kx {
5 kx if( !cctx.node->ltag && !cctx.node->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx --ctx.indent;
5 kx btree_print_line( "},\n", 1, &ctx );
5 kx btree_print_line( "{\n", 1, &ctx );
5 kx }
5 kx else
5 kx {
5 kx if( !cctx.node->ltag && !cctx.node->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx --ctx.indent;
5 kx btree_print_line( "}\n", 1, &ctx );
5 kx --ctx.indent;
5 kx btree_print_line( "]\n", 1, &ctx );
5 kx }
5 kx }
5 kx if( cctx.node->parent && cctx.node->parent->rtag && cctx.node->parent->right == cctx.node )
5 kx {
5 kx cctx.node->parent->rprn = 1;
5 kx
5 kx if( !cctx.node->ltag && !cctx.node->rtag )
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx --ctx.indent;
5 kx btree_print_line( "}\n", 1, &ctx );
5 kx --ctx.indent;
5 kx btree_print_line( "]\n", 1, &ctx );
5 kx }
5 kx
5 kx }
5 kx
5 kx memcpy( (void *)&cctx, (const void *)&pctx, sizeof(struct _bctx) );
5 kx
5 kx if( (pctx.node->ltag && (pctx.node->lprn < pctx.node->ltag)) || (pctx.node->rtag && (pctx.node->rprn < pctx.node->rtag)) )
5 kx {
5 kx btree_stack_push( pstack, (const void *)&pctx );
5 kx }
5 kx
5 kx } while( !btree_stack_is_empty( stack ) );
5 kx
5 kx while( btree_stack_pop( pstack, (void *)&pctx ) == 0 )
5 kx {
5 kx btree_stack_push( stack, (const void *)&pctx );
5 kx }
5 kx
5 kx btree_stack_free( &pstack );
5 kx }
5 kx else
5 kx {
5 kx btree_print_line( "\n", 0, &ctx );
5 kx }
5 kx
5 kx } /* End if( parent ) */
5 kx else
5 kx {
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx }
5 kx
5 kx } /* End if( no children ) */
5 kx
5 kx } /* End if( any child ) */
5 kx
5 kx
5 kx next = __next_preorder( next );
5 kx
5 kx
5 kx if( next != root )
5 kx {
5 kx btree_stack_pop( stack, (void *)&ctx );
5 kx btree_stack_push( stack, (const void *)&ctx );
5 kx
5 kx ctx.output = output;
5 kx ctx.node = next;
5 kx
5 kx if( btree_stack_push( stack, (const void *)&ctx ) == -1 ) FATAL_ERROR( "btree stack is destroyed" );
5 kx }
5 kx
5 kx if( next == root || next == root->right ) break;
5 kx
5 kx } while( next );
5 kx
5 kx btree_stack_free( &stack );
5 kx }
5 kx
5 kx
5 kx int btree_compare( struct btree *root_a, struct btree *root_b, TREE_CMPF cmp_func )
5 kx {
5 kx struct btree *next_a = root_a, *next_b = root_b;
5 kx
5 kx if( !next_a || !next_b || !cmp_func ) return 1;
5 kx
5 kx next_a = __start_endorder( next_a );
5 kx next_b = __start_endorder( next_b );
5 kx
5 kx do
5 kx {
5 kx if( cmp_func( next_a->data, next_b->data ) )
5 kx {
5 kx return 1;
5 kx }
5 kx
5 kx if( next_a == root_a || next_b == root_b )
5 kx {
5 kx if( (next_a == root_a) && (next_b == root_b) )
5 kx break;
5 kx else
5 kx return 1;
5 kx }
5 kx
5 kx next_a = __next_endorder( next_a );
5 kx next_b = __next_endorder( next_b );
5 kx
5 kx } while( next_a && next_b );
5 kx
5 kx return 0;
5 kx }
5 kx
5 kx
5 kx static void __remove_duplicates( struct btree *root, struct btree *node, TREE_CMPF cmp_func, TREE_FUNC free_func )
5 kx {
5 kx struct btree *next = NULL, *rem = NULL;
5 kx
5 kx if( !root || !node || !cmp_func || node == root ) return;
5 kx
5 kx
5 kx next = __next_endorder( node );
5 kx
5 kx if( next == root ) return;
5 kx
5 kx do
5 kx {
5 kx if( !cmp_func( node->data, next->data ) )
5 kx rem = next;
5 kx else
5 kx rem = NULL;
5 kx
5 kx if( next == root ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx if( rem && !rem->ltag && !rem->rtag )
5 kx {
5 kx struct btree *node = btree_detach( rem );
5 kx
5 kx if( free_func )
5 kx {
5 kx btree_free( node, free_func );
5 kx }
5 kx else
5 kx {
5 kx __btree_free( node );
5 kx }
5 kx }
5 kx
5 kx } while( next );
5 kx }
5 kx
5 kx void btree_reduce( struct btree *root, TREE_CMPF cmp_func, TREE_FUNC free_func )
5 kx {
5 kx struct btree *next = root;
5 kx
5 kx if( !next || ! cmp_func ) return;
5 kx
5 kx next = __start_endorder( next );
5 kx
5 kx do
5 kx {
5 kx __remove_duplicates( root, next, cmp_func, free_func );
5 kx
5 kx if( next == root ) break;
5 kx
5 kx next = __next_endorder( next );
5 kx
5 kx } while( next );
5 kx }