/*
 * M*LIB - TREE module
 *
 * Copyright (c) 2017-2023, 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_F(name, _t), M_F(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)->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)->allow_realloc == 0 || (tree)->allow_realloc == INT32_MAX ); \
    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)->allow_realloc != 0 || (tree)->free_index < 0 || (tree)->tab[(tree)->free_index].parent == M_TR33_NO_NODE); \
    M_ASSERT( (tree)->allow_realloc != 0 || (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_ASSERT( (it).index < (it).tree->capacity);                          \
        M_TR33_NODE_CONTRACT(&(it).tree->tab[(it).index], (it).tree);         \
        /* Don't deref table if realloc is disabled as the tree can be        \
           accessed concurrently (for _ref methods) */                        \
        if ( (it).tree->allow_realloc == 0) {                                 \
        /* All children of this node have the parent field correctly set */   \
        m_tr33_index_t itj = (it).tree->tab[(it).index].child;                \
        /* They all have their siblings as the left node */                   \
        m_tr33_index_t lftj = 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 == lftj );                     \
            lftj = itj;                                                       \
            itj = (it).tree->tab[itj].right;                                  \
            M_ASSERT( ++cpt < M_USE_TREE_MAX_CHILD_PER_PARENT);               \
        }                                                                     \
        (void) cpt; /* may be unused in release mode */                       \
        (void) lftj; /* may be unused in release mode */                      \
        }                                                                     \
    }                                                                         \
} 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)                       \
  M_TR33_DEF_TYPE(name, type, oplist, tree_t, it_t)                           \
  M_TR33_DEF_P4_CORE(name, type, oplist, tree_t, it_t)                        \
  M_TR33_DEF_P4_EXT(name, type, oplist, tree_t, it_t)                         \
  M_TR33_DEF_P4_IO(name, type, oplist, tree_t, it_t)                          \
  M_TR33_DEF_P4_EMPLACE(name, type, oplist, tree_t, it_t)

