#include "cx/tree.h"
#include "cx/array_list.h"
#include <assert.h>
#define CX_TREE_PTR(cur, off) (*(
void**)(((
char*)(cur))+(off)))
#define tree_parent(node)
CX_TREE_PTR(node, loc_parent)
#define tree_children(node)
CX_TREE_PTR(node, loc_children)
#define tree_last_child(node)
CX_TREE_PTR(node, loc_last_child)
#define tree_prev(node)
CX_TREE_PTR(node, loc_prev)
#define tree_next(node)
CX_TREE_PTR(node, loc_next)
#define cx_tree_ptr_locations \
loc_parent, loc_children, loc_last_child, loc_prev, loc_next
#define cx_tree_node_layout(tree) \
(tree)->loc_parent,\
(tree)->loc_children,\
(tree)->loc_last_child,\
(tree)->loc_prev, \
(tree)->loc_next
static void cx_tree_zero_pointers(
void *node,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
tree_parent(node) =
NULL;
if (loc_prev >=
0) {
tree_prev(node) =
NULL;
}
tree_next(node) =
NULL;
tree_children(node) =
NULL;
if (loc_last_child >=
0) {
tree_last_child(node) =
NULL;
}
}
void cx_tree_link(
void *parent,
void *node,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
assert(loc_parent >=
0);
assert(loc_children >=
0);
assert(loc_next >=
0);
void *current_parent = tree_parent(node);
if (current_parent == parent)
return;
if (current_parent !=
NULL) {
cx_tree_unlink(node, cx_tree_ptr_locations);
}
if (tree_children(parent) ==
NULL) {
tree_children(parent) = node;
if (loc_last_child >=
0) {
tree_last_child(parent) = node;
}
}
else {
void *child;
if (loc_last_child >=
0) {
child = tree_last_child(parent);
tree_last_child(parent) = node;
}
else {
child = tree_children(parent);
void *next;
while ((next = tree_next(child)) !=
NULL) {
child = next;
}
}
if (loc_prev >=
0) {
tree_prev(node) = child;
}
tree_next(child) = node;
}
tree_parent(node) = parent;
}
static void *cx_tree_node_prev(
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_next,
const void *node
) {
void *parent = tree_parent(node);
void *begin = tree_children(parent);
if (begin == node)
return NULL;
const void *cur = begin;
const void *next;
while (
1) {
next = tree_next(cur);
if (next == node)
return (
void *) cur;
cur = next;
}
}
void cx_tree_unlink(
void *node,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
if (tree_parent(node) ==
NULL)
return;
assert(loc_children >=
0);
assert(loc_next >=
0);
assert(loc_parent >=
0);
void *left;
if (loc_prev >=
0) {
left = tree_prev(node);
}
else {
left = cx_tree_node_prev(loc_parent, loc_children, loc_next, node);
}
void *right = tree_next(node);
void *parent = tree_parent(node);
assert(left ==
NULL || tree_children(parent) != node);
assert(right ==
NULL || loc_last_child <
0 ||
tree_last_child(parent) != node);
if (left ==
NULL) {
tree_children(parent) = right;
}
else {
tree_next(left) = right;
}
if (right ==
NULL) {
if (loc_last_child >=
0) {
tree_last_child(parent) = left;
}
}
else {
if (loc_prev >=
0) {
tree_prev(right) = left;
}
}
tree_parent(node) =
NULL;
tree_next(node) =
NULL;
if (loc_prev >=
0) {
tree_prev(node) =
NULL;
}
}
int cx_tree_search(
const void *root,
size_t depth,
const void *node,
cx_tree_search_func sfunc,
void **result,
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
assert(result !=
NULL);
*result =
NULL;
int ret = sfunc(root, node);
if (ret <
0) {
return -1;
}
*result = (
void*) root;
if (ret ==
0) {
return 0;
}
if (depth ==
1) {
return ret;
}
if (depth ==
0) {
depth =
SIZE_MAX;
}
CxTreeIterator iter = cx_tree_iterator(
(
void*) root, false, loc_children, loc_next
);
cxIteratorNext(iter);
cx_foreach(
void *, elem, iter) {
int ret_elem = sfunc(elem, node);
if (ret_elem ==
0) {
*result = elem;
ret =
0;
break;
}
else if (ret_elem >
0 && ret_elem < ret) {
*result = elem;
ret = ret_elem;
}
else if (ret_elem <
0 || ret_elem > ret) {
cxTreeIteratorContinue(iter);
}
if (iter.depth == depth) {
cxTreeIteratorContinue(iter);
}
}
cxTreeIteratorDispose(&iter);
assert(ret <
0 || *result !=
NULL);
return ret;
}
int cx_tree_search_data(
const void *root,
size_t depth,
const void *data,
cx_tree_search_data_func sfunc,
void **result,
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
return cx_tree_search(
root, depth, data,
(cx_tree_search_func) sfunc,
result,
loc_children, loc_next);
}
static bool cx_tree_iter_valid(
const void *it) {
const struct cx_tree_iterator_s *iter = it;
return iter->node !=
NULL;
}
static void *cx_tree_iter_current(
const void *it) {
const struct cx_tree_iterator_s *iter = it;
return iter->node;
}
static void cx_tree_iter_next(
void *it) {
struct cx_tree_iterator_s *iter = it;
ptrdiff_t const loc_next = iter->loc_next;
ptrdiff_t const loc_children = iter->loc_children;
if (!iter->base.valid(iter))
return;
void *children;
if (iter->exiting) {
children =
NULL;
iter->skip = false;
}
else {
if (iter->skip) {
iter->skip = false;
children =
NULL;
}
else {
children = tree_children(iter->node);
}
}
if (children ==
NULL) {
void *next =
NULL;
cx_tree_iter_search_next:
if (iter->exiting) {
next = iter->node_next;
}
else if (iter->depth >
1) {
next = tree_next(iter->node);
iter->node_next = next;
}
if (next ==
NULL) {
if (iter->visit_on_exit && !iter->exiting) {
iter->exiting = true;
}
else {
iter->exiting = false;
if (iter->depth ==
1) {
iter->node = iter->node_next =
NULL;
iter->stack_capacity = iter->depth =
0;
cxFreeDefault(iter->stack);
iter->stack =
NULL;
}
else {
iter->depth--;
iter->node = iter->stack[iter->depth -
1];
goto cx_tree_iter_search_next;
}
}
}
else {
if (iter->visit_on_exit && !iter->exiting) {
iter->exiting = true;
}
else {
iter->exiting = false;
iter->counter++;
iter->node = next;
iter->stack[iter->depth -
1] = next;
}
}
}
else {
cx_array_simple_add(iter->stack, children);
iter->node = children;
iter->counter++;
}
}
CxTreeIterator cx_tree_iterator(
void *root,
bool visit_on_exit,
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
CxTreeIterator iter;
iter.loc_children = loc_children;
iter.loc_next = loc_next;
iter.visit_on_exit = visit_on_exit;
iter.node_next =
NULL;
iter.exiting = false;
iter.skip = false;
iter.base.allow_remove = false;
iter.base.remove = false;
iter.base.current_impl =
NULL;
iter.base.valid = cx_tree_iter_valid;
iter.base.next = cx_tree_iter_next;
iter.base.current = cx_tree_iter_current;
iter.node = root;
if (root !=
NULL) {
iter.stack_capacity =
16;
iter.stack = cxMallocDefault(
sizeof(
void *) *
16);
iter.stack[
0] = root;
iter.counter =
1;
iter.depth =
1;
}
else {
iter.stack_capacity =
0;
iter.stack =
NULL;
iter.counter =
0;
iter.depth =
0;
}
return iter;
}
static bool cx_tree_visitor_valid(
const void *it) {
const struct cx_tree_visitor_s *iter = it;
return iter->node !=
NULL;
}
static void *cx_tree_visitor_current(
const void *it) {
const struct cx_tree_visitor_s *iter = it;
return iter->node;
}
cx_attr_nonnull
static void cx_tree_visitor_enqueue_siblings(
struct cx_tree_visitor_s *iter,
void *node,
ptrdiff_t loc_next) {
node = tree_next(node);
while (node !=
NULL) {
struct cx_tree_visitor_queue_s *q;
q = cxMallocDefault(
sizeof(
struct cx_tree_visitor_queue_s));
q->depth = iter->queue_last->depth;
q->node = node;
iter->queue_last->next = q;
iter->queue_last = q;
node = tree_next(node);
}
iter->queue_last->next =
NULL;
}
static void cx_tree_visitor_next(
void *it) {
struct cx_tree_visitor_s *iter = it;
if (!iter->base.valid(iter))
return;
ptrdiff_t const loc_next = iter->loc_next;
ptrdiff_t const loc_children = iter->loc_children;
void *children;
if (iter->skip) {
iter->skip = false;
children =
NULL;
}
else {
children = tree_children(iter->node);
}
if (children !=
NULL) {
struct cx_tree_visitor_queue_s *q;
q = cxMallocDefault(
sizeof(
struct cx_tree_visitor_queue_s));
q->depth = iter->depth +
1;
q->node = children;
if (iter->queue_last ==
NULL) {
assert(iter->queue_next ==
NULL);
iter->queue_next = q;
}
else {
iter->queue_last->next = q;
}
iter->queue_last = q;
cx_tree_visitor_enqueue_siblings(iter, children, loc_next);
}
if (iter->queue_next ==
NULL) {
iter->node =
NULL;
return;
}
iter->node = iter->queue_next->node;
iter->depth = iter->queue_next->depth;
{
struct cx_tree_visitor_queue_s *q = iter->queue_next;
iter->queue_next = q->next;
if (iter->queue_next ==
NULL) {
assert(iter->queue_last == q);
iter->queue_last =
NULL;
}
cxFreeDefault(q);
}
iter->counter++;
}
CxTreeVisitor cx_tree_visitor(
void *root,
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
CxTreeVisitor iter;
iter.loc_children = loc_children;
iter.loc_next = loc_next;
iter.skip = false;
iter.queue_next =
NULL;
iter.queue_last =
NULL;
iter.base.allow_remove = false;
iter.base.remove = false;
iter.base.current_impl =
NULL;
iter.base.valid = cx_tree_visitor_valid;
iter.base.next = cx_tree_visitor_next;
iter.base.current = cx_tree_visitor_current;
iter.node = root;
if (root !=
NULL) {
iter.counter =
1;
iter.depth =
1;
}
else {
iter.counter =
0;
iter.depth =
0;
}
return iter;
}
static void cx_tree_add_link_duplicate(
void *original,
void *duplicate,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
void *shared_parent = tree_parent(original);
if (shared_parent ==
NULL) {
cx_tree_link(original, duplicate, cx_tree_ptr_locations);
}
else {
cx_tree_link(shared_parent, duplicate, cx_tree_ptr_locations);
}
}
static void cx_tree_add_link_new(
void *parent,
void *node, cx_tree_search_func sfunc,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
void *child = tree_children(parent);
while (child !=
NULL) {
void *next = tree_next(child);
if (sfunc(node, child) >
0) {
cx_tree_link(node, child, cx_tree_ptr_locations);
}
child = next;
}
cx_tree_link(parent, node, cx_tree_ptr_locations);
}
int cx_tree_add(
const void *src,
cx_tree_search_func sfunc,
cx_tree_node_create_func cfunc,
void *cdata,
void **cnode,
void *root,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
*cnode = cfunc(src, cdata);
if (*cnode ==
NULL)
return 1;
cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations);
void *match =
NULL;
int result = cx_tree_search(
root,
0,
*cnode,
sfunc,
&match,
loc_children,
loc_next
);
if (result <
0) {
return 1;
}
else if (result ==
0) {
cx_tree_add_link_duplicate(match, *cnode, cx_tree_ptr_locations);
}
else {
cx_tree_add_link_new(match, *cnode, sfunc, cx_tree_ptr_locations);
}
return 0;
}
unsigned int cx_tree_add_look_around_depth =
3;
size_t cx_tree_add_iter(
struct cx_iterator_base_s *iter,
size_t num,
cx_tree_search_func sfunc,
cx_tree_node_create_func cfunc,
void *cdata,
void **failed,
void *root,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
*failed =
NULL;
if (!iter->valid(iter))
return 0;
size_t processed =
0;
void *current_node = root;
const void *elem;
for (
void **eptr; processed < num &&
iter->valid(iter) && (eptr = iter->current(iter)) !=
NULL;
iter->next(iter)) {
elem = *eptr;
void *new_node = cfunc(elem, cdata);
if (new_node ==
NULL)
return processed;
cx_tree_zero_pointers(new_node, cx_tree_ptr_locations);
void *match;
int result;
unsigned int look_around_retries = cx_tree_add_look_around_depth;
cx_tree_add_look_around_retry:
result = cx_tree_search(
current_node,
0,
new_node,
sfunc,
&match,
loc_children,
loc_next
);
if (result <
0) {
void *parent = tree_parent(current_node);
if (parent !=
NULL) {
if (look_around_retries >
0) {
look_around_retries--;
current_node = parent;
}
else {
current_node = root;
}
goto cx_tree_add_look_around_retry;
}
else {
*failed = new_node;
return processed;
}
}
else if (result ==
0) {
cx_tree_add_link_duplicate(match, new_node, cx_tree_ptr_locations);
current_node = match;
}
else {
cx_tree_add_link_new(match, new_node, sfunc,
cx_tree_ptr_locations);
current_node = match;
}
processed++;
}
return processed;
}
size_t cx_tree_add_array(
const void *src,
size_t num,
size_t elem_size,
cx_tree_search_func sfunc,
cx_tree_node_create_func cfunc,
void *cdata,
void **failed,
void *root,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
*failed =
NULL;
if (num ==
0) {
return 0;
}
if (num ==
1) {
void *node;
if (
0 == cx_tree_add(
src, sfunc, cfunc, cdata, &node, root,
loc_parent, loc_children, loc_last_child,
loc_prev, loc_next)) {
return 1;
}
else {
*failed = node;
return 0;
}
}
CxIterator iter = cxIterator(src, elem_size, num, false);
return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
cfunc, cdata, failed, root,
loc_parent, loc_children, loc_last_child,
loc_prev, loc_next);
}
static int cx_tree_default_insert_element(
CxTree *tree,
const void *data
) {
void *node;
if (tree->root ==
NULL) {
node = tree->node_create(data, tree);
if (node ==
NULL)
return 1;
cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
tree->root = node;
tree->collection.size =
1;
return 0;
}
int result = cx_tree_add(data, tree->search, tree->node_create,
tree, &node, tree->root, cx_tree_node_layout(tree));
if (
0 == result) {
tree->collection.size++;
}
else {
cxFree(tree->collection.allocator, node);
}
return result;
}
static size_t cx_tree_default_insert_many(
CxTree *tree,
CxIteratorBase *iter,
size_t n
) {
size_t ins =
0;
if (!iter->valid(iter))
return 0;
if (tree->root ==
NULL) {
void **eptr = iter->current(iter);
void *node = tree->node_create(*eptr, tree);
if (node ==
NULL)
return 0;
cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
tree->root = node;
ins =
1;
iter->next(iter);
}
void *failed;
ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create,
tree, &failed, tree->root, cx_tree_node_layout(tree));
tree->collection.size += ins;
if (ins < n) {
cxFree(tree->collection.allocator, failed);
}
return ins;
}
static void *cx_tree_default_find(
CxTree *tree,
const void *subtree,
const void *data,
size_t depth
) {
if (tree->root ==
NULL)
return NULL;
void *found;
if (
0 == cx_tree_search_data(
subtree,
depth,
data,
tree->search_data,
&found,
tree->loc_children,
tree->loc_next
)) {
return found;
}
else {
return NULL;
}
}
static cx_tree_class cx_tree_default_class = {
cx_tree_default_insert_element,
cx_tree_default_insert_many,
cx_tree_default_find
};
CxTree *cxTreeCreate(
const CxAllocator *allocator,
cx_tree_node_create_func create_func,
cx_tree_search_func search_func,
cx_tree_search_data_func search_data_func,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
if (allocator ==
NULL) {
allocator = cxDefaultAllocator;
}
assert(create_func !=
NULL);
assert(search_func !=
NULL);
assert(search_data_func !=
NULL);
CxTree *tree = cxZalloc(allocator,
sizeof(CxTree));
if (tree ==
NULL)
return NULL;
tree->cl = &cx_tree_default_class;
tree->collection.allocator = allocator;
tree->node_create = create_func;
tree->search = search_func;
tree->search_data = search_data_func;
tree->collection.advanced_destructor = (cx_destructor_func2) cxFree;
tree->collection.destructor_data = (
void *) allocator;
tree->loc_parent = loc_parent;
tree->loc_children = loc_children;
tree->loc_last_child = loc_last_child;
tree->loc_prev = loc_prev;
tree->loc_next = loc_next;
return tree;
}
void cxTreeFree(CxTree *tree) {
if (tree ==
NULL)
return;
if (tree->root !=
NULL) {
cxTreeClear(tree);
}
cxFree(tree->collection.allocator, tree);
}
CxTree *cxTreeCreateWrapped(
const CxAllocator *allocator,
void *root,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_last_child,
ptrdiff_t loc_prev,
ptrdiff_t loc_next) {
if (allocator ==
NULL) {
allocator = cxDefaultAllocator;
}
assert(root !=
NULL);
CxTree *tree = cxZalloc(allocator,
sizeof(CxTree));
if (tree ==
NULL)
return NULL;
tree->cl = &cx_tree_default_class;
tree->collection.allocator = allocator;
tree->loc_parent = loc_parent;
tree->loc_children = loc_children;
tree->loc_last_child = loc_last_child;
tree->loc_prev = loc_prev;
tree->loc_next = loc_next;
tree->root = root;
tree->collection.size = cxTreeSubtreeSize(tree, root);
return tree;
}
void cxTreeSetParent(CxTree *tree,
void *parent,
void *child) {
size_t loc_parent = tree->loc_parent;
if (tree_parent(child) ==
NULL) {
tree->collection.size++;
}
cx_tree_link(parent, child, cx_tree_node_layout(tree));
}
void cxTreeAddChildNode(CxTree *tree,
void *parent,
void *child) {
cx_tree_link(parent, child, cx_tree_node_layout(tree));
tree->collection.size++;
}
int cxTreeAddChild(CxTree *tree,
void *parent,
const void *data) {
void *node = tree->node_create(data, tree);
if (node ==
NULL)
return 1;
cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
cx_tree_link(parent, node, cx_tree_node_layout(tree));
tree->collection.size++;
return 0;
}
int cxTreeInsert(CxTree *tree,
const void *data) {
return tree->cl->insert_element(tree, data);
}
size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter,
size_t n) {
return tree->cl->insert_many(tree, iter, n);
}
size_t cxTreeInsertArray(CxTree *tree,
const void *data,
size_t elem_size,
size_t n) {
if (n ==
0)
return 0;
if (n ==
1)
return 0 == cxTreeInsert(tree, data) ?
1 :
0;
CxIterator iter = cxIterator(data, elem_size, n, false);
return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
}
void *cxTreeFind( CxTree *tree,
const void *data) {
return tree->cl->find(tree, tree->root, data,
0);
}
void *cxTreeFindInSubtree(CxTree *tree,
const void *data,
void *subtree_root,
size_t max_depth) {
return tree->cl->find(tree, subtree_root, data, max_depth);
}
size_t cxTreeSubtreeSize(CxTree *tree,
void *subtree_root) {
CxTreeVisitor visitor = cx_tree_visitor(
subtree_root,
tree->loc_children,
tree->loc_next
);
while (cxIteratorValid(visitor)) {
cxIteratorNext(visitor);
}
return visitor.counter;
}
size_t cxTreeSubtreeDepth(CxTree *tree,
void *subtree_root) {
CxTreeVisitor visitor = cx_tree_visitor(
subtree_root,
tree->loc_children,
tree->loc_next
);
while (cxIteratorValid(visitor)) {
cxIteratorNext(visitor);
}
return visitor.depth;
}
size_t cxTreeSize(CxTree *tree) {
return tree->collection.size;
}
size_t cxTreeDepth(CxTree *tree) {
CxTreeVisitor visitor = cx_tree_visitor(
tree->root, tree->loc_children, tree->loc_next
);
while (cxIteratorValid(visitor)) {
cxIteratorNext(visitor);
}
return visitor.depth;
}
int cxTreeRemoveNode(
CxTree *tree,
void *node,
cx_tree_relink_func relink_func
) {
if (node == tree->root)
return 1;
ptrdiff_t loc_parent = tree->loc_parent;
void *new_parent = tree_parent(node);
cx_tree_unlink(node, cx_tree_node_layout(tree));
ptrdiff_t loc_children = tree->loc_children;
ptrdiff_t loc_next = tree->loc_next;
void *child = tree_children(node);
while (child !=
NULL) {
tree_parent(child) =
NULL;
if (relink_func !=
NULL) {
relink_func(child, node, new_parent);
}
cx_tree_link(new_parent, child, cx_tree_node_layout(tree));
child = tree_next(child);
}
tree_children(node) =
NULL;
ptrdiff_t loc_last_child = tree->loc_last_child;
if (loc_last_child >=
0) tree_last_child(node) =
NULL;
tree->collection.size--;
return 0;
}
void cxTreeRemoveSubtree(CxTree *tree,
void *node) {
if (node == tree->root) {
tree->root =
NULL;
tree->collection.size =
0;
return;
}
size_t subtree_size = cxTreeSubtreeSize(tree, node);
cx_tree_unlink(node, cx_tree_node_layout(tree));
tree->collection.size -= subtree_size;
}
int cxTreeDestroyNode(
CxTree *tree,
void *node,
cx_tree_relink_func relink_func
) {
int result = cxTreeRemoveNode(tree, node, relink_func);
if (result ==
0) {
cx_invoke_destructor(tree, node);
return 0;
}
else {
return result;
}
}
void cxTreeDestroySubtree(CxTree *tree,
void *node) {
cx_tree_unlink(node, cx_tree_node_layout(tree));
CxTreeIterator iter = cx_tree_iterator(
node, true,
tree->loc_children, tree->loc_next
);
cx_foreach(
void *, child, iter) {
if (iter.exiting) {
cx_invoke_destructor(tree, child);
}
}
tree->collection.size -= iter.counter;
if (node == tree->root) {
tree->root =
NULL;
}
}
void cxTreeIteratorDispose(CxTreeIterator *iter) {
cxFreeDefault(iter->stack);
iter->stack =
NULL;
}
void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
struct cx_tree_visitor_queue_s *q = visitor->queue_next;
while (q !=
NULL) {
struct cx_tree_visitor_queue_s *next = q->next;
cxFreeDefault(q);
q = next;
}
visitor->queue_next = visitor->queue_last =
NULL;
}
CxTreeIterator cxTreeIterateSubtree(CxTree *tree,
void *node, bool visit_on_exit) {
return cx_tree_iterator(
node, visit_on_exit,
tree->loc_children, tree->loc_next
);
}
CxTreeVisitor cxTreeVisitSubtree(CxTree *tree,
void *node) {
return cx_tree_visitor(
node, tree->loc_children, tree->loc_next
);
}
CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit) {
return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
}
CxTreeVisitor cxTreeVisit(CxTree *tree) {
return cxTreeVisitSubtree(tree, tree->root);
}