#include "cx/tree.h"
#include "cx/array_list.h"
#include <assert.h>
#define CX_TREE_PTR(cur, off) (*(
void**)(((
char*)(cur))+(off)))
#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_prev(node)
CX_TREE_PTR(node, loc_prev)
#define tree_next(node)
CX_TREE_PTR(node, loc_next)
void cx_tree_link(
void *restrict parent,
void *restrict node,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
void *current_parent = tree_parent(node);
if (current_parent == parent)
return;
if (current_parent !=
NULL) {
cx_tree_unlink(node, loc_parent, loc_children,
loc_prev, loc_next);
}
if (tree_children(parent) ==
NULL) {
tree_children(parent) = node;
}
else {
void *children = tree_children(parent);
tree_prev(children) = node;
tree_next(node) = children;
tree_children(parent) = node;
}
tree_parent(node) = parent;
}
void cx_tree_unlink(
void *node,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
ptrdiff_t loc_prev,
ptrdiff_t loc_next
) {
if (tree_parent(node) ==
NULL)
return;
void *left = tree_prev(node);
void *right = tree_next(node);
assert(left ==
NULL || tree_children(tree_parent(node)) != node);
if (left ==
NULL) {
tree_children(tree_parent(node)) = right;
}
else {
tree_next(left) = right;
}
if (right !=
NULL) tree_prev(right) = left;
tree_parent(node) =
NULL;
tree_prev(node) =
NULL;
tree_next(node) =
NULL;
}
int cx_tree_search(
void const *root,
void const *data,
cx_tree_search_func sfunc,
void **result,
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
int ret;
*result =
NULL;
ret = sfunc(root, data);
if (ret <
0) {
return ret;
}
else if (ret ==
0 || tree_children(root) ==
NULL) {
*result = (
void*)root;
return ret;
}
CX_ARRAY_DECLARE(
void const*, work);
cx_array_initialize(work,
32);
{
void *c = tree_children(root);
while (c !=
NULL) {
cx_array_simple_add(work, c);
c = tree_next(c);
}
}
void *candidate =
NULL;
int ret_candidate = -
1;
while (work_size >
0) {
void const *node = work[--work_size];
ret = sfunc(node, data);
if (ret ==
0) {
*result = (
void*) node;
work_size =
0;
break;
}
else if (ret >
0) {
void *c = tree_children(node);
while (c !=
NULL) {
cx_array_simple_add(work, c);
c = tree_next(c);
}
if (ret_candidate <
0 || ret < ret_candidate) {
candidate = (
void *) node;
ret_candidate = ret;
}
}
}
if (ret !=
0 && candidate !=
NULL) {
ret = ret_candidate;
*result = candidate;
}
free(work);
return ret;
}
static bool cx_tree_iter_valid(
void const *it) {
struct cx_tree_iterator_s
const *iter = it;
return iter->node !=
NULL;
}
static void *cx_tree_iter_current(
void const *it) {
struct cx_tree_iterator_s
const *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;
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;
cx_tree_iter_search_next:
if (iter->exiting) {
next = iter->node_next;
}
else {
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;
free(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.stack_capacity =
16;
iter.stack = malloc(
sizeof(
void *) *
16);
iter.depth =
0;
iter.node = root;
iter.node_next =
NULL;
iter.counter =
1;
iter.depth =
1;
iter.stack[
0] = root;
iter.exiting = false;
iter.skip = false;
iter.base.mutating = 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;
return iter;
}
static bool cx_tree_visitor_valid(
void const *it) {
struct cx_tree_visitor_s
const *iter = it;
return iter->node !=
NULL;
}
static void *cx_tree_visitor_current(
void const *it) {
struct cx_tree_visitor_s
const *iter = it;
return iter->node;
}
__attribute__((__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 = malloc(
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;
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 = malloc(
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;
}
free(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.depth =
0;
iter.node = root;
iter.counter =
1;
iter.depth =
1;
iter.skip = false;
iter.queue_next =
NULL;
iter.queue_last =
NULL;
iter.base.mutating = 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;
return iter;
}