#define M_TR33_DEF_TYPE(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_F(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_F(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'.             \
       + allow_realloc is a bool encoded as true=0 and false=INT32_MAX        \
       + tab is a pointer to the allocated nodes.                             \
    */                                                                        \
    typedef struct M_F(name, _s) {                                            \
        m_tr33_index_t       size;                                            \
        m_tr33_index_t       capacity;                                        \
        m_tr33_index_t       root_index;                                      \
        m_tr33_index_t       free_index;                                      \
        uint32_t             allow_realloc;                                   \
        M_F(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_F(name, _it_s) {                                         \
        struct M_F(name, _s) *tree;                                           \
        m_tr33_index_t        index;                                          \
    } it_t;                                                                   \
                                                                              \
    typedef it_t M_F(name, _it_ct);

/* Define the core & unique methods of a tree */
#define M_TR33_DEF_P4_CORE(name, type, oplist, tree_t, it_t)                  \
    /* Initialize a generic tree (empty) */                                   \
    M_INLINE void                                                             \
    M_F(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->allow_realloc = 0;                                              \
        tree->tab = NULL;                                                     \
        M_TR33_CONTRACT(tree);                                                \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(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);                                                \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _clear)(tree_t tree) {                                          \
        M_F(name, _reset)(tree);                                              \
        struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\
        M_CALL_FREE(oplist, ptr);                                             \
        /* This is so reusing the object implies an assertion failure */      \
        tree->size = 1;                                                       \
        tree->tab = NULL;                                                     \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _reserve)(tree_t tree, size_t alloc) {                          \
        M_TR33_CONTRACT(tree);                                                \
        /* Nothing to do if the request is lower than the current capacity. */ \
        if (alloc <= (size_t) tree->capacity) {                               \
            return;                                                           \
        }                                                                     \
        /* Realloc the array */                                               \
        if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) {                          \
            M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc);        \
            return;                                                           \
        }                                                                     \
        /* Allocate one more term in the array so that tab[-1] exists.        \
           This enables performing latter tab[M_TR33_NO_NODE].x = something;  \
           as M_TR33_NO_NODE is -1. This enables avoiding testing for         \
           M_TR33_NO_NODE in some cases, performing branchless code. */       \
        struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\
        ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, alloc+1);\
        if (M_UNLIKELY_NOMEM (ptr == NULL) ) {                                \
            M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc);        \
            return;                                                           \
        }                                                                     \
        /* Skip the first term to keep it as empty & unused */                \
        ptr++;                                                                \
        /* Free the list */                                                   \
        m_tr33_index_t *free_index = &tree->free_index;                       \
        if (*free_index != M_TR33_NO_NODE) {                                  \
            while (ptr[*free_index].child != M_TR33_NO_NODE) {                \
                free_index = &ptr[*free_index].child;                         \
            }                                                                 \
        }                                                                     \
        *free_index = tree->capacity;                                         \
        /* Construct the list of free node in the extra allocated pool */     \
        for(size_t i = (size_t)tree->capacity; 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  = (m_tr33_index_t)(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 = (m_tr33_index_t) alloc;                              \
        M_TR33_CONTRACT(tree);                                                \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _lock)(tree_t tree, bool lock) {                                \
        M_TR33_CONTRACT(tree);                                                \
        tree->allow_realloc = lock ? INT32_MAX : 0;                           \
        M_TR33_CONTRACT(tree);                                                \
    }                                                                         \
                                                                              \
    M_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 */                     \
            size_t alloc = M_CALL_INC_ALLOC(oplist, (size_t) tree->capacity); \
            /* Take into account if realloc is allowed */                     \
            alloc += tree->allow_realloc;                                     \
            if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) {                      \
                M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc);    \
                return M_TR33_NO_NODE;                                        \
            }                                                                 \
            /* Allocate one more term in the array so that tab[-1] exists.    \
            This enables performing latter tab[M_TR33_NO_NODE].x = something; \
            as M_TR33_NO_NODE is -1. This enables avoiding testing for        \
            M_TR33_NO_NODE in some cases, performing branchless code. */      \
            struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1; \
            ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, alloc+1); \
            if (M_UNLIKELY_NOMEM (ptr == NULL) ) {                            \
                M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc);    \
                return M_TR33_NO_NODE;                                        \
            }                                                                 \
            /* Skip the first term to keep it as empty & unused */            \
            ptr++;                                                            \
            /* Construct the list of free node in the extra allocated pool */ \
            M_ASSERT(tree->capacity >= 0);                                    \
            for(size_t i = (size_t) tree->capacity; 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  = (m_tr33_index_t) 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 = (m_tr33_index_t) alloc;                          \
            ret = tree->size;                                                 \
        }                                                                     \
        /* Pop an element in the list of free nodes */                        \
        tree->free_index = tree->tab[ret].child;                              \
        tree->size ++;                                                        \
        return ret;                                                           \
    }                                                                         \
                                                                              \
    M_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;                                                 \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _set_root)(tree_t tree, type const data) {                      \
        M_TR33_CONTRACT(tree);                                                \
        M_F(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 */                         \
    /* usually for pre-order walk */                                          \
    M_INLINE it_t                                                             \
    M_F(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;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _it_end)(tree_t tree) {                                         \
        M_TR33_CONTRACT(tree);                                                \
        it_t it;                                                              \
        it.tree = tree;                                                       \
        it.index = M_TR33_NO_NODE;                                            \
        M_TR33_IT_CONTRACT(it, false);                                        \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _end_p)(it_t it) {                                              \
        M_TR33_IT_CONTRACT(it, false);                                        \
        return it.index < 0;                                                  \
    }                                                                         \
                                                                              \
    M_INLINE type *                                                           \
    M_F(name, _ref)(it_t it) {                                                \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return &it.tree->tab[it.index].data;                                  \
    }                                                                         \
                                                                              \
    M_INLINE type const *                                                     \
    M_F(name, _cref)(it_t it) {                                               \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return M_CONST_CAST(type, &it.tree->tab[it.index].data);              \
    }                                                                         \
                                                                              \
    M_INLINE type *                                                           \
    M_F(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;                          \
    }                                                                         \
                                                                              \
    M_INLINE type *                                                           \
    M_F(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;                          \
    }                                                                         \
                                                                              \
    M_INLINE type *                                                           \
    M_F(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;                          \
    }                                                                         \
                                                                              \
    M_INLINE type *                                                           \
    M_F(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;                          \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_up_raw)(it_t it) {                                      \
        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;                \
        m_tr33_index_t left   = it.tree->tab[it.index].left;                  \
        m_tr33_index_t right  = it.tree->tab[it.index].right;                 \
        it.tree->tab[i].parent = parent;                                      \
        it.tree->tab[i].left   = left;                                        \
        it.tree->tab[i].right  = 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;                                          \
            M_ASSERT( it.tree->tab[i].parent == M_TR33_ROOT_NODE);            \
        } else { if (it.tree->tab[parent].child == it.index) {                \
            /* Update the parent to point to the new child */                 \
            it.tree->tab[parent].child = i;                                   \
        } }                                                                   \
        it.tree->tab[left].right = i;                                         \
        it.tree->tab[right].left = i;                                         \
        /* Return updated iterator on the inserted node */                    \
        it.index = i;                                                         \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_up)(it_t pos, type const data) {                        \
        it_t it = M_F(name, _insert_up_raw)(pos);                             \
        M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _move_up)(it_t pos, type *data) {                               \
        it_t it = M_F(name, _insert_up_raw)(pos);                             \
        M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_down_raw)(it_t it) {                                    \
        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_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_down)(it_t pos, type const data) {                      \
        it_t it = M_F(name, _insert_down_raw)(pos);                           \
        M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _move_down)(it_t pos, type *data) {                             \
        it_t it = M_F(name, _insert_down_raw)(pos);                           \
        M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_child_raw)(it_t it) {                                   \
        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 */                                              \
        it.tree->tab[child].left = i;                                         \
        /* Return updated iterator on the inserted node */                    \
        it.index = i;                                                         \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_child)(it_t pos, type const data) {                     \
        it_t it = M_F(name, _insert_child_raw)(pos);                          \
        M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _move_child)(it_t pos, type *data) {                            \
        it_t it = M_F(name, _insert_child_raw)(pos);                          \
        M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_left_raw)(it_t it) {                                    \
        M_TR33_IT_CONTRACT(it, true);                                         \
        M_ASSERT(it.index != it.tree->root_index);                            \
        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 */                       \
        it.tree->tab[left].right = i;                                         \
        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_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_left)(it_t pos, type const data) {                      \
        it_t it = M_F(name, _insert_left_raw)(pos);                           \
        M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _move_left)(it_t pos, type *data) {                             \
        it_t it = M_F(name, _insert_left_raw)(pos);                           \
        M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_right_raw)(it_t it) {                                   \
        M_TR33_IT_CONTRACT(it, true);                                         \
        M_ASSERT(it.index != it.tree->root_index);                            \
        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;                              \
        it.tree->tab[right].left = i;                                         \
        it.tree->tab[it.index].right = i;                                     \
        /* Return updated iterator on the inserted node */                    \
        it.index = i;                                                         \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _insert_right)(it_t pos, type const data) {                     \
        it_t it = M_F(name, _insert_right_raw)(pos);                          \
        M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _move_right)(it_t pos, type *data) {                            \
        it_t it = M_F(name, _insert_right_raw)(pos);                          \
        M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data);           \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it;                                                            \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _it_up)(it_t *it) {                                             \
        M_ASSERT(it != NULL);                                                 \
        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;                                                           \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _it_down)(it_t *it) {                                           \
        M_ASSERT(it != NULL);                                                 \
        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;                                                           \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _it_left)(it_t *it) {                                           \
        M_ASSERT(it != NULL);                                                 \
        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;                                                           \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _it_right)(it_t *it) {                                          \
        M_ASSERT(it != NULL);                                                 \
        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;                                                           \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _root_p)(const it_t it) {                                       \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it.tree->tab[it.index].parent == M_TR33_ROOT_NODE;             \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _node_p)(const it_t it) {                                       \
        M_TR33_IT_CONTRACT(it, true);                                         \
        return it.tree->tab[it.index].child != M_TR33_NO_NODE;                \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _leaf_p)(const 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 */                         \
    M_INLINE int32_t                                                          \
    M_F(name, _degree)(const 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 */                          \
    M_INLINE int32_t                                                          \
    M_F(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;                                                           \
    }                                                                         \
                                                                              \
    M_INLINE struct M_F(name, _s) *                                           \
    M_F(name, _tree)(it_t it) {                                               \
        M_TR33_IT_CONTRACT(it, false);                                        \
        return it.tree;                                                       \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _swap_at)(it_t it1, it_t it2, bool swapChild) {                 \
        M_ASSUME(it1.tree == it2.tree);                                       \
        M_TR33_IT_CONTRACT(it1, true);                                        \
        M_TR33_IT_CONTRACT(it2, true);                                        \
        if (M_UNLIKELY(it1.index == it2.index)) { return; }                   \
        /* Read all references before modifying anything */                   \
        m_tr33_index_t tmp1_l = it1.tree->tab[it1.index].left;                \
        m_tr33_index_t tmp2_l = it2.tree->tab[it2.index].left;                \
        m_tr33_index_t tmp1_r = it1.tree->tab[it1.index].right;               \
        m_tr33_index_t tmp2_r = it2.tree->tab[it2.index].right;               \
        m_tr33_index_t tmp1_d = it1.tree->tab[it1.index].child;               \
        m_tr33_index_t tmp2_d = it2.tree->tab[it2.index].child;               \
        m_tr33_index_t tmp1_u = it1.tree->tab[it1.index].parent;              \
        m_tr33_index_t tmp2_u = it2.tree->tab[it2.index].parent;              \
        /* Special cases if both nodes are siblings of the same node */       \
        if (tmp1_r == it2.index) {                                            \
            M_ASSERT(tmp2_l == it1.index);                                    \
            tmp1_r = it1.index;                                               \
            tmp2_l = it2.index;                                               \
        }                                                                     \
        if (tmp2_r == it1.index) {                                            \
            M_ASSERT(tmp1_l == it2.index);                                    \
            tmp2_r = it2.index;                                               \
            tmp1_l = it1.index;                                               \
        }                                                                     \
        if (tmp1_u == it2.index) {                                            \
            tmp1_u = it1.index;                                               \
            if (tmp2_d == it1.index) { tmp2_d = it2.index; }                  \
        }                                                                     \
        if (tmp2_u == it1.index) {                                            \
            tmp2_u = it2.index;                                               \
            if (tmp1_d == it2.index) { tmp1_d = it1.index; }                  \
        }                                                                     \
        /* Swap left references */                                            \
        it1.tree->tab[it1.index].left = tmp2_l;                               \
        it2.tree->tab[it2.index].left = tmp1_l;                               \
        it1.tree->tab[tmp1_l].right = it2.index;                              \
        it2.tree->tab[tmp2_l].right = it1.index;                              \
        /* Swap right references */                                           \
        it1.tree->tab[it1.index].right = tmp2_r;                              \
        it2.tree->tab[it2.index].right = tmp1_r;                              \
        it1.tree->tab[tmp1_r].left = it2.index;                               \
        it2.tree->tab[tmp2_r].left = it1.index;                               \
        /* Swap down references */                                            \
        if (swapChild == false) {                                             \
            it1.tree->tab[it1.index].child = tmp2_d;                          \
            it2.tree->tab[it2.index].child = tmp1_d;                          \
            while (tmp1_d >= 0) {                                             \
                it1.tree->tab[tmp1_d].parent = it2.index;                     \
                tmp1_d = it1.tree->tab[tmp1_d].right;                         \
            }                                                                 \
            while (tmp2_d >= 0) {                                             \
                it2.tree->tab[tmp2_d].parent = it1.index;                     \
                tmp2_d = it2.tree->tab[tmp2_d].right;                         \
            }                                                                 \
        }                                                                     \
        /* Swap up references */                                              \
        bool dont_swap_back = true;                                           \
        it1.tree->tab[it1.index].parent = tmp2_u;                             \
        it2.tree->tab[it2.index].parent = tmp1_u;                             \
        if (tmp1_u >= 0 && it1.tree->tab[tmp1_u].child == it1.index) {        \
            it1.tree->tab[tmp1_u].child = it2.index;                          \
            dont_swap_back = tmp1_u != tmp2_u;                                \
        }                                                                     \
        if (tmp1_u == M_TR33_ROOT_NODE) {                                     \
            it1.tree->root_index = it2.index;                                 \
            M_ASSERT(tmp1_u != tmp2_u);                                       \
        }                                                                     \
        /* Both may have the same parent (don't swap back in this case) */    \
        if (tmp2_u >= 0 && dont_swap_back && it2.tree->tab[tmp2_u].child == it2.index) { \
            it2.tree->tab[tmp2_u].child = it1.index;                          \
        }                                                                     \
        if (tmp2_u == M_TR33_ROOT_NODE) {                                     \
            it2.tree->root_index = it1.index;                                 \
            M_ASSERT(tmp1_u != tmp2_u);                                       \
        }                                                                     \
        M_TR33_IT_CONTRACT(it1, true);                                        \
        M_TR33_IT_CONTRACT(it2, true);                                        \
    }                                                                         \
                                                                              \
    M_INLINE type *                                                           \
    M_F(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_child_no_node:                                             \
            /* Remove node from sibling */                                    \
            it.tree->tab[left].right = right;                                 \
            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 if (parent == M_TR33_ROOT_NODE) {                          \
                it.tree->root_index = right;                                  \
            }                                                                 \
        } else {                                                              \
            if (M_UNLIKELY(it.index == it.tree->root_index)) {                \
                /* complex case. Swap root with its first child */            \
                it_t it_child = { it.tree, child };                           \
                M_F(name, _swap_at)(it, it_child, false);                     \
                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;                        \
                if (child == M_TR33_NO_NODE) { goto remove_child_no_node; }   \
            }                                                                 \
            /* Merge the child with the current siblings */                   \
            /* Compute the range of childs & update their parent */           \
            size_t num_child = 1;                                             \
            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_r].right;                        \
                it.tree->tab[child_r].parent = parent;                        \
                num_child ++;                                                 \
            }                                                                 \
            (void) num_child;                                                 \
            M_ASSERT(it.index != it.tree->root_index || num_child == 1);      \
            /* Remove node from sibling */                                    \
            it.tree->tab[left].right = child;                                 \
            it.tree->tab[child].left = left;                                  \
            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;                           \
            }                                                                 \
            M_ASSERT (parent != M_TR33_ROOT_NODE);                            \
        }                                                                     \
        /* Free the node to the allocator */                                  \
        M_C3(m_tr33_, name, _free_node)(it.tree, it.index);                   \
        return &it.tree->tab[it.index].data;                                  \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _remove)(it_t it) {                                             \
        M_TR33_IT_CONTRACT(it, false);                                        \
        if (M_UNLIKELY(it.index < 0)) { return false; }                       \
        type *ptr = M_F(name, _unlink)(it);                                   \
        M_CALL_CLEAR(oplist, *ptr);                                           \
        return true;                                                          \
    }                                                                         \
                                                                              \
    /* Scan all nodes, first the parent then the children (uses with _it) */  \
    /* pre-order walk */                                                      \
    M_INLINE void                                                             \
    M_F(name, _next)(it_t *it) {                                              \
        M_TR33_IT_CONTRACT(*it, true);                                        \
        /* First go down, if impossible go right */                           \
        if (M_F(name, _it_down)(it) || M_F(name, _it_right)(it)) {            \
            return;                                                           \
        }                                                                     \
        /* If impossible to go right, move up and then right until impossible */ \
        while (M_F(name, _it_up)(it)) {                                       \
            if (M_F(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 */                  \
    /* post-order walk */                                                     \
    M_INLINE it_t                                                             \
    M_F(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_F(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) */ \
    /* post-order walk */                                                     \
    M_INLINE void                                                             \
    M_F(name, _next_post)(it_t *it) {                                         \
        M_TR33_IT_CONTRACT(*it, true);                                        \
        /* First go right */                                                  \
        if (M_F(name, _it_right)(it)) {                                       \
            /* then go down */                                                \
            while (M_F(name, _it_down)(it)) {}                                \
            return;                                                           \
        }                                                                     \
        /* If impossible to go right, move up */                              \
        if (M_F(name, _it_up)(it)) {                                          \
            return;                                                           \
        }                                                                     \
        /* Reach end of tree */                                               \
        it->index = M_TR33_NO_NODE;                                           \
        M_TR33_IT_CONTRACT(*it, false);                                       \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(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 all nodes, first the parent, then the children */                 \
    /* post-order walk */                                                     \
    M_INLINE it_t                                                             \
    M_F(name, _it_subpre)(it_t it) {                                          \
        /* Nothing to do as it is already on the parent! */                   \
        return it;                                                            \
    }                                                                         \
                                                                              \
    /* Scan the nodes of it_ref, first the parent then the children */        \
    /* pre-order walk */                                                      \
    M_INLINE void                                                             \
    M_F(name, _next_subpre)(it_t *it, it_t it_ref) {                          \
        M_TR33_IT_CONTRACT(*it, true);                                        \
        M_TR33_IT_CONTRACT(it_ref, true);                                     \
        M_ASSERT(it->tree == it_ref.tree);                                    \
        /* First go down, if impossible go right */                           \
        if (M_F(name, _it_down)(it)) { return; }                              \
        if (M_F(name, _it_right)(it)) { return;}                              \
        /* If impossible to go right, move up and then right for the all section */ \
        while (M_F(name, _it_up)(it) && it->index != it_ref.index) {          \
            if (M_F(name, _it_right)(it)) {                                   \
                return;                                                       \
            }                                                                 \
        }                                                                     \
        /* Reach end of section */                                            \
        it->index = M_TR33_NO_NODE;                                           \
        M_TR33_IT_CONTRACT(*it, false);                                       \
    }                                                                         \
                                                                              \
    /* Scan all nodes, first the children then the parent */                  \
    /* post-order walk */                                                     \
    M_INLINE it_t                                                             \
    M_F(name, _it_subpost)(it_t it) {                                         \
        M_TR33_IT_CONTRACT(it, true);                                         \
        /* Evaluate child first, so go down to the lowest child */            \
        while (M_F(name, _it_down)(&it)) {}                                   \
        M_TR33_IT_CONTRACT(it, false);                                        \
        return it;                                                            \
    }                                                                         \
                                                                              \
    /* Scan all nodes, first the children then the parent (uses with _it_subpost) */ \
    /* post-order walk */                                                     \
    M_INLINE void                                                             \
    M_F(name, _next_subpost)(it_t *it, it_t ref) {                            \
        M_TR33_IT_CONTRACT(*it, true);                                        \
        M_TR33_IT_CONTRACT(ref, true);                                        \
        M_ASSERT(it->tree == ref.tree);                                       \
        if (it->index == ref.index) {                                         \
            /* Reach end of tree */                                           \
            it->index = M_TR33_NO_NODE;                                       \
            return;                                                           \
        }                                                                     \
        /* First go right */                                                  \
        if (M_F(name, _it_right)(it)) {                                       \
            /* then go down */                                                \
            while (M_F(name, _it_down)(it)) {}                                \
            return;                                                           \
        }                                                                     \
        /* If impossible to go right, move up */                              \
        bool b = M_F(name, _it_up)(it);                                       \
        (void) b; /* parameter not used */                                    \
        assert(b);                                                            \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _prune)(it_t it) {                                              \
        M_TR33_IT_CONTRACT(it, true);                                         \
        /* remove the node, including its childs */                           \
        it_t child = M_F(name, _it_subpost)(it);                              \
        while (!M_F(name, _end_p)(child)) {                                   \
            it_t next = child;                                                \
            M_F(name, _next_subpost)(&next, it);                              \
            bool b = M_F(name, _remove)(child);                               \
            (void) b; /* parameter not used */                                \
            M_ASSERT(b);                                                      \
            child = next;                                                     \
        }                                                                     \
    }                                                                         \
                                                                              \
    M_INLINE it_t                                                             \
    M_F(name, _lca)(it_t it1, it_t it2) {                                     \
        M_TR33_IT_CONTRACT(it1, true);                                        \
        M_TR33_IT_CONTRACT(it2, true);                                        \
        M_ASSERT(it1.tree == it2.tree);                                       \
        /* Compute the Lowest Common Ancestor in linear time */               \
        int32_t d1 = M_F(name, _depth)(it1);                                  \
        int32_t d2 = M_F(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_F(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_F(name, _it_up)(&it1);                                      \
            b = M_F(name, _it_up)(&it2);                                      \
        }                                                                     \
        /* If we went back to the root node, we must have found a common node*/ \
        M_ASSERT(b);                                                          \
        return it1;                                                           \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(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);                                        \
        M_ASSERT(it2.index != it2.tree->root_index);                          \
        /* Move the node it2 and its child down the node *it1 */              \
        /* Both belongs to the same tree */                                   \
        const m_tr33_index_t i = it2.index;                                   \
        /* Unlink it2 except its child */                                     \
        const 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;             \
        }                                                                     \
        const m_tr33_index_t left = it1.tree->tab[i].left;                    \
        it1.tree->tab[left].right = it1.tree->tab[i].right;                   \
        const m_tr33_index_t right = it1.tree->tab[i].right;                  \
        it1.tree->tab[right].left = it1.tree->tab[i].left;                    \
        /* Add the new node */                                                \
        const 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;                                       \
        /* Update the parent */                                               \
        it1.tree->tab[it1.index].child = i;                                   \
        /* Update the sibling */                                              \
        it1.tree->tab[child].left = i;                                        \
        M_TR33_IT_CONTRACT(it1, true);                                        \
        M_TR33_IT_CONTRACT(it2, true);                                        \
    }                                                                         \
                                                                              \
    M_IF_METHOD(CMP,oplist)(                                                  \
    M_INLINE void                                                             \
    M_F(name, _sort_child)(it_t it0) {                                        \
        M_TR33_IT_CONTRACT(it0, true);                                        \
        it_t it1 = it0;                                                       \
        /* Go to the child, if it doesn't exist, nothing to sort */           \
        if (!M_F(name, _it_down)(&it1) ) return ;                             \
        /* Selection sort */                                                  \
        do {                                                                  \
            it_t it_min = it1;                                                \
            it_t it2    = it1;                                                \
            while (M_F(name, _it_right)(&it2)) {                              \
                if (M_CALL_CMP(oplist, *M_F(name, _cref)(it2), *M_F(name, _cref)(it_min)) < 0) { \
                    it_min = it2;                                             \
                }                                                             \
            }                                                                 \
            if (M_F(name, _it_equal_p)(it_min, it1) == false) {               \
                M_F(name, _swap_at)(it1, it_min, true);                       \
                /* The iterator it1 is no longer the min */                   \
                it1 = it_min;                                                 \
            }                                                                 \
        } while (M_F(name, _it_right)(&it1));                                 \
        M_TR33_IT_CONTRACT(it0, true);                                        \
    }                                                                         \
    , /* No CMP */ )                                                          \


/* Define the classic extended missing methods of a tree */
#define M_TR33_DEF_P4_EXT(name, type, oplist, tree_t, it_t)                   \
    M_INLINE void                                                             \
    M_F(name, _init_set)(tree_t tree, const tree_t ref) {                     \
        tree->size = ref->size;                                               \
        tree->capacity = ref->capacity;                                       \
        tree->root_index = ref->root_index;                                   \
        tree->free_index = ref->free_index;                                   \
        tree->allow_realloc = ref->allow_realloc;                             \
        size_t alloc = (size_t) ref->capacity;                                \
        if (ref->tab == NULL) {                                               \
            tree->tab = NULL;                                                 \
        } else {                                                              \
            struct M_F(name, _node_s) *ptr =                                  \
                M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, alloc+1); \
            if (M_UNLIKELY_NOMEM (ptr == NULL) ) {                            \
                M_MEMORY_FULL(sizeof(struct M_F(name, _node_s)) * alloc);     \
                return;                                                       \
            }                                                                 \
            tree->tab = ++ptr;                                                \
            /* We don't scan recursively the node tree, but sequentially */   \
            for(m_tr33_index_t i = 0 ; i < ref->capacity ; i ++) {            \
                tree->tab[i].parent = ref->tab[i].parent;                     \
                tree->tab[i].child  = ref->tab[i].child;                      \
                tree->tab[i].left   = ref->tab[i].left;                       \
                tree->tab[i].right  = ref->tab[i].right;                      \
                /* If the node is not a free node, copy the data  */          \
                if (tree->tab[i].parent != M_TR33_NO_NODE) {                  \
                    M_CALL_INIT_SET(oplist, tree->tab[i].data, ref->tab[i].data); \
                }                                                             \
            }                                                                 \
        }                                                                     \
        M_TR33_CONTRACT(tree);                                                \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _set)(tree_t tree, const tree_t ref) {                          \
        /* No optimum, but good enought for present time */                   \
        M_F(name, _clear)(tree);                                              \
        M_F(name, _init_set)(tree, ref);                                      \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _init_move)(tree_t tree, tree_t ref) {                          \
        tree->size = ref->size;                                               \
        tree->capacity = ref->capacity;                                       \
        tree->root_index = ref->root_index;                                   \
        tree->free_index = ref->free_index;                                   \
        tree->allow_realloc = ref->allow_realloc;                             \
        tree->tab = ref->tab;                                                 \
        /* This is so reusing the object implies an assertion failure */      \
        ref->size = 1;                                                        \
        ref->tab = NULL;                                                      \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _move)(tree_t tree, tree_t ref) {                               \
        M_F(name, _clear)(tree);                                              \
        M_F(name, _init_move)(tree, ref);                                     \
    }                                                                         \
                                                                              \
    M_INLINE void                                                             \
    M_F(name, _swap)(tree_t tree1, tree_t tree2) {                            \
        M_TR33_CONTRACT(tree1);                                               \
        M_TR33_CONTRACT(tree2);                                               \
        M_SWAP(m_tr33_index_t, tree1->size, tree2->size);                     \
        M_SWAP(m_tr33_index_t, tree1->capacity, tree2->capacity);             \
        M_SWAP(m_tr33_index_t, tree1->root_index, tree2->root_index);         \
        M_SWAP(m_tr33_index_t, tree1->free_index, tree2->free_index);         \
        M_SWAP(unsigned, tree1->allow_realloc, tree2->allow_realloc);         \
        M_SWAP(M_F(name, _node_ct) *, tree1->tab, tree2->tab);                \
        M_TR33_CONTRACT(tree1);                                               \
        M_TR33_CONTRACT(tree2);                                               \
    }                                                                         \
                                                                              \
    M_INLINE size_t                                                           \
    M_F(name, _size)(const tree_t tree) {                                     \
        M_TR33_CONTRACT(tree);                                                \
        return (size_t) tree->size;                                           \
    }                                                                         \
                                                                              \
    M_INLINE bool                                                             \
    M_F(name, _empty_p)(const tree_t tree) {                                  \
        M_TR33_CONTRACT(tree);                                                \
        return tree->size == 0;                                               \
    }                                                                         \
                                                                              \
    M_INLINE size_t                                                           \
    M_F(name, _capacity)(const tree_t tree) {                                 \
        M_TR33_CONTRACT(tree);                                                \
        return (size_t) tree->capacity;                                       \
    }                                                                         \
                                                                              \
    /* Service not really usefull as the affectation operator works with it */\
    M_INLINE void                                                             \
    M_F(name, _it_set)(it_t *dst, it_t src ){                                 \
        *dst = src;                                                           \
    }                                                                         \
                                                                              \
    M_IF_METHOD(EQUAL, oplist)(                                               \
    M_INLINE bool                                                             \
    M_F(name, _equal_p)(/*const*/ tree_t t1, /*const*/ tree_t t2) {           \
        M_TR33_CONTRACT(t1);                                                  \
        M_TR33_CONTRACT(t2);                                                  \
        /* Fast case if the sizes don't match */                              \
        if (M_LIKELY(t1->size != t2->size)) {                                 \
            return false;                                                     \
        }                                                                     \
        /* Slow case. We need to scan both tree                               \
           and check if we move in the same way                               \
           while checking also the data                                       \
           */                                                                 \
        it_t it1 = M_F(name, _it)(t1);                                        \
        it_t it2 = M_F(name, _it)(t2);                                        \
        while (!M_F(name, _end_p)(it1)) {                                     \
            /* Since both trees have the same size,                           \
               both iterators shall end at the same time. */                  \
            M_ASSERT(!M_F(name, _end_p)(it2));                                \
            bool b = M_CALL_EQUAL(oplist, *M_F(name, _cref)(it1), *M_F(name, _cref)(it2)); \
            if (!b) return false;                                             \
            /* First go down, if impossible go right */                       \
            if (M_F(name, _it_down)(&it1) ) {                                 \
                b = M_F(name, _it_down)(&it2);                                \
                if (!b) return false;                                         \
                continue;                                                     \
            }                                                                 \
            if (M_F(name, _it_right)(&it1)) {                                 \
                b = M_F(name, _it_right)(&it2);                               \
                if (!b) return false;                                         \
                continue;                                                     \
            }                                                                 \
            /* If impossible, move up and then right until impossible */      \
            while (M_F(name, _it_up)(&it1)) {                                 \
                /* Both iterators have move down the same tree by the same    \
                   amount. Therefore if we can move up one iterator, we can   \
                   move the other one up too*/                                \
                b = M_F(name, _it_up)(&it2);                                  \
                M_ASSERT (b);                                                 \
                if (M_F(name, _it_right)(&it1)) {                             \
                    /* it2 right child may not exist */                       \
                    b = M_F(name, _it_right)(&it2);                           \
                    if (!b) return false;                                     \
                    goto do_continue;                                         \
                }                                                             \
            }                                                                 \
            /* Both tree have the same size and the same "local" depth        \
               Since there is no longer any node up iterator it1,             \
               there shall not be any node for iterator it2 (same size        \
               same depth)                                                    \
             */                                                               \
            M_ASSERT( M_F(name, _it_up)(&it2) == false);                      \
            return true;                                                      \
            /* Reach end of tree */                                           \
            do_continue:                                                      \
            continue;                                                         \
        }                                                                     \
        M_ASSERT(M_F(name, _end_p)(it2));                                     \
        return true;                                                          \
    }                                                                         \
    , /* No EQUAL */ )                                                        \
                                                                              \
    M_IF_METHOD(HASH, oplist)(                                                \
    M_INLINE size_t                                                           \
    M_F(name, _hash)(/* const */ tree_t t1) {                                 \
        M_HASH_DECL(hash);                                                    \
        for(it_t it = M_F(name, _it)(t1);                                     \
            !M_F(name, _end_p)(it) ;                                          \
            M_F(name, _next)(&it)) {                                          \
            size_t h = M_CALL_HASH(oplist, *M_F(name, _cref)(it));            \
            M_HASH_UP(hash, h);                                               \
        }                                                                     \
        return M_HASH_FINAL(hash);                                            \
    }                                                                         \
    , /* No HASH */ )                                                         \
    

/* Define the IO methods of a tree */
#define M_TR33_DEF_P4_IO(name, type, oplist, tree_t, it_t)                    \
M_IF_METHOD(GET_STR, oplist)(                                                 \
M_INLINE void                                                                 \
M_F(name, _get_str)(string_t str, /*const*/ tree_t tree, bool append) {       \
    (append ? m_string_cat_cstr : m_string_set_cstr) (str, "[");              \
    it_t it = M_F(name, _it)(tree);                                           \
    while (!M_F(name, _end_p)(it)) {                                          \
        m_string_push_back (str, '{');                                        \
        type const *item = M_F(name, _cref)(it);                              \
        M_CALL_GET_STR(oplist, str, *item, true);                             \
        /* Go down the tree */                                                \
        if (M_F(name, _it_down)(&it)) {                                       \
            m_string_push_back (str, M_GET_SEPARATOR oplist);                 \
            m_string_push_back (str, '[');                                    \
            continue;                                                         \
        }                                                                     \
            m_string_push_back (str, '}');                                    \
        if (M_F(name, _it_right)(&it)) {                                      \
            m_string_push_back (str, M_GET_SEPARATOR oplist);                 \
            continue;                                                         \
        }                                                                     \
        while (M_F(name, _it_up)(&it)) {                                      \
            m_string_push_back (str, ']');                                    \
            m_string_push_back (str, '}');                                    \
            if (M_F(name, _it_right)(&it)) {                                  \
                m_string_push_back (str, M_GET_SEPARATOR oplist);             \
                goto continue_tree;                                           \
            }                                                                 \
        }                                                                     \
        it = M_F(name, _it_end)(tree);                                        \
        continue_tree:                                                        \
        (void) 0;                                                             \
    }                                                                         \
    m_string_push_back (str, ']');                                            \
}                                                                             \
, /* No GET_STR */ )                                                          \
                                                                              \
M_IF_METHOD(PARSE_STR, oplist)(                                               \
M_INLINE bool                                                                 \
M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) {     \
    M_TR33_CONTRACT(tree);                                                    \
    int cmd = 0;                                                              \
    type item;                                                                \
    it_t it;                                                                  \
    M_F(name, _reset)(tree);                                                  \
    bool success = false;                                                     \
    int c = *str;                                                             \
    if (M_UNLIKELY (c != '[')) goto exit;                                     \
    c = *++str;                                                               \
    if (M_UNLIKELY (c == ']')) { success = true; str++; goto exit; }          \
    if (M_UNLIKELY (c == 0)) goto exit;                                       \
    M_CALL_INIT(oplist, item);                                                \
    it = M_F(name, _it_end)(tree);                                            \
    while (true) {                                                            \
        c = *str++;                                                           \
        if (c != '{') goto exit_clear;                                        \
        bool b = M_CALL_PARSE_STR(oplist, item, str, &str);                   \
        c = *str++;                                                           \
        if (b == false || c == 0) { goto exit_clear; }                        \
        /* Insert the item as the root or as a right sibling or as a child */ \
        switch (cmd) {                                                        \
            case 0: it = M_F(name, _set_root)(tree, item); break;             \
            case 1: it = M_F(name, _insert_right)(it, item); break;           \
            case 2: it = M_F(name, _insert_child)(it, item); break;           \
            default: M_ASSERT(0);                                             \
        }                                                                     \
        if (c == ',') {                                                       \
            /* The current item has some children */                          \
            c = *str++;                                                       \
            if (c != '[') { goto exit_clear; }                                \
            /* next is a child: push_down */                                  \
            cmd = 2;                                                          \
            continue;                                                         \
        }                                                                     \
        /* The current item has no children. */                               \
        if (c != '}') { goto exit_clear; }                                    \
        /* Scan the next character to decide where to move (right or up) */   \
        c = *str++;                                                           \
        if (c == ']') {                                                       \
            do {                                                              \
                /* move up. It we cannot, we have reached the end */          \
                if (!M_F(name, _it_up)(&it)) { goto exit_success; }           \
                c = *str++;                                                   \
                if (c != '}') { goto exit_clear; }                            \
                c = *str++;                                                   \
            } while (c == ']');                                               \
        }                                                                     \
        if (c != ',') { goto exit_clear; }                                    \
        /* next is a sibling: push_right */                                   \
        cmd = 1;                                                              \
    }                                                                         \
exit_success:                                                                 \
    success = true;                                                           \
exit_clear:                                                                   \
    M_CALL_CLEAR(oplist, item);                                               \
exit:                                                                         \
    if (endp) *endp = str;                                                    \
    M_TR33_CONTRACT(tree);                                                    \
    return success;                                                           \
}                                                                             \
, /* No PARSE_STR */ )                                                        \
                                                                              \
M_IF_METHOD(OUT_STR, oplist)(                                                 \
M_INLINE void                                                                 \
M_F(name, _out_str)(FILE *f, /*const*/ tree_t tree) {                         \
    fputc('[', f);                                                            \
    it_t it = M_F(name, _it)(tree);                                           \
    while (!M_F(name, _end_p)(it)) {                                          \
        fputc('{', f);                                                        \
        type const *item = M_F(name, _cref)(it);                              \
        M_CALL_OUT_STR(oplist, f, *item);                                     \
        /* Go down the tree */                                                \
        if (M_F(name, _it_down)(&it)) {                                       \
            fputc (M_GET_SEPARATOR oplist, f);                                \
            fputc ('[', f);                                                   \
            continue;                                                         \
        }                                                                     \
            fputc ('}', f);                                                   \
        if (M_F(name, _it_right)(&it)) {                                      \
            fputc (M_GET_SEPARATOR oplist, f);                                \
            continue;                                                         \
        }                                                                     \
        while (M_F(name, _it_up)(&it)) {                                      \
            fputc (']', f);                                                   \
            fputc ('}', f);                                                   \
            if (M_F(name, _it_right)(&it)) {                                  \
                fputc (M_GET_SEPARATOR oplist, f);                            \
                goto continue_tree;                                           \
            }                                                                 \
        }                                                                     \
        it = M_F(name, _it_end)(tree);                                        \
        continue_tree:                                                        \
        (void) 0;                                                             \
    }                                                                         \
    fputc (']', f);                                                           \
}                                                                             \
, /* No OUT_STR */ )                                                          \
                                                                              \
M_IF_METHOD(IN_STR, oplist)(                                                  \
M_INLINE bool                                                                 \
M_F(name, _in_str)(tree_t tree, FILE *f) {                                    \
    M_TR33_CONTRACT(tree);                                                    \
    int cmd = 0;                                                              \
    type item;                                                                \
    it_t it;                                                                  \
    M_F(name, _reset)(tree);                                                  \
    bool success = false;                                                     \
    int c = fgetc(f);                                                         \
    if (M_UNLIKELY (c != '[')) goto exit;                                     \
    c = fgetc(f);                                                             \
    if (M_UNLIKELY (c == ']')) { success = true; goto exit; }                 \
    ungetc(c, f);                                                             \
    if (M_UNLIKELY (c == 0)) goto exit;                                       \
    M_CALL_INIT(oplist, item);                                                \
    it = M_F(name, _it_end)(tree);                                            \
    while (true) {                                                            \
        c = fgetc(f);                                                         \
        if (c != '{') goto exit_clear;                                        \
        bool b = M_CALL_IN_STR(oplist, item, f);                              \
        c = fgetc(f);                                                         \
        if (b == false || c == 0) { goto exit_clear; }                        \
        /* Insert the item as the root or as a right sibling or as a child */ \
        switch (cmd) {                                                        \
            case 0: it = M_F(name, _set_root)(tree, item); break;             \
            case 1: it = M_F(name, _insert_right)(it, item); break;           \
            case 2: it = M_F(name, _insert_child)(it, item); break;           \
            default: M_ASSERT(0);                                             \
        }                                                                     \
        if (c == ',') {                                                       \
            /* The current item has some children */                          \
            c = fgetc(f);                                                     \
            if (c != '[') { goto exit_clear; }                                \
            /* next is a child: push_down */                                  \
            cmd = 2;                                                          \
            continue;                                                         \
        }                                                                     \
        /* The current item has no children. */                               \
        if (c != '}') { goto exit_clear; }                                    \
        /* Scan the next character to decide where to move (right or up) */   \
        c = fgetc(f);                                                         \
        if (c == ']') {                                                       \
            do {                                                              \
                /* move up. It we cannot, we have reached the end */          \
                if (!M_F(name, _it_up)(&it)) { goto exit_success; }           \
                c = fgetc(f);                                                 \
                if (c != '}') { goto exit_clear; }                            \
                c = fgetc(f);                                                 \
            } while (c == ']');                                               \
        }                                                                     \
        if (c != ',') { goto exit_clear; }                                    \
        /* next is a sibling: push_right */                                   \
        cmd = 1;                                                              \
    }                                                                         \
exit_success:                                                                 \
    success = true;                                                           \
exit_clear:                                                                   \
    M_CALL_CLEAR(oplist, item);                                               \
exit:                                                                         \
    M_TR33_CONTRACT(tree);                                                    \
    return success;                                                           \
}                                                                             \
, /* No IN_STR */ )                                                           \

/* Define the emplace methods of a tree */
#define M_TR33_DEF_P4_EMPLACE(name, type, oplist, tree_t, it_t)               \
  M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace_root), oplist, M_TR33_EMPLACE_ROOT_DEF) \
  M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_up), oplist, M_TR33_EMPLACE_UP_DEF) \
  M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_down), oplist, M_TR33_EMPLACE_DOWN_DEF) \
  M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_child), oplist, M_TR33_EMPLACE_CHILD_DEF) \
  M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_left), oplist, M_TR33_EMPLACE_LEFT_DEF) \
  M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_right), oplist, M_TR33_EMPLACE_RIGHT_DEF)

