Make vector struct type-safe

This commit is contained in:
Max Brunsfeld 2016-02-17 14:45:00 -08:00
parent 3f08bfb264
commit 6fa7eca966
6 changed files with 223 additions and 246 deletions

View file

@ -19,23 +19,23 @@ typedef struct StackNode {
short unsigned int ref_count;
} StackNode;
struct Stack {
Vector heads;
Vector pop_results;
Vector pop_paths;
Vector node_pool;
void *tree_selection_payload;
TreeSelectionFunction tree_selection_function;
};
typedef Vector(TSTree *) TreeVector;
typedef struct {
size_t goal_tree_count;
StackNode *node;
Vector trees;
TreeVector trees;
bool is_shared;
} PopPath;
static StackNode *NULL_NODE = NULL;
struct Stack {
Vector(StackNode *) heads;
StackPopResultVector pop_results;
Vector(PopPath) pop_paths;
Vector(StackNode *) node_pool;
void *tree_selection_payload;
TreeSelectionFunction tree_selection_function;
};
/*
* Section: Stack lifecycle
@ -50,10 +50,10 @@ Stack *ts_stack_new() {
if (!self)
goto error;
self->heads = vector_new(sizeof(StackNode *));
self->pop_results = vector_new(sizeof(StackPopResult));
self->pop_paths = vector_new(sizeof(PopPath));
self->node_pool = vector_new(sizeof(StackNode *));
vector_init(&self->heads);
vector_init(&self->pop_results);
vector_init(&self->pop_paths);
vector_init(&self->node_pool);
self->tree_selection_payload = NULL;
self->tree_selection_function = ts_stack__default_tree_selection;
@ -69,7 +69,7 @@ Stack *ts_stack_new() {
if (!vector_grow(&self->node_pool, 20))
goto error;
vector_push(&self->heads, &NULL_NODE);
vector_push(&self->heads, NULL);
return self;
@ -108,7 +108,7 @@ TSTree *ts_stack_top_tree(const Stack *self, int head) {
}
StackEntry *ts_stack_head(Stack *self, int head) {
StackNode *node = *(StackNode **)vector_get(&self->heads, head);
StackNode *node = self->heads.contents[head];
return node ? &node->entry : NULL;
}
@ -148,7 +148,7 @@ static bool stack_node_release(Stack *self, StackNode *node) {
if (self->node_pool.size >= MAX_NODE_POOL_SIZE)
ts_free(node);
else
vector_push(&self->node_pool, &node);
vector_push(&self->node_pool, node);
return true;
} else {
@ -156,7 +156,8 @@ static bool stack_node_release(Stack *self, StackNode *node) {
}
}
static StackNode *stack_node_new(Stack *self, StackNode *next, TSStateId state, TSTree *tree) {
static StackNode *stack_node_new(Stack *self, StackNode *next, TSStateId state,
TSTree *tree) {
assert(tree->ref_count > 0);
StackNode *node;
if (self->node_pool.size == 0) {
@ -164,7 +165,7 @@ static StackNode *stack_node_new(Stack *self, StackNode *next, TSStateId state,
if (!node)
return NULL;
} else {
node = *(StackNode **)vector_pop(&self->node_pool);
node = vector_pop(&self->node_pool);
}
ts_tree_retain(tree);
@ -184,8 +185,8 @@ static StackNode *stack_node_new(Stack *self, StackNode *next, TSStateId state,
static void ts_stack__add_alternative_tree(Stack *self, StackNode *node,
TSTree *tree) {
if (tree != node->entry.tree) {
int comparison = self->tree_selection_function(
self->tree_selection_payload, node->entry.tree, tree);
int comparison = self->tree_selection_function(self->tree_selection_payload,
node->entry.tree, tree);
if (comparison > 0) {
ts_tree_retain(tree);
@ -211,7 +212,8 @@ static void ts_stack__add_alternative_pop_result(Stack *self,
for (size_t i = 0; i < result->tree_count; i++) {
TSTree *tree = result->trees[i];
TSTree *new_tree = new_result->trees[i];
int comparison = self->tree_selection_function(self->tree_selection_payload, tree, new_tree);
int comparison = self->tree_selection_function(
self->tree_selection_payload, tree, new_tree);
if (comparison < 0) {
break;
} else if (comparison > 0) {
@ -230,7 +232,6 @@ static void ts_stack__add_alternative_pop_result(Stack *self,
}
}
static void ts_stack__add_node_successor(Stack *self, StackNode *node,
StackNode *new_successor) {
for (int i = 0; i < node->successor_count; i++) {
@ -259,7 +260,7 @@ static void ts_stack__add_node_successor(Stack *self, StackNode *node,
*/
static int ts_stack__add_head(Stack *self, StackNode *node) {
if (vector_push(&self->heads, &node)) {
if (vector_push(&self->heads, node)) {
stack_node_retain(node);
return self->heads.size - 1;
} else {
@ -269,16 +270,15 @@ static int ts_stack__add_head(Stack *self, StackNode *node) {
static int ts_stack__find_head(Stack *self, StackNode *node) {
for (size_t i = 0; i < self->heads.size; i++) {
StackNode **existing_node = vector_get(&self->heads, i);
if (*existing_node == node)
if (self->heads.contents[i] == node)
return i;
}
return -1;
}
void ts_stack_remove_head(Stack *self, int head_index) {
StackNode **node = vector_get(&self->heads, head_index);
stack_node_release(self, *node);
StackNode *node = *vector_get(&self->heads, head_index);
stack_node_release(self, node);
vector_erase(&self->heads, head_index);
}
@ -288,57 +288,55 @@ void ts_stack_remove_head(Stack *self, int head_index) {
StackPushResult ts_stack_push(Stack *self, int head_index, TSStateId state,
TSTree *tree) {
assert((size_t)head_index < self->heads.size);
assert(tree);
TSLength position = ts_tree_total_size(tree);
StackNode **current_head = vector_get(&self->heads, head_index);
if (*current_head)
position = ts_length_add((*current_head)->entry.position, position);
StackNode *current_head = *vector_get(&self->heads, head_index);
if (current_head)
position = ts_length_add(current_head->entry.position, position);
for (int i = 0; i < head_index; i++) {
StackNode **prior_node = vector_get(&self->heads, i);
StackEntry prior_entry = (*prior_node)->entry;
if (prior_entry.state == state && ts_length_eq(prior_entry.position, position)) {
ts_stack__add_alternative_tree(self, *prior_node, tree);
ts_stack__add_node_successor(self, *prior_node, *current_head);
StackNode *prior_node = self->heads.contents[i];
StackEntry prior_entry = prior_node->entry;
if (prior_entry.state == state &&
ts_length_eq(prior_entry.position, position)) {
ts_stack__add_alternative_tree(self, prior_node, tree);
ts_stack__add_node_successor(self, prior_node, current_head);
ts_stack_remove_head(self, head_index);
return StackPushResultMerged;
}
}
StackNode *new_head = stack_node_new(self, *current_head, state, tree);
StackNode *new_head = stack_node_new(self, current_head, state, tree);
if (!new_head)
return StackPushResultFailed;
stack_node_release(self, *current_head);
vector_set(&self->heads, head_index, &new_head);
stack_node_release(self, current_head);
self->heads.contents[head_index] = new_head;
return StackPushResultContinued;
}
int ts_stack_split(Stack *self, int head_index) {
StackNode **head = vector_get(&self->heads, head_index);
return ts_stack__add_head(self, *head);
StackNode *head = self->heads.contents[head_index];
return ts_stack__add_head(self, head);
}
Vector ts_stack_pop(Stack *self, int head_index, int child_count,
bool count_extra) {
StackPopResultVector ts_stack_pop(Stack *self, int head_index, int child_count,
bool count_extra) {
vector_clear(&self->pop_results);
vector_clear(&self->pop_paths);
StackNode *previous_head = *(StackNode **)vector_get(&self->heads, head_index);
StackNode *previous_head = *vector_get(&self->heads, head_index);
int capacity = (child_count == -1) ? STARTING_TREE_CAPACITY : child_count;
PopPath initial_path = {
.goal_tree_count = child_count,
.node = previous_head,
.trees = vector_new(sizeof(TSTree *)),
.is_shared = false,
};
vector_init(&initial_path.trees);
if (!vector_grow(&initial_path.trees, capacity))
goto error;
if (!vector_push(&self->pop_paths, &initial_path))
if (!vector_push(&self->pop_paths, initial_path))
goto error;
/*
@ -350,7 +348,7 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
all_paths_done = true;
for (size_t i = 0; i < self->pop_paths.size; i++) {
PopPath *path = vector_get(&self->pop_paths, i);
PopPath *path = &self->pop_paths.contents[i];
StackNode *node = path->node;
if (!node || path->trees.size == path->goal_tree_count)
@ -369,23 +367,19 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
* the additional successors.
*/
if (path->is_shared) {
path->trees = vector_copy(&path->trees);
for (size_t j = 0; j < path->trees.size; j++) {
TSTree **tree = vector_get(&path->trees, j);
ts_tree_retain(*tree);
}
path->trees = (TreeVector)vector_copy(&path->trees);
for (size_t j = 0; j < path->trees.size; j++)
ts_tree_retain(path->trees.contents[j]);
path->is_shared = false;
}
ts_tree_retain(node->entry.tree);
if (!vector_push(&path->trees, &node->entry.tree))
if (!vector_push(&path->trees, node->entry.tree))
goto error;
path->node = path->node->successors[0];
PopPath path_copy = *path;
for (int j = 1; j < node->successor_count; j++) {
if (!vector_push(&self->pop_paths, &path_copy))
if (!vector_push(&self->pop_paths, *path))
goto error;
PopPath *next_path = vector_back(&self->pop_paths);
@ -396,7 +390,7 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
}
for (size_t i = 0; i < self->pop_paths.size; i++) {
PopPath *path = vector_get(&self->pop_paths, i);
PopPath *path = &self->pop_paths.contents[i];
if (!path->is_shared)
vector_reverse(&path->trees);
@ -409,7 +403,7 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
if (i == 0) {
stack_node_retain(path->node);
vector_set(&self->heads, head_index, &path->node);
self->heads.contents[head_index] = path->node;
result.head_index = head_index;
} else {
result.head_index = ts_stack__find_head(self, path->node);
@ -420,7 +414,7 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
} else {
bool merged_result = false;
for (size_t j = 0; j < self->pop_results.size; j++) {
StackPopResult *prior_result = vector_get(&self->pop_results, j);
StackPopResult *prior_result = &self->pop_results.contents[j];
if (prior_result->head_index == result.head_index) {
ts_stack__add_alternative_pop_result(self, prior_result, &result);
merged_result = true;
@ -432,7 +426,7 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
}
}
if (!vector_push(&self->pop_results, &result))
if (!vector_push(&self->pop_results, result))
goto error;
}
@ -441,30 +435,29 @@ Vector ts_stack_pop(Stack *self, int head_index, int child_count,
error:
vector_delete(&initial_path.trees);
return vector_new(0);
StackPopResultVector result;
vector_init(&result);
return result;
}
void ts_stack_shrink(Stack *self, int head_index, int count) {
StackNode **head = vector_get(&self->heads, head_index);
StackNode *new_head = *head;
StackNode *head = *vector_get(&self->heads, head_index);
StackNode *new_head = head;
for (int i = 0; i < count; i++) {
if (new_head->successor_count == 0)
break;
new_head = new_head->successors[0];
}
stack_node_retain(new_head);
stack_node_release(self, *head);
vector_set(&self->heads, head_index, new_head);
stack_node_release(self, head);
self->heads.contents[head_index] = new_head;
}
void ts_stack_clear(Stack *self) {
for (size_t i = 0; i < self->heads.size; i++) {
StackNode **head = vector_get(&self->heads, i);
stack_node_release(self, *head);
}
for (size_t i = 0; i < self->heads.size; i++)
stack_node_release(self, self->heads.contents[i]);
vector_clear(&self->heads);
vector_push(&self->heads, &NULL_NODE);
vector_push(&self->heads, NULL);
}
void ts_stack_set_tree_selection_callback(Stack *self, void *payload,
@ -479,12 +472,11 @@ void ts_stack_delete(Stack *self) {
if (self->pop_paths.contents)
vector_delete(&self->pop_paths);
ts_stack_clear(self);
for (size_t i = 0; i < self->node_pool.size; i++) {
StackNode **node = vector_get(&self->node_pool, i);
ts_free(*node);
}
if (self->node_pool.contents)
if (self->node_pool.contents) {
for (size_t i = 0; i < self->node_pool.size; i++)
ts_free(self->node_pool.contents[i]);
vector_delete(&self->node_pool);
}
vector_delete(&self->heads);
ts_free(self);
}