mie: ir: walk: implement non-recursive traversal
struct mie_walker is now a public struct that can (and should) be stack allocated. this means that non-recursive traversal of an Op's children uses no dynamically allocated memory.
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
#include <stddef.h>
|
||||
|
||||
struct mie_op;
|
||||
struct mie_walker;
|
||||
|
||||
enum mie_walker_flags {
|
||||
MIE_WALKER_F_NONE = 0x00u,
|
||||
@@ -38,7 +37,7 @@ struct mie_walk_item {
|
||||
int _f;
|
||||
b_queue_entry _e;
|
||||
enum mie_walk_item_type i_type;
|
||||
size_t i_index;
|
||||
// size_t i_index;
|
||||
size_t i_depth;
|
||||
union {
|
||||
struct mie_op *i_op;
|
||||
@@ -47,8 +46,21 @@ struct mie_walk_item {
|
||||
};
|
||||
};
|
||||
|
||||
MIE_API struct mie_walker *mie_walker_begin(
|
||||
struct mie_op *op, enum mie_walker_flags flags);
|
||||
struct mie_walker {
|
||||
enum mie_walker_flags w_flags;
|
||||
union {
|
||||
/* used for recursive walks */
|
||||
b_queue w_stack;
|
||||
/* used for non-recursive walks */
|
||||
struct {
|
||||
struct mie_walk_item w_region, w_block, w_op;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
MIE_API void mie_walker_begin(
|
||||
struct mie_walker *walker, const struct mie_op *op,
|
||||
enum mie_walker_flags flags);
|
||||
MIE_API void mie_walker_end(struct mie_walker *walker);
|
||||
|
||||
MIE_API enum mie_status mie_walker_step(struct mie_walker *walker);
|
||||
|
||||
388
mie/ir/walk.c
388
mie/ir/walk.c
@@ -11,12 +11,6 @@
|
||||
|
||||
#define ITEM_TYPE(f) ((f) & 0x0Fu)
|
||||
|
||||
struct mie_walker {
|
||||
enum mie_walker_flags w_flags;
|
||||
struct mie_op *w_root;
|
||||
b_queue w_stack;
|
||||
};
|
||||
|
||||
static bool should_ignore_item(
|
||||
const struct mie_walker *walker, const struct mie_walk_item *item)
|
||||
{
|
||||
@@ -56,15 +50,31 @@ static void pop_walk_item(struct mie_walker *walker)
|
||||
|
||||
static struct mie_walk_item *current_item(struct mie_walker *walker)
|
||||
{
|
||||
struct mie_walk_item *item = NULL;
|
||||
bool recursive = (walker->w_flags & MIE_WALKER_F_RECURSIVE) != 0;
|
||||
if (!recursive) {
|
||||
if (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) {
|
||||
item = &walker->w_region;
|
||||
} else if (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) {
|
||||
item = &walker->w_block;
|
||||
} else {
|
||||
item = &walker->w_op;
|
||||
}
|
||||
|
||||
bool eof = !item || item->i_type != MIE_WALK_ITEM_NONE;
|
||||
return eof ? item : NULL;
|
||||
}
|
||||
|
||||
b_queue_entry *entry = b_queue_last(&walker->w_stack);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_walk_item *item = b_unbox(struct mie_walk_item, entry, _e);
|
||||
item = b_unbox(struct mie_walk_item, entry, _e);
|
||||
return item->i_type != MIE_WALK_ITEM_NONE ? item : NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct mie_op *get_first_child(struct mie_walker *walker, struct mie_op *op)
|
||||
{
|
||||
bool backwards = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0;
|
||||
@@ -95,16 +105,17 @@ static struct mie_op *get_first_child(struct mie_walker *walker, struct mie_op *
|
||||
|
||||
return op;
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t walk_item_get_nr_children(const struct mie_walk_item *item)
|
||||
static bool walk_item_has_children(const struct mie_walk_item *item)
|
||||
{
|
||||
switch (item->i_type) {
|
||||
case MIE_WALK_ITEM_OP:
|
||||
return MIE_VECTOR_COUNT(item->i_op->op_regions);
|
||||
return mie_op_get_first_region(item->i_op) != NULL;
|
||||
case MIE_WALK_ITEM_BLOCK:
|
||||
return MIE_VECTOR_COUNT(item->i_block->b_ops);
|
||||
return mie_block_get_first_op(item->i_block) != NULL;
|
||||
case MIE_WALK_ITEM_REGION:
|
||||
return MIE_VECTOR_COUNT(item->i_region->r_blocks);
|
||||
return mie_region_get_first_block(item->i_region) != NULL;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -128,42 +139,68 @@ static bool should_correct_depth(
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool walk_item_get_child(
|
||||
static bool walk_item_get_first_child(
|
||||
struct mie_walker *walker, const struct mie_walk_item *item,
|
||||
size_t index, struct mie_walk_item *child)
|
||||
struct mie_walk_item *child)
|
||||
{
|
||||
bool ok = false;
|
||||
b_queue_entry *entry = NULL;
|
||||
|
||||
switch (item->i_type) {
|
||||
case MIE_WALK_ITEM_OP:
|
||||
if (MIE_VECTOR_COUNT(item->i_op->op_regions) <= index) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
child->i_type = MIE_WALK_ITEM_REGION;
|
||||
child->i_region = &item->i_op->op_regions.items[index];
|
||||
ok = true;
|
||||
child->i_region = mie_op_get_first_region(item->i_op);
|
||||
ok = child->i_region != NULL;
|
||||
break;
|
||||
case MIE_WALK_ITEM_BLOCK:
|
||||
if (MIE_VECTOR_COUNT(item->i_block->b_ops) <= index) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
child->i_type = MIE_WALK_ITEM_OP;
|
||||
child->i_op = &item->i_block->b_ops.items[index];
|
||||
ok = true;
|
||||
child->i_op = mie_block_get_first_op(item->i_block);
|
||||
ok = child->i_op != NULL;
|
||||
break;
|
||||
case MIE_WALK_ITEM_REGION:
|
||||
if (MIE_VECTOR_COUNT(item->i_region->r_blocks) <= index) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
child->i_type = MIE_WALK_ITEM_BLOCK;
|
||||
child->i_block = &item->i_region->r_blocks.items[index];
|
||||
ok = true;
|
||||
child->i_block = mie_region_get_first_block(item->i_region);
|
||||
ok = child->i_block != NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
child->i_depth = item->i_depth + 1;
|
||||
|
||||
if (should_correct_depth(walker, item)) {
|
||||
child->i_depth--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool walk_item_get_last_child(
|
||||
struct mie_walker *walker, const struct mie_walk_item *item,
|
||||
struct mie_walk_item *child)
|
||||
{
|
||||
bool ok = false;
|
||||
b_queue_entry *entry = NULL;
|
||||
|
||||
switch (item->i_type) {
|
||||
case MIE_WALK_ITEM_OP:
|
||||
child->i_type = MIE_WALK_ITEM_REGION;
|
||||
child->i_region = mie_op_get_last_region(item->i_op);
|
||||
ok = child->i_region != NULL;
|
||||
break;
|
||||
case MIE_WALK_ITEM_BLOCK:
|
||||
child->i_type = MIE_WALK_ITEM_OP;
|
||||
child->i_op = mie_block_get_last_op(item->i_block);
|
||||
ok = child->i_op != NULL;
|
||||
break;
|
||||
case MIE_WALK_ITEM_REGION:
|
||||
child->i_type = MIE_WALK_ITEM_BLOCK;
|
||||
child->i_block = mie_region_get_last_block(item->i_region);
|
||||
ok = child->i_block != NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -174,7 +211,6 @@ static bool walk_item_get_child(
|
||||
}
|
||||
|
||||
child->i_depth = item->i_depth + 1;
|
||||
child->i_index = index;
|
||||
|
||||
if (should_correct_depth(walker, item)) {
|
||||
child->i_depth--;
|
||||
@@ -192,8 +228,9 @@ static bool walk_item_get_next_sibling(
|
||||
|
||||
sibling->i_depth = item->i_depth;
|
||||
sibling->i_type = item->i_type;
|
||||
sibling->i_index = item->i_index + 1;
|
||||
|
||||
size_t index = 0;
|
||||
b_queue_entry *entry = NULL;
|
||||
struct mie_region *parent_r = NULL;
|
||||
struct mie_block *parent_b = NULL;
|
||||
struct mie_op *parent_o = NULL;
|
||||
@@ -205,36 +242,26 @@ static bool walk_item_get_next_sibling(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_b->b_ops)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_op = &parent_b->b_ops.items[item->i_index + 1];
|
||||
return true;
|
||||
sibling->i_op = mie_block_get_next_op(parent_b, item->i_op);
|
||||
return sibling->i_op != NULL;
|
||||
case MIE_WALK_ITEM_BLOCK:
|
||||
parent_r = item->i_block->b_parent;
|
||||
if (!parent_r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_r->r_blocks)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_block = &parent_r->r_blocks.items[item->i_index + 1];
|
||||
return true;
|
||||
sibling->i_block
|
||||
= mie_region_get_next_block(parent_r, item->i_block);
|
||||
return sibling->i_block != NULL;
|
||||
case MIE_WALK_ITEM_REGION:
|
||||
parent_o = item->i_region->r_parent;
|
||||
if (!parent_o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_o->op_regions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_region = &parent_o->op_regions.items[item->i_index + 1];
|
||||
return true;
|
||||
sibling->i_region
|
||||
= mie_op_get_next_region(parent_o, item->i_region);
|
||||
return sibling->i_region != NULL;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -243,14 +270,14 @@ static bool walk_item_get_next_sibling(
|
||||
static bool walk_item_get_prev_sibling(
|
||||
const struct mie_walk_item *item, struct mie_walk_item *sibling)
|
||||
{
|
||||
if (item->i_depth == 0 || item->i_index == 0) {
|
||||
if (item->i_depth == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_depth = item->i_depth;
|
||||
sibling->i_type = item->i_type;
|
||||
sibling->i_index = item->i_index - 1;
|
||||
|
||||
size_t index = 0;
|
||||
struct mie_region *parent_r = NULL;
|
||||
struct mie_block *parent_b = NULL;
|
||||
struct mie_op *parent_o = NULL;
|
||||
@@ -262,24 +289,26 @@ static bool walk_item_get_prev_sibling(
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_op = &parent_b->b_ops.items[item->i_index - 1];
|
||||
return true;
|
||||
sibling->i_op = mie_block_get_prev_op(parent_b, item->i_op);
|
||||
return sibling->i_op != NULL;
|
||||
case MIE_WALK_ITEM_BLOCK:
|
||||
parent_r = item->i_block->b_parent;
|
||||
if (!parent_r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_block = &parent_r->r_blocks.items[item->i_index - 1];
|
||||
return true;
|
||||
sibling->i_block
|
||||
= mie_region_get_prev_block(parent_r, item->i_block);
|
||||
return sibling->i_block != NULL;
|
||||
case MIE_WALK_ITEM_REGION:
|
||||
parent_o = item->i_region->r_parent;
|
||||
if (!parent_o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sibling->i_region = &parent_o->op_regions.items[item->i_index - 1];
|
||||
return true;
|
||||
sibling->i_region
|
||||
= mie_op_get_prev_region(parent_o, item->i_region);
|
||||
return sibling->i_region != NULL;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -334,9 +363,9 @@ static bool step_pre_f(struct mie_walker *walker)
|
||||
struct mie_walk_item next;
|
||||
|
||||
bool ok = false;
|
||||
size_t nr_children = walk_item_get_nr_children(item);
|
||||
if (nr_children > 0) {
|
||||
ok = walk_item_get_child(walker, item, 0, &next);
|
||||
bool has_children = walk_item_has_children(item);
|
||||
if (has_children) {
|
||||
ok = walk_item_get_first_child(walker, item, &next);
|
||||
|
||||
if (ok) {
|
||||
push_walk_item(walker, &next);
|
||||
@@ -384,9 +413,9 @@ static bool step_pre_b(struct mie_walker *walker)
|
||||
struct mie_walk_item next;
|
||||
|
||||
bool ok = false;
|
||||
size_t nr_children = walk_item_get_nr_children(item);
|
||||
if (nr_children > 0) {
|
||||
ok = walk_item_get_child(walker, item, nr_children - 1, &next);
|
||||
bool has_children = walk_item_has_children(item);
|
||||
if (has_children) {
|
||||
ok = walk_item_get_last_child(walker, item, &next);
|
||||
|
||||
if (ok) {
|
||||
push_walk_item(walker, &next);
|
||||
@@ -437,10 +466,10 @@ static bool step_post_f(struct mie_walker *walker)
|
||||
|
||||
while (1) {
|
||||
item = current_item(walker);
|
||||
size_t nr_children = walk_item_get_nr_children(item);
|
||||
bool has_children = walk_item_has_children(item);
|
||||
|
||||
if (nr_children > 0 && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
|
||||
ok = walk_item_get_child(walker, item, 0, &next);
|
||||
if (has_children && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
|
||||
ok = walk_item_get_first_child(walker, item, &next);
|
||||
|
||||
if (ok) {
|
||||
push_walk_item(walker, &next);
|
||||
@@ -449,7 +478,7 @@ static bool step_post_f(struct mie_walker *walker)
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) {
|
||||
if (!has_children && !(item->_f & WALK_ITEM_F_VISITED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -469,6 +498,55 @@ static bool step_post_f(struct mie_walker *walker)
|
||||
}
|
||||
}
|
||||
|
||||
static bool step_flat_f(struct mie_walker *walker)
|
||||
{
|
||||
struct mie_walk_item *stack[] = {
|
||||
&walker->w_region,
|
||||
&walker->w_block,
|
||||
&walker->w_op,
|
||||
};
|
||||
const int stack_size = sizeof stack / sizeof stack[0];
|
||||
|
||||
int start;
|
||||
if (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) {
|
||||
start = 0;
|
||||
} else if (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) {
|
||||
start = 1;
|
||||
} else {
|
||||
start = 2;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = start; i >= 0; i--) {
|
||||
struct mie_walk_item *item = stack[i];
|
||||
struct mie_walk_item next;
|
||||
if (walk_item_get_next_sibling(item, &next)) {
|
||||
*item = next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int k = i; k < stack_size - 1; k++) {
|
||||
struct mie_walk_item *parent = stack[k];
|
||||
struct mie_walk_item *child = stack[k + 1];
|
||||
|
||||
if (!walk_item_get_first_child(walker, parent, child)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool step_flat_b(struct mie_walker *walker)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool step_post_b(struct mie_walker *walker)
|
||||
{
|
||||
/* backward, post-order traversal:
|
||||
@@ -485,11 +563,10 @@ static bool step_post_b(struct mie_walker *walker)
|
||||
|
||||
while (1) {
|
||||
item = current_item(walker);
|
||||
size_t nr_children = walk_item_get_nr_children(item);
|
||||
bool has_children = walk_item_has_children(item);
|
||||
|
||||
if (nr_children > 0 && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
|
||||
ok = walk_item_get_child(
|
||||
walker, item, nr_children - 1, &next);
|
||||
if (has_children && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
|
||||
ok = walk_item_get_last_child(walker, item, &next);
|
||||
|
||||
if (ok) {
|
||||
push_walk_item(walker, &next);
|
||||
@@ -498,7 +575,7 @@ static bool step_post_b(struct mie_walker *walker)
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) {
|
||||
if (!has_children && !(item->_f & WALK_ITEM_F_VISITED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -520,25 +597,106 @@ static bool step_post_b(struct mie_walker *walker)
|
||||
|
||||
static bool step(struct mie_walker *walker)
|
||||
{
|
||||
bool recursive = (walker->w_flags & MIE_WALKER_F_RECURSIVE) != 0;
|
||||
bool backward = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0;
|
||||
bool postorder = (walker->w_flags & MIE_WALKER_F_POSTORDER) != 0;
|
||||
|
||||
if (backward) {
|
||||
if (postorder) {
|
||||
return step_post_b(walker);
|
||||
if (!recursive) {
|
||||
return backward ? step_flat_b(walker) : step_flat_f(walker);
|
||||
} else if (postorder) {
|
||||
return backward ? step_post_b(walker) : step_post_f(walker);
|
||||
} else {
|
||||
return backward ? step_pre_b(walker) : step_pre_f(walker);
|
||||
}
|
||||
|
||||
return step_pre_b(walker);
|
||||
}
|
||||
|
||||
if (postorder) {
|
||||
return step_post_f(walker);
|
||||
}
|
||||
|
||||
return step_pre_f(walker);
|
||||
}
|
||||
|
||||
static enum mie_status prepare_preorder_traversal(struct mie_walker *walker)
|
||||
static enum mie_status prepare_flat_traversal(
|
||||
struct mie_walker *walker, const struct mie_op *op)
|
||||
{
|
||||
bool backward = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0;
|
||||
bool ok = false;
|
||||
enum mie_walk_item_type target_type = MIE_WALK_ITEM_NONE;
|
||||
enum mie_status status = MIE_SUCCESS;
|
||||
|
||||
struct mie_walk_item root = {};
|
||||
root.i_op = (struct mie_op *)op;
|
||||
root.i_type = MIE_WALK_ITEM_OP;
|
||||
|
||||
if (walker->w_flags & MIE_WALKER_F_INCLUDE_REGIONS) {
|
||||
target_type = MIE_WALK_ITEM_REGION;
|
||||
} else if (walker->w_flags & MIE_WALKER_F_INCLUDE_BLOCKS) {
|
||||
target_type = MIE_WALK_ITEM_BLOCK;
|
||||
} else {
|
||||
target_type = MIE_WALK_ITEM_OP;
|
||||
}
|
||||
|
||||
bool has_children = walk_item_has_children(&root);
|
||||
if (!has_children) {
|
||||
return MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (backward) {
|
||||
ok = walk_item_get_last_child(walker, &root, &walker->w_region);
|
||||
status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
} else {
|
||||
ok = walk_item_get_first_child(walker, &root, &walker->w_region);
|
||||
status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (status != MIE_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (target_type == MIE_WALK_ITEM_REGION) {
|
||||
walker->w_region.i_depth = 1;
|
||||
return MIE_SUCCESS;
|
||||
}
|
||||
|
||||
has_children = walk_item_has_children(&walker->w_region);
|
||||
if (!has_children) {
|
||||
return MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (backward) {
|
||||
ok = walk_item_get_last_child(
|
||||
walker, &walker->w_region, &walker->w_block);
|
||||
status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
} else {
|
||||
ok = walk_item_get_first_child(
|
||||
walker, &walker->w_region, &walker->w_block);
|
||||
status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (status != MIE_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (target_type == MIE_WALK_ITEM_BLOCK) {
|
||||
walker->w_block.i_depth = 1;
|
||||
return MIE_SUCCESS;
|
||||
}
|
||||
|
||||
has_children = walk_item_has_children(&walker->w_block);
|
||||
if (!has_children) {
|
||||
return MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (backward) {
|
||||
ok = walk_item_get_last_child(
|
||||
walker, &walker->w_block, &walker->w_op);
|
||||
status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
} else {
|
||||
ok = walk_item_get_first_child(
|
||||
walker, &walker->w_block, &walker->w_op);
|
||||
status = ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
walker->w_op.i_depth = 1;
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum mie_status prepare_preorder_traversal(
|
||||
struct mie_walker *walker, const struct mie_op *root)
|
||||
{
|
||||
struct mie_walk_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
@@ -546,7 +704,7 @@ static enum mie_status prepare_preorder_traversal(struct mie_walker *walker)
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
item->i_op = walker->w_root;
|
||||
item->i_op = (struct mie_op *)root;
|
||||
item->i_type = MIE_WALK_ITEM_OP;
|
||||
|
||||
push_walk_item(walker, item);
|
||||
@@ -554,10 +712,11 @@ static enum mie_status prepare_preorder_traversal(struct mie_walker *walker)
|
||||
return MIE_SUCCESS;
|
||||
}
|
||||
|
||||
static enum mie_status prepare_postorder_traversal(struct mie_walker *walker)
|
||||
static enum mie_status prepare_postorder_traversal(
|
||||
struct mie_walker *walker, const struct mie_op *root)
|
||||
{
|
||||
struct mie_walk_item item = {};
|
||||
item.i_op = walker->w_root;
|
||||
item.i_op = (struct mie_op *)root;
|
||||
item.i_type = MIE_WALK_ITEM_OP;
|
||||
|
||||
push_walk_item(walker, &item);
|
||||
@@ -568,18 +727,17 @@ static enum mie_status prepare_postorder_traversal(struct mie_walker *walker)
|
||||
while (1) {
|
||||
struct mie_walk_item *current = current_item(walker);
|
||||
struct mie_walk_item child;
|
||||
size_t nr_children = walk_item_get_nr_children(current);
|
||||
if (!nr_children) {
|
||||
bool has_children = walk_item_has_children(current);
|
||||
if (!has_children) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
if (backward) {
|
||||
ok = walk_item_get_child(
|
||||
walker, current, nr_children - 1, &child);
|
||||
ok = walk_item_get_last_child(walker, current, &child);
|
||||
} else {
|
||||
ok = walk_item_get_child(walker, current, 0, &child);
|
||||
ok = walk_item_get_first_child(walker, current, &child);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
@@ -592,30 +750,26 @@ static enum mie_status prepare_postorder_traversal(struct mie_walker *walker)
|
||||
return ok ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct mie_walker *mie_walker_begin(struct mie_op *op, enum mie_walker_flags flags)
|
||||
void mie_walker_begin(
|
||||
struct mie_walker *walker, const struct mie_op *op,
|
||||
enum mie_walker_flags flags)
|
||||
{
|
||||
struct mie_walker *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
memset(walker, 0x0, sizeof *walker);
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
walker->w_flags = flags;
|
||||
|
||||
out->w_flags = flags;
|
||||
out->w_root = op;
|
||||
|
||||
if (flags & MIE_WALKER_F_POSTORDER) {
|
||||
prepare_postorder_traversal(out);
|
||||
if (!(flags & MIE_WALKER_F_RECURSIVE)) {
|
||||
prepare_flat_traversal(walker, op);
|
||||
} else if (flags & MIE_WALKER_F_POSTORDER) {
|
||||
prepare_postorder_traversal(walker, op);
|
||||
} else {
|
||||
prepare_preorder_traversal(out);
|
||||
prepare_preorder_traversal(walker, op);
|
||||
}
|
||||
|
||||
struct mie_walk_item *cur = current_item(out);
|
||||
if (should_ignore_item(out, cur)) {
|
||||
mie_walker_step(out);
|
||||
struct mie_walk_item *cur = current_item(walker);
|
||||
if (cur && should_ignore_item(walker, cur)) {
|
||||
mie_walker_step(walker);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void mie_walker_end(struct mie_walker *walker)
|
||||
@@ -631,9 +785,9 @@ enum mie_status mie_walker_step(struct mie_walker *walker)
|
||||
do {
|
||||
ok = step(walker);
|
||||
cur = current_item(walker);
|
||||
} while (cur && should_ignore_item(walker, cur));
|
||||
} while (ok && cur && should_ignore_item(walker, cur));
|
||||
|
||||
return cur ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
return (ok && cur) ? MIE_SUCCESS : MIE_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct mie_walk_item *mie_walker_get(struct mie_walker *walker)
|
||||
|
||||
Reference in New Issue
Block a user