/* Definition of the emplace_back functions */
#define M_TR33_EMPLACE_ROOT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
  M_INLINE M_F(name, _it_ct)                                                  \
    function_name(name_t tree                                                 \
                  M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) )              \
    {                                                                         \
        M_TR33_CONTRACT(tree);                                                \
        M_F(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_EMPLACE_CALL_FUNC(a, init_func, oplist, tree->tab[i].data,          \
                        exp_emplace_type);                                    \
        M_F(name, _it_ct) it;                                                 \
        it.tree = tree;                                                       \
        it.index = tree->root_index;                                          \
        M_TR33_CONTRACT(tree);                                                \
        return it;                                                            \
    }

#define M_TR33_EMPLACE_UP_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
  M_INLINE name_t                                                             \
  function_name(name_t pos                                                    \
                M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) )                \
  {                                                                           \
    name_t it = M_F(name, _insert_up_raw)(pos);                               \
    M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data,    \
                        exp_emplace_type);                                    \
    return it;                                                                \
  }

#define M_TR33_EMPLACE_DOWN_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
  M_INLINE name_t                                                             \
  function_name(name_t pos                                                    \
                M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) )                \
  {                                                                           \
    name_t it = M_F(name, _insert_down_raw)(pos);                             \
    M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data,    \
                        exp_emplace_type);                                    \
    return it;                                                                \
  }

