Add WIP / untested generic tree datastructure
This commit is contained in:
1 parent
b5a3e010d8
commit
5516b50b3a
2 files changed
+842
-1
No files matched your search
@@ -37,7 +37,7 @@ PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.6.1
|
||||
|
||||
# Define the contain of the distribution tarball
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-tuple.h m-variant.h m-worker.h
|
||||
DOC1=LICENSE README.md
|
||||
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c
|
||||
|
||||
@@ -0,0 +1,841 @@
|
||||
/*
|
||||
* M*LIB - TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MSTARLIB_TREE_H
|
||||
#define MSTARLIB_TREE_H
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a complete tree of 'type'
|
||||
https://en.wikipedia.org/wiki/Tree_(data_structure)
|
||||
USAGE:
|
||||
TREE_DEF(name, type_t[, type_oplist])
|
||||
*/
|
||||
#define M_TREE_DEF(name, ...) \
|
||||
M_TREE_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
|
||||
|
||||
/* Define a complete tree of 'type'
|
||||
as the given name name_t with its associated functions.
|
||||
USAGE:
|
||||
TREE_DEF_AS(name, name_t, it_t, type_t[, type_oplist])
|
||||
*/
|
||||
#define M_TREE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_TR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/* Maximum number of child per node.
|
||||
Used for assertion. */
|
||||
#ifndef M_USE_TREE_MAX_CHILD_PER_PARENT
|
||||
#define M_USE_TREE_MAX_CHILD_PER_PARENT 10000000
|
||||
#endif
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************** INTERNAL ************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
# define M_TR33_NODE_CONTRACT(node, tree) do { \
|
||||
M_ASSERT( (tree)->size > 0); \
|
||||
M_ASSERT( (node)->parent != M_TR33_NO_NODE); \
|
||||
M_ASSERT( (node) >= &(tree)->tab[0] && (node) < &(tree)->tab[(tree)->capacity] ); \
|
||||
M_ASSERT( (node)->parent == M_TR33_ROOT_NODE || (node)->parent >= 0); \
|
||||
M_ASSERT( (node)->parent != M_TR33_ROOT_NODE || (node) == &(tree)->tab[(tree)->root_index] ); \
|
||||
} while (0)
|
||||
|
||||
# define M_TR33_CONTRACT(tree) do { \
|
||||
M_ASSERT( (tree)->size >= 0 && (tree)->size <= (tree)->capacity); \
|
||||
M_ASSERT( (tree)->capacity >= 0 ); \
|
||||
M_ASSERT( (tree)->capacity == 0 || (tree)->tab != NULL); \
|
||||
M_ASSERT( (tree)->free_index >= M_TR33_NO_NODE && (tree)->free_index < (tree)->capacity); \
|
||||
M_ASSERT( (tree)->root_index >= M_TR33_NO_NODE && (tree)->root_index < (tree)->capacity); \
|
||||
M_ASSERT( (tree)->free_index < 0 || (tree)->tab[(tree)->free_index].parent == M_TR33_NO_NODE); \
|
||||
M_ASSERT( (tree)->root_index < 0 || (tree)->tab[(tree)->root_index].parent == M_TR33_ROOT_NODE); \
|
||||
M_ASSERT( (tree)->root_index != M_TR33_NO_NODE || (tree)->size == 0); \
|
||||
} while (0)
|
||||
|
||||
# define M_TR33_IT_CONTRACT(it, valid) do { \
|
||||
M_TR33_CONTRACT( (it).tree); \
|
||||
M_ASSERT(valid == false || (it).index >= 0); \
|
||||
if ((it).index >= 0) { \
|
||||
M_TR33_NODE_CONTRACT(&(it).tree->tab[(it).index], (it).tree); \
|
||||
/* All child of this node have the parent field correctly set */ \
|
||||
m_tr33_index_t itj = (it).tree->tab[(it).index].child; \
|
||||
/* They all have their sibling as the left node */ \
|
||||
m_tr33_index_t left = M_TR33_NO_NODE; \
|
||||
/* We don't have any infinite loop */ \
|
||||
unsigned cpt = 0; \
|
||||
while (itj >= 0) { \
|
||||
M_ASSERT( (it).tree->tab[itj].parent == (it).index ); \
|
||||
M_ASSERT( (it).tree->tab[itj].left == left ); \
|
||||
left = itj; \
|
||||
itj = (it).tree->tab[itj].right; \
|
||||
M_ASSERT( ++cpt < M_USE_TREE_MAX_CHILD_PER_PARENT); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Deferred evaluation */
|
||||
#define M_TR33_DEF_P1(arg) M_ID( M_TR33_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_TR33_DEF_P2(name, type, oplist, tree_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_TR33_DEF_P3, M_TR33_DEF_FAILURE)(name, type, oplist, tree_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define M_TR33_DEF_FAILURE(name, type, oplist, tree_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(TREE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* type of an index in the tree. Up to 2^31-1 nodes can be created.*/
|
||||
typedef int32_t m_tr33_index_t;
|
||||
|
||||
/* Special value for the parent field of a node:
|
||||
* M_TR33_ROOT_NODE is only for the root node.
|
||||
* M_TR33_NO_NODE is for nodes without parent, i.e. the pool of free nodes.
|
||||
*/
|
||||
#define M_TR33_ROOT_NODE (-2)
|
||||
#define M_TR33_NO_NODE (-1)
|
||||
|
||||
/* Internal definition:
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the tree
|
||||
- oplist: oplist of the type of the elements of the tree
|
||||
- tree_t: alias for the type of the tree
|
||||
- it_t: alias for the iterator of the tree
|
||||
|
||||
A free node is identified as parent as M_TR33_NO_NODE, in which case child is the next item in the list of free node.
|
||||
A root node is identified as parent as M_TR33_ROOT_NODE
|
||||
*/
|
||||
#define M_TR33_DEF_P3(name, type, oplist, tree_t, it_t) \
|
||||
\
|
||||
/* Define a node of the tree. \
|
||||
Each node of a tree is present in the array of the tree and as such \
|
||||
we don't store the reference of other nodes using pointers but using \
|
||||
integers. It is shorter and avoids allocating too much data. \
|
||||
As such, a node may move on inserting another one, and \
|
||||
an iterator is not a pointer on the node but an index in this array. \
|
||||
+ 'parent' is the parent node of the current node, \
|
||||
or M_TR33_ROOT_NODE if it is a root. \
|
||||
+ 'child' is the first child node of the current node (the left one) \
|
||||
or M_TR33_NO_NODE if there is none. \
|
||||
+ 'left' is the left sibling or M_TR33_NO_NODE if there is none \
|
||||
+ 'right' is the right sibling or M_TR33_NO_NODE if there is none \
|
||||
+ 'data' if the data field of the node containing the given type \
|
||||
*/ \
|
||||
typedef struct M_C(name, _node_s) { \
|
||||
m_tr33_index_t parent; \
|
||||
m_tr33_index_t child; \
|
||||
m_tr33_index_t left; \
|
||||
m_tr33_index_t right; \
|
||||
type data; \
|
||||
} M_C(name, _node_ct); \
|
||||
\
|
||||
/* Define a tree: \
|
||||
+ size is the number of nodes in the tree, \
|
||||
+ capacity is the allocated size of the array 'tab' \
|
||||
+ root_index is the index of the "first" root in the tree. \
|
||||
+ free_index is the list of free nodes in the array 'tab'. \
|
||||
+ tab is a pointer to the allocated nodes. \
|
||||
*/ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
m_tr33_index_t size; \
|
||||
m_tr33_index_t capacity; \
|
||||
m_tr33_index_t root_index; \
|
||||
m_tr33_index_t free_index; \
|
||||
M_C(name, _node_ct) *tab; \
|
||||
} tree_t[1]; \
|
||||
\
|
||||
/* Define an iterator that references a node. \
|
||||
A node is an internal type, whereas the iterator is not. \
|
||||
A node can be moved, whereas the iterator will always remain valid \
|
||||
until the node is destroyed. \
|
||||
It is composed of: \
|
||||
+ tree is a pointer to the tree structure \
|
||||
+ index is an index in the array tab, identifying the node. \
|
||||
NOTE: we don't define then using [1] as we want to pass then by value \
|
||||
so that we can return iterator on the inserted elements. \
|
||||
*/ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct M_C(name, _s) *tree; \
|
||||
m_tr33_index_t index; \
|
||||
} it_t; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(tree_t tree) { \
|
||||
tree->size = 0; \
|
||||
tree->capacity = 0; \
|
||||
tree->root_index = M_TR33_NO_NODE; \
|
||||
tree->free_index = M_TR33_NO_NODE; \
|
||||
tree->tab = NULL; \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(tree_t tree) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
if (tree->size > 0) { \
|
||||
/* We don't scan recursively the node tree, but sequentially */ \
|
||||
m_tr33_index_t free_index = tree->free_index; \
|
||||
for(m_tr33_index_t i = 0 ; i < tree->capacity ; i ++) { \
|
||||
/* If the node is not a free node */ \
|
||||
if (tree->tab[i].parent != M_TR33_NO_NODE) { \
|
||||
/* free it */ \
|
||||
M_CALL_CLEAR(oplist, tree->tab[i].data); \
|
||||
tree->tab[i].parent = M_TR33_NO_NODE; \
|
||||
tree->tab[i].child = free_index; \
|
||||
tree->tab[i].left = M_TR33_NO_NODE; \
|
||||
tree->tab[i].right = M_TR33_NO_NODE; \
|
||||
free_index = i; \
|
||||
} \
|
||||
} \
|
||||
/* Update the free index */ \
|
||||
tree->free_index = free_index; \
|
||||
tree->size = 0; \
|
||||
tree->root_index = M_TR33_NO_NODE; \
|
||||
} \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(tree_t tree) { \
|
||||
M_C(name, _reset)(tree); \
|
||||
M_CALL_FREE(oplist, tree->tab); \
|
||||
/* This is so reusing the object implies an assertion failure */ \
|
||||
tree->size = 1; \
|
||||
tree->tab = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const tree_t tree) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
return M_ASSIGN_CAST(size_t, tree->size); \
|
||||
} \
|
||||
\
|
||||
static inline m_tr33_index_t \
|
||||
M_C3(m_tr33_, name, _alloc_node)(tree_t tree) { \
|
||||
m_tr33_index_t ret = tree->free_index; \
|
||||
if (M_UNLIKELY(ret < 0)) { \
|
||||
/* No more enough space: realloc the array */ \
|
||||
const size_t alloc = M_CALL_INC_ALLOC(oplist, tree->size); \
|
||||
if (M_UNLIKELY (alloc >= INT32_MAX)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _node_s)) * alloc); \
|
||||
return M_TR33_NO_NODE; \
|
||||
} \
|
||||
struct M_C(name, _node_s) *ptr = \
|
||||
M_CALL_REALLOC(oplist, struct M_C(name, _node_s), tree->tab, alloc); \
|
||||
if (M_UNLIKELY (ptr == NULL) ) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _node_s)) * alloc); \
|
||||
return M_TR33_NO_NODE; \
|
||||
} \
|
||||
/* Construct the list of free node in the extra allocated pool */ \
|
||||
for(int32_t i = tree->size ; i < alloc; i++) { \
|
||||
ptr[i].parent = M_TR33_NO_NODE; \
|
||||
ptr[i].left = M_TR33_NO_NODE; \
|
||||
ptr[i].right = M_TR33_NO_NODE; \
|
||||
ptr[i].child = i + 1; \
|
||||
} \
|
||||
/* The last node has no child in the free node list */ \
|
||||
ptr[alloc-1].child = M_TR33_NO_NODE; \
|
||||
/* Save the free list state in the tree */ \
|
||||
tree->tab = ptr; \
|
||||
tree->capacity = alloc; \
|
||||
ret = tree->size; \
|
||||
} \
|
||||
/* Pop an element in the list of free nodes */ \
|
||||
tree->free_index = tree->tab[ret].child; \
|
||||
tree->size ++; \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C3(m_tr33_, name, _free_node)(tree_t tree, m_tr33_index_t i) { \
|
||||
tree->tab[i].parent = M_TR33_NO_NODE; \
|
||||
tree->tab[i].left = M_TR33_NO_NODE; \
|
||||
tree->tab[i].right = M_TR33_NO_NODE; \
|
||||
tree->tab[i].child = tree->free_index; \
|
||||
tree->size --; \
|
||||
tree->free_index = i; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _set_root)(tree_t tree, type const data) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
M_C(name, _reset)(tree); \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(tree); \
|
||||
tree->tab[i].parent = M_TR33_ROOT_NODE; \
|
||||
tree->tab[i].left = M_TR33_NO_NODE; \
|
||||
tree->tab[i].right = M_TR33_NO_NODE; \
|
||||
tree->tab[i].child = M_TR33_NO_NODE; \
|
||||
tree->root_index = i; \
|
||||
M_CALL_INIT_SET(oplist, tree->tab[i].data, data); \
|
||||
it_t it; \
|
||||
it.tree = tree; \
|
||||
it.index = tree->root_index; \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
/* The iterator references the first root node */ \
|
||||
static inline it_t \
|
||||
M_C(name, _it)(tree_t tree) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
it_t it; \
|
||||
it.tree = tree; \
|
||||
it.index = tree->root_index; \
|
||||
M_TR33_IT_CONTRACT(it, false); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, false); \
|
||||
return it.index < 0; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return &it.tree->tab[it.index].data; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return M_CONST_CAST(type, &it.tree->tab[it.index].data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _up_ref)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = it.tree->tab[it.index].parent; \
|
||||
return i < 0 ? NULL : &it.tree->tab[i].data; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _down_ref)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = it.tree->tab[it.index].child; \
|
||||
return i < 0 ? NULL : &it.tree->tab[i].data; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _left_ref)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = it.tree->tab[it.index].left; \
|
||||
return i < 0 ? NULL : &it.tree->tab[i].data; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _right_ref)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = it.tree->tab[it.index].right; \
|
||||
return i < 0 ? NULL : &it.tree->tab[i].data; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _insert_up)(it_t it, type const data) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
|
||||
m_tr33_index_t parent = it.tree->tab[it.index].parent; \
|
||||
it.tree->tab[i].parent = parent; \
|
||||
it.tree->tab[i].left = it.tree->tab[it.index].left; \
|
||||
it.tree->tab[i].right = it.tree->tab[it.index].right; \
|
||||
it.tree->tab[i].child = it.index; \
|
||||
it.tree->tab[it.index].parent = i; \
|
||||
it.tree->tab[it.index].left = M_TR33_NO_NODE; \
|
||||
it.tree->tab[it.index].right = M_TR33_NO_NODE; \
|
||||
if (M_UNLIKELY(it.tree->root_index == it.index)) { \
|
||||
/* We have added a parent to the root node. Update root index */ \
|
||||
it.tree->root_index = i; \
|
||||
} else { if (it.tree->tab[ parent ].child == it.index) { \
|
||||
/* Update the parent to point to the new child */ \
|
||||
it.tree->tab[ parent ].child = i; \
|
||||
} } \
|
||||
/* Return updated iterator on the inserted node */ \
|
||||
it.index = i; \
|
||||
M_CALL_INIT_SET(oplist, it.tree->tab[i].data, data); \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _insert_down)(it_t it, type const data) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
|
||||
m_tr33_index_t child = it.tree->tab[it.index].child; \
|
||||
it.tree->tab[i].parent = it.index; \
|
||||
it.tree->tab[i].left = M_TR33_NO_NODE; \
|
||||
it.tree->tab[i].right = M_TR33_NO_NODE; \
|
||||
it.tree->tab[i].child = child; \
|
||||
it.tree->tab[it.index].child = i; \
|
||||
/* Update the parent of all the childs if at least one exists */ \
|
||||
while (child != M_TR33_NO_NODE) { \
|
||||
it.tree->tab[child].parent = i; \
|
||||
child = it.tree->tab[child].right; \
|
||||
} \
|
||||
/* Return updated iterator on the inserted node */ \
|
||||
it.index = i; \
|
||||
M_CALL_INIT_SET(oplist, it.tree->tab[i].data, data); \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _insert_child)(it_t it, type const data) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
/* Insert a node as a child of another, making the current childreen \
|
||||
of the nodes their siblings */ \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
|
||||
m_tr33_index_t child = it.tree->tab[it.index].child; \
|
||||
it.tree->tab[i].parent = it.index; \
|
||||
it.tree->tab[i].left = M_TR33_NO_NODE; \
|
||||
it.tree->tab[i].right = child; \
|
||||
it.tree->tab[i].child = M_TR33_NO_NODE; \
|
||||
/* Update the parent */ \
|
||||
it.tree->tab[it.index].child = i; \
|
||||
/* Update the sibling */ \
|
||||
if (child != M_TR33_NO_NODE) { \
|
||||
it.tree->tab[child].left = i; \
|
||||
} \
|
||||
/* Return updated iterator on the inserted node */ \
|
||||
it.index = i; \
|
||||
M_CALL_INIT_SET(oplist, it.tree->tab[i].data, data); \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _insert_left)(it_t it, type const data) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
|
||||
m_tr33_index_t left = it.tree->tab[it.index].left; \
|
||||
m_tr33_index_t parent = it.tree->tab[it.index].parent; \
|
||||
it.tree->tab[i].parent = parent; \
|
||||
it.tree->tab[i].left = left; \
|
||||
it.tree->tab[i].right = it.index; \
|
||||
it.tree->tab[i].child = M_TR33_NO_NODE; \
|
||||
it.tree->tab[it.index].left = i; \
|
||||
/* If there is a left node, update its right */ \
|
||||
if (left > 0) { it.tree->tab[left].right = i; } \
|
||||
/* Might insert left of root: update root in this case */ \
|
||||
if (M_UNLIKELY(parent == M_TR33_ROOT_NODE)) { \
|
||||
it.tree->root_index = i; \
|
||||
} else { if (it.tree->tab[parent].child == it.index) { \
|
||||
/* Update the first child of the parent */ \
|
||||
it.tree->tab[parent].child = i; \
|
||||
} } \
|
||||
/* Return updated iterator on the inserted node */ \
|
||||
it.index = i; \
|
||||
M_CALL_INIT_SET(oplist, it.tree->tab[i].data, data); \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _insert_right)(it_t it, type const data) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
|
||||
m_tr33_index_t right = it.tree->tab[it.index].right; \
|
||||
it.tree->tab[i].parent = it.tree->tab[it.index].parent; \
|
||||
it.tree->tab[i].left = it.index; \
|
||||
it.tree->tab[i].right = right; \
|
||||
it.tree->tab[i].child = M_TR33_NO_NODE; \
|
||||
if (right > 0) { it.tree->tab[right].left = i; } \
|
||||
it.tree->tab[it.index].right = i; \
|
||||
/* Return updated iterator on the inserted node */ \
|
||||
it.index = i; \
|
||||
M_CALL_INIT_SET(oplist, it.tree->tab[i].data, data); \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_up)(it_t *it) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
m_tr33_index_t i = it->tree->tab[it->index].parent; \
|
||||
bool ret = i >= 0; \
|
||||
if (M_LIKELY(ret)) { \
|
||||
it->index = i; \
|
||||
} \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_down)(it_t *it) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
m_tr33_index_t i = it->tree->tab[it->index].child; \
|
||||
bool ret = i >= 0; \
|
||||
if (M_LIKELY(ret)) { \
|
||||
it->index = i; \
|
||||
} \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_left)(it_t *it) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
m_tr33_index_t i = it->tree->tab[it->index].left; \
|
||||
bool ret = i >= 0; \
|
||||
if (M_LIKELY(ret)) { \
|
||||
it->index = i; \
|
||||
} \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_right)(it_t *it) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
m_tr33_index_t i = it->tree->tab[it->index].right; \
|
||||
bool ret = i >= 0; \
|
||||
if (M_LIKELY(ret)) { \
|
||||
it->index = i; \
|
||||
} \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _root_p)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it.tree->tab[it.index].parent == M_TR33_ROOT_NODE; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _node_p)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it.tree->tab[it.index].child != M_TR33_NO_NODE; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _leaf_p)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
return it.tree->tab[it.index].child == M_TR33_NO_NODE; \
|
||||
} \
|
||||
\
|
||||
/* Compute the degree of a node in linear time */ \
|
||||
static inline int32_t \
|
||||
M_C(name, _degree)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
int32_t ret = 0; \
|
||||
m_tr33_index_t i = it.tree->tab[it.index].child; \
|
||||
while (i >= 0) { \
|
||||
ret ++; \
|
||||
i = it.tree->tab[i].right; \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
/* Compute the depth of a node in linear time */ \
|
||||
static inline int32_t \
|
||||
M_C(name, _depth)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
int32_t ret = 0; \
|
||||
m_tr33_index_t i = it.tree->tab[it.index].parent; \
|
||||
while (i >= 0) { \
|
||||
ret ++; \
|
||||
i = it.tree->tab[i].parent; \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(name, _s) * \
|
||||
M_C(name, _tree)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, false); \
|
||||
return it.tree; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _unlink)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
m_tr33_index_t parent, child, left, right, child_r; \
|
||||
parent = it.tree->tab[it.index].parent; \
|
||||
child = it.tree->tab[it.index].child; \
|
||||
left = it.tree->tab[it.index].left; \
|
||||
right = it.tree->tab[it.index].right; \
|
||||
/* Test if No child for this node */ \
|
||||
if (child == M_TR33_NO_NODE) { \
|
||||
/* Remove node from sibling */ \
|
||||
if (left != M_TR33_NO_NODE) { \
|
||||
it.tree->tab[left].right = right; \
|
||||
} \
|
||||
if (right != M_TR33_NO_NODE) { \
|
||||
it.tree->tab[right].left = left; \
|
||||
} \
|
||||
/* Remove node from parent if it is the first child */ \
|
||||
if (parent >= 0 && it.tree->tab[parent].child == it.index) { \
|
||||
M_ASSERT(left == M_TR33_NO_NODE); \
|
||||
it.tree->tab[parent].child = right; \
|
||||
} \
|
||||
} else { \
|
||||
/* Merge the child with the current siblings */ \
|
||||
/* Compute the range of childs & update their parent */ \
|
||||
child_r = child; \
|
||||
it.tree->tab[child_r].parent = parent; \
|
||||
while (it.tree->tab[child_r].right != M_TR33_NO_NODE) { \
|
||||
child_r = it.tree->tab[child].right; \
|
||||
it.tree->tab[child_r].parent = parent; \
|
||||
} \
|
||||
/* Remove node from sibling */ \
|
||||
if (left != M_TR33_NO_NODE) { \
|
||||
it.tree->tab[left].right = child; \
|
||||
it.tree->tab[child].left = left; \
|
||||
} \
|
||||
if (right != M_TR33_NO_NODE) { \
|
||||
it.tree->tab[right].left = child_r; \
|
||||
it.tree->tab[child_r].right = right; \
|
||||
} \
|
||||
/* Remove node from parent if it is the first child */ \
|
||||
if (parent >= 0 && it.tree->tab[parent].child == it.index) { \
|
||||
M_ASSERT(left == M_TR33_NO_NODE); \
|
||||
it.tree->tab[parent].child = child; \
|
||||
} \
|
||||
} \
|
||||
/* Free the node to the allocator */ \
|
||||
M_C3(m_tr33_, name, _free_node)(it.tree, it.index); \
|
||||
return &it.tree->tab[it.index].data; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _remove)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, false); \
|
||||
if (M_UNLIKELY(it.index < 0)) { return false; } \
|
||||
type *ptr = M_C(name, _unlink)(it); \
|
||||
M_CALL_CLEAR(oplist, *ptr); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Scan all nodes, first the parent then the children (uses with _it) */ \
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t *it) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
/* First go down, if impossible go right */ \
|
||||
if (M_C(name, _it_down)(it) || M_C(name, _it_right)(it)) { \
|
||||
return; \
|
||||
} \
|
||||
/* If impossible to go right, move up and then right until impossible */ \
|
||||
while (M_C(name, _it_up)(it)) { \
|
||||
if (M_C(name, _it_right)(it)) { \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
/* Reach end of tree */ \
|
||||
it->index = M_TR33_NO_NODE; \
|
||||
M_TR33_IT_CONTRACT(*it, false); \
|
||||
} \
|
||||
\
|
||||
/* Scan all nodes, first the children then the parent */ \
|
||||
static inline it_t \
|
||||
M_C(name, _it_post)(tree_t tree) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
it_t it; \
|
||||
it.tree = tree; \
|
||||
it.index = tree->root_index; \
|
||||
/* Evaluate child first, so go down to the lowest child */ \
|
||||
while (M_C(name, _it_down)(&it)) {} \
|
||||
M_TR33_IT_CONTRACT(it, false); \
|
||||
return it; \
|
||||
} \
|
||||
\
|
||||
/* Scan all nodes, first the children then the parent (uses with _it_post) */ \
|
||||
static inline void \
|
||||
M_C(name, _next_post)(it_t *it) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
/* First go right */ \
|
||||
if (M_C(name, _it_right)(it)) { \
|
||||
/* then go down */ \
|
||||
while (M_C(name, _it_down)(it)) {} \
|
||||
return; \
|
||||
} \
|
||||
/* If impossible to go right, move up */ \
|
||||
if (M_C(name, _it_up)(it)) { \
|
||||
return; \
|
||||
} \
|
||||
/* Reach end of tree */ \
|
||||
it->index = M_TR33_NO_NODE; \
|
||||
M_TR33_IT_CONTRACT(*it, false); \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
M_C(name, _it_equal_p)(it_t it1, it_t it2) { \
|
||||
M_TR33_IT_CONTRACT(it1, false); \
|
||||
M_TR33_IT_CONTRACT(it2, false); \
|
||||
return it1.tree == it2.tree && it1.index == it2.index; \
|
||||
} \
|
||||
\
|
||||
/* Scan the nodes of it_ref, first the parent then the children */ \
|
||||
static inline void \
|
||||
M_C(name, _next_section)(it_t *it, it_t it_ref) { \
|
||||
M_TR33_IT_CONTRACT(*it, true); \
|
||||
M_ASSERT(it->tree == it_ref.tree); \
|
||||
/* First go down, if impossible go right */ \
|
||||
if (M_C(name, _it_down)(it)) { return; } \
|
||||
if (M_C(name, _it_right)(it)) { return;} \
|
||||
/* If impossible to go right, move up and then right for the all section */ \
|
||||
while (M_C(name, _it_up)(it) && it->index != it_ref.index) { \
|
||||
if (M_C(name, _it_right)(it)) { \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
/* Reach end of section */ \
|
||||
it->index = M_TR33_NO_NODE; \
|
||||
M_TR33_IT_CONTRACT(*it, false); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _prune)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
/* remove the node, including its childs */ \
|
||||
/* Fast removal of all the childs as we don't need to perfom a clean unlink */ \
|
||||
it_t child = it; \
|
||||
M_C(name, _next_section)(&child, it); \
|
||||
while (!M_C(name, _end_p)(child)) { \
|
||||
M_C3(m_tr33_, name, _free_node)(child.tree, child.index); \
|
||||
M_CALL_CLEAR(oplist, child.tree->tab[child.index]); \
|
||||
M_C(name, _next_section)(&child, it); \
|
||||
} \
|
||||
/* Unlink the removed node */ \
|
||||
it.tree->tab[it.index].child = M_TR33_NO_NODE; \
|
||||
bool b = M_C(name, _remove)(it); \
|
||||
M_ASSERT(b); \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _lca)(it_t it1, it_t it2) { \
|
||||
M_TR33_IT_CONTRACT(it1, true); \
|
||||
M_TR33_IT_CONTRACT(it2, true); \
|
||||
/* Compute the Lowest Common Ancestor in linear time */ \
|
||||
int32_t d1 = M_C(name, _depth)(it1); \
|
||||
int32_t d2 = M_C(name, _depth)(it2); \
|
||||
bool b = true; \
|
||||
if (d1 > d2) { \
|
||||
M_SWAP(int32_t, d1, d2); \
|
||||
M_SWAP(it_t, it1, it2); \
|
||||
} \
|
||||
/* it2 is deeper than it1 */ \
|
||||
while (d1 < d2) { \
|
||||
b = M_C(name, _it_up)(&it2); \
|
||||
d2--; \
|
||||
assert(b); \
|
||||
} \
|
||||
/* Move up both iterators until we found the common node */ \
|
||||
while (b && it1.index != it2.index) { \
|
||||
b = M_C(name, _it_up)(&it1); \
|
||||
b = M_C(name, _it_up)(&it2); \
|
||||
} \
|
||||
/* If we went back to the root node, and cannot find a common node */ \
|
||||
if (b == false) { \
|
||||
it1.index = M_TR33_NO_NODE; \
|
||||
} \
|
||||
return it1; \
|
||||
} \
|
||||
\
|
||||
static inline it_t \
|
||||
M_C(name, _swap_at)(it_t it1, it_t it2) { \
|
||||
M_ASSERT(it1.tree == it2.tree); \
|
||||
M_TR33_IT_CONTRACT(it1, true); \
|
||||
M_TR33_IT_CONTRACT(it2, true); \
|
||||
m_tr33_index_t tmp1, tmp2; \
|
||||
/* Swap left references */ \
|
||||
tmp1 = it1.tree->tab[it1.index].left; \
|
||||
tmp2 = it2.tree->tab[it2.index].left; \
|
||||
it1.tree->tab[it1.index].left = tmp2; \
|
||||
it2.tree->tab[it2.index].left = tmp1; \
|
||||
if (tmp1 >= 0) { it1.tree->tab[tmp1].right = it2.index; } \
|
||||
if (tmp2 >= 0) { it2.tree->tab[tmp2].right = it1.index; } \
|
||||
/* Swap right references */ \
|
||||
tmp1 = it1.tree->tab[it1.index].right; \
|
||||
tmp2 = it2.tree->tab[it2.index].right; \
|
||||
it1.tree->tab[it1.index].right = tmp2; \
|
||||
it2.tree->tab[it2.index].right = tmp1; \
|
||||
if (tmp1 >= 0) { it1.tree->tab[tmp1].left = it2.index; } \
|
||||
if (tmp2 >= 0) { it2.tree->tab[tmp2].left = it1.index; } \
|
||||
/* Swap down references */ \
|
||||
tmp1 = it1.tree->tab[it1.index].child; \
|
||||
tmp2 = it2.tree->tab[it2.index].child; \
|
||||
it1.tree->tab[it1.index].child = tmp2; \
|
||||
it2.tree->tab[it2.index].child = tmp1; \
|
||||
while (tmp1 >= 0) { \
|
||||
it1.tree->tab[tmp1].parent = it2.index; \
|
||||
tmp1 = it1.tree->tab[tmp1].right; \
|
||||
} \
|
||||
while (tmp2 >= 0) { \
|
||||
it2.tree->tab[tmp2].parent = it1.index; \
|
||||
tmp2 = it2.tree->tab[tmp2].right; \
|
||||
} \
|
||||
/* Swap up references */ \
|
||||
tmp1 = it1.tree->tab[it1.index].parent; \
|
||||
tmp2 = it2.tree->tab[it2.index].parent; \
|
||||
it1.tree->tab[it1.index].parent = tmp2; \
|
||||
it2.tree->tab[it2.index].parent = tmp1; \
|
||||
if (it1.tree->tab[tmp1].child == it1.index) { \
|
||||
it1.tree->tab[tmp1].child = it2.index; \
|
||||
} \
|
||||
if (it2.tree->tab[tmp2].child == it2.index) { \
|
||||
it2.tree->tab[tmp2].child = it1.index; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
M_C(name, _graft_child)(it_t it1, const it_t it2) { \
|
||||
M_ASSERT(it1.tree == it2.tree); \
|
||||
M_TR33_IT_CONTRACT(it1, true); \
|
||||
M_TR33_IT_CONTRACT(it2, true); \
|
||||
/* Move the node it2 and its child down the node *it1 */ \
|
||||
/* Both belongs to the same tree */ \
|
||||
m_tr33_index_t i = it2.index; \
|
||||
/* Unlink it2 except its child */ \
|
||||
m_tr33_index_t parent = it1.tree->tab[i].parent; \
|
||||
if (parent >= 0 && it1.tree->tab[parent].child == i) { \
|
||||
it1.tree->tab[parent].child = it1.tree->tab[i].right; \
|
||||
} \
|
||||
m_tr33_index_t left = it1.tree->tab[i].left; \
|
||||
if (left >= 0) { it1.tree->tab[left].right = it1.tree->tab[i].right;} \
|
||||
m_tr33_index_t right = it1.tree->tab[i].right; \
|
||||
if (right >= 0) { it1.tree->tab[right].left = it1.tree->tab[i].left;} \
|
||||
/* Add the new node */ \
|
||||
m_tr33_index_t child = it1.tree->tab[it1.index].child; \
|
||||
it1.tree->tab[i].parent = it1.index; \
|
||||
it1.tree->tab[i].left = M_TR33_NO_NODE; \
|
||||
it1.tree->tab[i].right = child; \
|
||||
it1.tree->tab[i].child = M_TR33_NO_NODE; \
|
||||
/* Update the parent */ \
|
||||
it1.tree->tab[it1.index].child = i; \
|
||||
/* Update the sibling */ \
|
||||
if (child != M_TR33_NO_NODE) { \
|
||||
it1.tree->tab[child].left = i; \
|
||||
} \
|
||||
M_TR33_IT_CONTRACT(it1, true); \
|
||||
M_TR33_IT_CONTRACT(it2, true); \
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// * insertion function with move semantics.
|
||||
// * Sort the nodes of a child in function of a userfunction
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user