Skip to content

Commit

Permalink
bftw: Share the bftw_state between iterations of ids/eds
Browse files Browse the repository at this point in the history
  • Loading branch information
tavianator committed Sep 13, 2023
1 parent beea0d2 commit 5f16169
Showing 1 changed file with 71 additions and 72 deletions.
143 changes: 71 additions & 72 deletions src/bftw.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ static void bftw_file_free(struct bftw_cache *cache, struct bftw_file *file) {
* Holds the current state of the bftw() traversal.
*/
struct bftw_state {
/** The path(s) to start from. */
const char **paths;
/** The number of starting paths. */
size_t npaths;
/** bftw() callback. */
bftw_callback *callback;
/** bftw() callback data. */
Expand Down Expand Up @@ -453,6 +457,8 @@ struct bftw_state {

/** Initialize the bftw() state. */
static int bftw_state_init(struct bftw_state *state, const struct bftw_args *args) {
state->paths = args->paths;
state->npaths = args->npaths;
state->callback = args->callback;
state->ptr = args->ptr;
state->flags = args->flags;
Expand Down Expand Up @@ -1426,52 +1432,61 @@ static int bftw_state_destroy(struct bftw_state *state) {
}

/**
* bftw() implementation for simple breadth-/depth-first search.
* Shared implementation for all search strategies.
*/
static int bftw_impl(const struct bftw_args *args) {
struct bftw_state state;
if (bftw_state_init(&state, args) != 0) {
return -1;
}

for (size_t i = 0; i < args->npaths; ++i) {
if (bftw_visit(&state, args->paths[i]) != 0) {
goto done;
static int bftw_impl(struct bftw_state *state) {
for (size_t i = 0; i < state->npaths; ++i) {
if (bftw_visit(state, state->paths[i]) != 0) {
return -1;
}
}
bftw_batch_finish(&state);
bftw_batch_finish(state);

while (true) {
while (bftw_pop_dir(&state)) {
if (bftw_opendir(&state) != 0) {
goto done;
while (bftw_pop_dir(state)) {
if (bftw_opendir(state) != 0) {
return -1;
}
while (bftw_readdir(&state) > 0) {
if (bftw_visit(&state, state.de->name) != 0) {
goto done;
while (bftw_readdir(state) > 0) {
if (bftw_visit(state, state->de->name) != 0) {
return -1;
}
}
if (bftw_closedir(&state) != 0) {
goto done;
if (bftw_closedir(state) != 0) {
return -1;
}
}

if (!bftw_pop_file(&state)) {
if (!bftw_pop_file(state)) {
break;
}
if (bftw_visit(&state, NULL) != 0) {
if (bftw_visit(state, NULL) != 0) {
break;
}
}

done:
return 0;
}

/**
* bftw() implementation for simple breadth-/depth-first search.
*/
static int bftw_walk(const struct bftw_args *args) {
struct bftw_state state;
if (bftw_state_init(&state, args) != 0) {
return -1;
}

bftw_impl(&state);
return bftw_state_destroy(&state);
}

/**
* Iterative deepening search state.
*/
struct bftw_ids_state {
/** Nested walk state. */
struct bftw_state nested;
/** The wrapped callback. */
bftw_callback *delegate;
/** The wrapped callback arguments. */
Expand All @@ -1486,12 +1501,8 @@ struct bftw_ids_state {
size_t max_depth;
/** The set of pruned paths. */
struct trie pruned;
/** An error code to report. */
int error;
/** Whether the bottom has been found. */
bool bottom;
/** Whether to quit the search. */
bool quit;
};

/** Iterative deepening callback function. */
Expand Down Expand Up @@ -1535,72 +1546,61 @@ static enum bftw_action bftw_ids_callback(const struct BFTW *ftwbuf, void *ptr)
ret = BFTW_PRUNE;
}
break;

case BFTW_PRUNE:
if (ftwbuf->type == BFS_DIR) {
if (!trie_insert_str(&state->pruned, ftwbuf->path)) {
state->error = errno;
state->quit = true;
state->nested.error = errno;
ret = BFTW_STOP;
}
}
break;

case BFTW_STOP:
state->quit = true;
break;
}

return ret;
}

/** Initialize iterative deepening state. */
static void bftw_ids_init(const struct bftw_args *args, struct bftw_ids_state *state, struct bftw_args *ids_args) {
static int bftw_ids_init(struct bftw_ids_state *state, const struct bftw_args *args) {
state->delegate = args->callback;
state->ptr = args->ptr;
state->visit = BFTW_PRE;
state->force_visit = false;
state->min_depth = 0;
state->max_depth = 1;
trie_init(&state->pruned);
state->error = 0;
state->bottom = false;
state->quit = false;

*ids_args = *args;
ids_args->callback = bftw_ids_callback;
ids_args->ptr = state;
ids_args->flags &= ~BFTW_POST_ORDER;
struct bftw_args ids_args = *args;
ids_args.callback = bftw_ids_callback;
ids_args.ptr = state;
ids_args.flags &= ~BFTW_POST_ORDER;
return bftw_state_init(&state->nested, &ids_args);
}

/** Finish an iterative deepening search. */
static int bftw_ids_finish(struct bftw_ids_state *state) {
int ret = 0;

if (state->error) {
ret = -1;
} else {
state->error = errno;
}

static int bftw_ids_destroy(struct bftw_ids_state *state) {
trie_destroy(&state->pruned);

errno = state->error;
return ret;
return bftw_state_destroy(&state->nested);
}

/**
* Iterative deepening bftw() wrapper.
*/
static int bftw_ids(const struct bftw_args *args) {
struct bftw_ids_state state;
struct bftw_args ids_args;
bftw_ids_init(args, &state, &ids_args);
if (bftw_ids_init(&state, args) != 0) {
return -1;
}

while (!state.quit && !state.bottom) {
while (!state.bottom) {
state.bottom = true;

if (bftw_impl(&ids_args) != 0) {
state.error = errno;
state.quit = true;
if (bftw_impl(&state.nested) != 0) {
goto done;
}

++state.min_depth;
Expand All @@ -1611,58 +1611,57 @@ static int bftw_ids(const struct bftw_args *args) {
state.visit = BFTW_POST;
state.force_visit = true;

while (!state.quit && state.min_depth > 0) {
while (state.min_depth > 0) {
--state.max_depth;
--state.min_depth;

if (bftw_impl(&ids_args) != 0) {
state.error = errno;
state.quit = true;
if (bftw_impl(&state.nested) != 0) {
goto done;
}
}
}

return bftw_ids_finish(&state);
done:
return bftw_ids_destroy(&state);
}

/**
* Exponential deepening bftw() wrapper.
*/
static int bftw_eds(const struct bftw_args *args) {
struct bftw_ids_state state;
struct bftw_args ids_args;
bftw_ids_init(args, &state, &ids_args);
if (bftw_ids_init(&state, args) != 0) {
return -1;
}

while (!state.quit && !state.bottom) {
while (!state.bottom) {
state.bottom = true;

if (bftw_impl(&ids_args) != 0) {
state.error = errno;
state.quit = true;
if (bftw_impl(&state.nested) != 0) {
goto done;
}

state.min_depth = state.max_depth;
state.max_depth *= 2;
}

if (!state.quit && (args->flags & BFTW_POST_ORDER)) {
if (args->flags & BFTW_POST_ORDER) {
state.visit = BFTW_POST;
state.min_depth = 0;
ids_args.flags |= BFTW_POST_ORDER;
state.nested.flags |= BFTW_POST_ORDER;

if (bftw_impl(&ids_args) != 0) {
state.error = errno;
}
bftw_impl(&state.nested);
}

return bftw_ids_finish(&state);
done:
return bftw_ids_destroy(&state);
}

int bftw(const struct bftw_args *args) {
switch (args->strategy) {
case BFTW_BFS:
case BFTW_DFS:
return bftw_impl(args);
return bftw_walk(args);
case BFTW_IDS:
return bftw_ids(args);
case BFTW_EDS:
Expand Down

0 comments on commit 5f16169

Please sign in to comment.