#define M_TR33_EMPLACE_CHILD_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
  M_INLINE name_t                                                             \
  function_name(name_t pos                                                    \
                M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) )                \
  {                                                                           \
    name_t it = M_F(name, _insert_child_raw)(pos);                            \
    M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data,    \
                        exp_emplace_type);                                    \
    return it;                                                                \
  }

#define M_TR33_EMPLACE_LEFT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
  M_INLINE name_t                                                             \
  function_name(name_t pos                                                    \
                M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) )                \
  {                                                                           \
    name_t it = M_F(name, _insert_left_raw)(pos);                             \
    M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data,    \
                        exp_emplace_type);                                    \
    return it;                                                                \
  }

#define M_TR33_EMPLACE_RIGHT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
  M_INLINE name_t                                                             \
  function_name(name_t pos                                                    \
                M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) )                \
  {                                                                           \
    name_t it = M_F(name, _insert_right_raw)(pos);                            \
    M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data,    \
                        exp_emplace_type);                                    \
    return it;                                                                \
  }

// TODO: 
// * serialization
// * OPLIST ?
// * _previous ?

/********************************** INTERNAL *********************************/

#if M_USE_SMALL_NAME
#define TREE_DEF M_TREE_DEF
#define TREE_DEF_AS M_TREE_DEF_AS
#define TREE_OPLIST M_TREE_OPLIST
#endif

#endif
