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>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct mie_op;
|
struct mie_op;
|
||||||
struct mie_walker;
|
|
||||||
|
|
||||||
enum mie_walker_flags {
|
enum mie_walker_flags {
|
||||||
MIE_WALKER_F_NONE = 0x00u,
|
MIE_WALKER_F_NONE = 0x00u,
|
||||||
@@ -38,7 +37,7 @@ struct mie_walk_item {
|
|||||||
int _f;
|
int _f;
|
||||||
b_queue_entry _e;
|
b_queue_entry _e;
|
||||||
enum mie_walk_item_type i_type;
|
enum mie_walk_item_type i_type;
|
||||||
size_t i_index;
|
// size_t i_index;
|
||||||
size_t i_depth;
|
size_t i_depth;
|
||||||
union {
|
union {
|
||||||
struct mie_op *i_op;
|
struct mie_op *i_op;
|
||||||
@@ -47,8 +46,21 @@ struct mie_walk_item {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
MIE_API struct mie_walker *mie_walker_begin(
|
struct mie_walker {
|
||||||
struct mie_op *op, enum mie_walker_flags flags);
|
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 void mie_walker_end(struct mie_walker *walker);
|
||||||
|
|
||||||
MIE_API enum mie_status mie_walker_step(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)
|
#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(
|
static bool should_ignore_item(
|
||||||
const struct mie_walker *walker, const struct mie_walk_item *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)
|
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);
|
b_queue_entry *entry = b_queue_last(&walker->w_stack);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return NULL;
|
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;
|
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)
|
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;
|
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;
|
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) {
|
switch (item->i_type) {
|
||||||
case MIE_WALK_ITEM_OP:
|
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:
|
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:
|
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:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -128,42 +139,68 @@ static bool should_correct_depth(
|
|||||||
return false;
|
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,
|
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;
|
bool ok = false;
|
||||||
|
b_queue_entry *entry = NULL;
|
||||||
|
|
||||||
switch (item->i_type) {
|
switch (item->i_type) {
|
||||||
case MIE_WALK_ITEM_OP:
|
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_type = MIE_WALK_ITEM_REGION;
|
||||||
child->i_region = &item->i_op->op_regions.items[index];
|
child->i_region = mie_op_get_first_region(item->i_op);
|
||||||
ok = true;
|
ok = child->i_region != NULL;
|
||||||
break;
|
break;
|
||||||
case MIE_WALK_ITEM_BLOCK:
|
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_type = MIE_WALK_ITEM_OP;
|
||||||
child->i_op = &item->i_block->b_ops.items[index];
|
child->i_op = mie_block_get_first_op(item->i_block);
|
||||||
ok = true;
|
ok = child->i_op != NULL;
|
||||||
break;
|
break;
|
||||||
case MIE_WALK_ITEM_REGION:
|
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_type = MIE_WALK_ITEM_BLOCK;
|
||||||
child->i_block = &item->i_region->r_blocks.items[index];
|
child->i_block = mie_region_get_first_block(item->i_region);
|
||||||
ok = true;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -174,7 +211,6 @@ static bool walk_item_get_child(
|
|||||||
}
|
}
|
||||||
|
|
||||||
child->i_depth = item->i_depth + 1;
|
child->i_depth = item->i_depth + 1;
|
||||||
child->i_index = index;
|
|
||||||
|
|
||||||
if (should_correct_depth(walker, item)) {
|
if (should_correct_depth(walker, item)) {
|
||||||
child->i_depth--;
|
child->i_depth--;
|
||||||
@@ -192,8 +228,9 @@ static bool walk_item_get_next_sibling(
|
|||||||
|
|
||||||
sibling->i_depth = item->i_depth;
|
sibling->i_depth = item->i_depth;
|
||||||
sibling->i_type = item->i_type;
|
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_region *parent_r = NULL;
|
||||||
struct mie_block *parent_b = NULL;
|
struct mie_block *parent_b = NULL;
|
||||||
struct mie_op *parent_o = NULL;
|
struct mie_op *parent_o = NULL;
|
||||||
@@ -205,36 +242,26 @@ static bool walk_item_get_next_sibling(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_b->b_ops)) {
|
sibling->i_op = mie_block_get_next_op(parent_b, item->i_op);
|
||||||
return false;
|
return sibling->i_op != NULL;
|
||||||
}
|
|
||||||
|
|
||||||
sibling->i_op = &parent_b->b_ops.items[item->i_index + 1];
|
|
||||||
return true;
|
|
||||||
case MIE_WALK_ITEM_BLOCK:
|
case MIE_WALK_ITEM_BLOCK:
|
||||||
parent_r = item->i_block->b_parent;
|
parent_r = item->i_block->b_parent;
|
||||||
if (!parent_r) {
|
if (!parent_r) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_r->r_blocks)) {
|
sibling->i_block
|
||||||
return false;
|
= mie_region_get_next_block(parent_r, item->i_block);
|
||||||
}
|
return sibling->i_block != NULL;
|
||||||
|
|
||||||
sibling->i_block = &parent_r->r_blocks.items[item->i_index + 1];
|
|
||||||
return true;
|
|
||||||
case MIE_WALK_ITEM_REGION:
|
case MIE_WALK_ITEM_REGION:
|
||||||
parent_o = item->i_region->r_parent;
|
parent_o = item->i_region->r_parent;
|
||||||
if (!parent_o) {
|
if (!parent_o) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->i_index + 1 >= MIE_VECTOR_COUNT(parent_o->op_regions)) {
|
sibling->i_region
|
||||||
return false;
|
= mie_op_get_next_region(parent_o, item->i_region);
|
||||||
}
|
return sibling->i_region != NULL;
|
||||||
|
|
||||||
sibling->i_region = &parent_o->op_regions.items[item->i_index + 1];
|
|
||||||
return true;
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -243,14 +270,14 @@ static bool walk_item_get_next_sibling(
|
|||||||
static bool walk_item_get_prev_sibling(
|
static bool walk_item_get_prev_sibling(
|
||||||
const struct mie_walk_item *item, struct mie_walk_item *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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sibling->i_depth = item->i_depth;
|
sibling->i_depth = item->i_depth;
|
||||||
sibling->i_type = item->i_type;
|
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_region *parent_r = NULL;
|
||||||
struct mie_block *parent_b = NULL;
|
struct mie_block *parent_b = NULL;
|
||||||
struct mie_op *parent_o = NULL;
|
struct mie_op *parent_o = NULL;
|
||||||
@@ -262,24 +289,26 @@ static bool walk_item_get_prev_sibling(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sibling->i_op = &parent_b->b_ops.items[item->i_index - 1];
|
sibling->i_op = mie_block_get_prev_op(parent_b, item->i_op);
|
||||||
return true;
|
return sibling->i_op != NULL;
|
||||||
case MIE_WALK_ITEM_BLOCK:
|
case MIE_WALK_ITEM_BLOCK:
|
||||||
parent_r = item->i_block->b_parent;
|
parent_r = item->i_block->b_parent;
|
||||||
if (!parent_r) {
|
if (!parent_r) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sibling->i_block = &parent_r->r_blocks.items[item->i_index - 1];
|
sibling->i_block
|
||||||
return true;
|
= mie_region_get_prev_block(parent_r, item->i_block);
|
||||||
|
return sibling->i_block != NULL;
|
||||||
case MIE_WALK_ITEM_REGION:
|
case MIE_WALK_ITEM_REGION:
|
||||||
parent_o = item->i_region->r_parent;
|
parent_o = item->i_region->r_parent;
|
||||||
if (!parent_o) {
|
if (!parent_o) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sibling->i_region = &parent_o->op_regions.items[item->i_index - 1];
|
sibling->i_region
|
||||||
return true;
|
= mie_op_get_prev_region(parent_o, item->i_region);
|
||||||
|
return sibling->i_region != NULL;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -334,9 +363,9 @@ static bool step_pre_f(struct mie_walker *walker)
|
|||||||
struct mie_walk_item next;
|
struct mie_walk_item next;
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
size_t nr_children = walk_item_get_nr_children(item);
|
bool has_children = walk_item_has_children(item);
|
||||||
if (nr_children > 0) {
|
if (has_children) {
|
||||||
ok = walk_item_get_child(walker, item, 0, &next);
|
ok = walk_item_get_first_child(walker, item, &next);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
push_walk_item(walker, &next);
|
push_walk_item(walker, &next);
|
||||||
@@ -384,9 +413,9 @@ static bool step_pre_b(struct mie_walker *walker)
|
|||||||
struct mie_walk_item next;
|
struct mie_walk_item next;
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
size_t nr_children = walk_item_get_nr_children(item);
|
bool has_children = walk_item_has_children(item);
|
||||||
if (nr_children > 0) {
|
if (has_children) {
|
||||||
ok = walk_item_get_child(walker, item, nr_children - 1, &next);
|
ok = walk_item_get_last_child(walker, item, &next);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
push_walk_item(walker, &next);
|
push_walk_item(walker, &next);
|
||||||
@@ -437,10 +466,10 @@ static bool step_post_f(struct mie_walker *walker)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
item = current_item(walker);
|
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)) {
|
if (has_children && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
|
||||||
ok = walk_item_get_child(walker, item, 0, &next);
|
ok = walk_item_get_first_child(walker, item, &next);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
push_walk_item(walker, &next);
|
push_walk_item(walker, &next);
|
||||||
@@ -449,7 +478,7 @@ static bool step_post_f(struct mie_walker *walker)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) {
|
if (!has_children && !(item->_f & WALK_ITEM_F_VISITED)) {
|
||||||
return true;
|
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)
|
static bool step_post_b(struct mie_walker *walker)
|
||||||
{
|
{
|
||||||
/* backward, post-order traversal:
|
/* backward, post-order traversal:
|
||||||
@@ -485,11 +563,10 @@ static bool step_post_b(struct mie_walker *walker)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
item = current_item(walker);
|
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)) {
|
if (has_children && !(item->_f & WALK_ITEM_F_CHILDREN_VISITED)) {
|
||||||
ok = walk_item_get_child(
|
ok = walk_item_get_last_child(walker, item, &next);
|
||||||
walker, item, nr_children - 1, &next);
|
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
push_walk_item(walker, &next);
|
push_walk_item(walker, &next);
|
||||||
@@ -498,7 +575,7 @@ static bool step_post_b(struct mie_walker *walker)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nr_children == 0 && !(item->_f & WALK_ITEM_F_VISITED)) {
|
if (!has_children && !(item->_f & WALK_ITEM_F_VISITED)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,25 +597,106 @@ static bool step_post_b(struct mie_walker *walker)
|
|||||||
|
|
||||||
static bool step(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 backward = (walker->w_flags & MIE_WALKER_F_BACKWARD) != 0;
|
||||||
bool postorder = (walker->w_flags & MIE_WALKER_F_POSTORDER) != 0;
|
bool postorder = (walker->w_flags & MIE_WALKER_F_POSTORDER) != 0;
|
||||||
|
|
||||||
if (backward) {
|
if (!recursive) {
|
||||||
if (postorder) {
|
return backward ? step_flat_b(walker) : step_flat_f(walker);
|
||||||
return step_post_b(walker);
|
} else if (postorder) {
|
||||||
}
|
return backward ? step_post_b(walker) : step_post_f(walker);
|
||||||
|
} else {
|
||||||
return step_pre_b(walker);
|
return backward ? step_pre_b(walker) : step_pre_f(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);
|
struct mie_walk_item *item = malloc(sizeof *item);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
@@ -546,7 +704,7 @@ static enum mie_status prepare_preorder_traversal(struct mie_walker *walker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(item, 0x0, sizeof *item);
|
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;
|
item->i_type = MIE_WALK_ITEM_OP;
|
||||||
|
|
||||||
push_walk_item(walker, item);
|
push_walk_item(walker, item);
|
||||||
@@ -554,10 +712,11 @@ static enum mie_status prepare_preorder_traversal(struct mie_walker *walker)
|
|||||||
return MIE_SUCCESS;
|
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 = {};
|
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;
|
item.i_type = MIE_WALK_ITEM_OP;
|
||||||
|
|
||||||
push_walk_item(walker, &item);
|
push_walk_item(walker, &item);
|
||||||
@@ -568,18 +727,17 @@ static enum mie_status prepare_postorder_traversal(struct mie_walker *walker)
|
|||||||
while (1) {
|
while (1) {
|
||||||
struct mie_walk_item *current = current_item(walker);
|
struct mie_walk_item *current = current_item(walker);
|
||||||
struct mie_walk_item child;
|
struct mie_walk_item child;
|
||||||
size_t nr_children = walk_item_get_nr_children(current);
|
bool has_children = walk_item_has_children(current);
|
||||||
if (!nr_children) {
|
if (!has_children) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
if (backward) {
|
if (backward) {
|
||||||
ok = walk_item_get_child(
|
ok = walk_item_get_last_child(walker, current, &child);
|
||||||
walker, current, nr_children - 1, &child);
|
|
||||||
} else {
|
} else {
|
||||||
ok = walk_item_get_child(walker, current, 0, &child);
|
ok = walk_item_get_first_child(walker, current, &child);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
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;
|
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);
|
memset(walker, 0x0, sizeof *walker);
|
||||||
if (!out) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(out, 0x0, sizeof *out);
|
walker->w_flags = flags;
|
||||||
|
|
||||||
out->w_flags = flags;
|
if (!(flags & MIE_WALKER_F_RECURSIVE)) {
|
||||||
out->w_root = op;
|
prepare_flat_traversal(walker, op);
|
||||||
|
} else if (flags & MIE_WALKER_F_POSTORDER) {
|
||||||
if (flags & MIE_WALKER_F_POSTORDER) {
|
prepare_postorder_traversal(walker, op);
|
||||||
prepare_postorder_traversal(out);
|
|
||||||
} else {
|
} else {
|
||||||
prepare_preorder_traversal(out);
|
prepare_preorder_traversal(walker, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mie_walk_item *cur = current_item(out);
|
struct mie_walk_item *cur = current_item(walker);
|
||||||
if (should_ignore_item(out, cur)) {
|
if (cur && should_ignore_item(walker, cur)) {
|
||||||
mie_walker_step(out);
|
mie_walker_step(walker);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mie_walker_end(struct mie_walker *walker)
|
void mie_walker_end(struct mie_walker *walker)
|
||||||
@@ -631,9 +785,9 @@ enum mie_status mie_walker_step(struct mie_walker *walker)
|
|||||||
do {
|
do {
|
||||||
ok = step(walker);
|
ok = step(walker);
|
||||||
cur = current_item(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)
|
struct mie_walk_item *mie_walker_get(struct mie_walker *walker)
|
||||||
|
|||||||
Reference in New Issue
Block a user