Add support for tree structures. Search function with DFS, BFS currently unimplemented. Improve linked list handling; fix bug in circular list detection.
This commit is contained in:
145
src/stdlib.c
145
src/stdlib.c
@@ -98,6 +98,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_printf(int *count, const char *restrict
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, count, AKERR_NULLPOINTER, "count=%p, format=%p", (void *)count, (void *)format);
|
||||
FAIL_ZERO_RETURN(e, format, AKERR_NULLPOINTER, "count=%p, format=%p", (void *)count, (void *)format);
|
||||
va_start(args, format);
|
||||
*count = vprintf(format, args);
|
||||
FAIL_NONZERO_RETURN(e, (*count == -1), errno, "Short write");
|
||||
SUCCEED_RETURN(e);
|
||||
@@ -111,6 +112,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fprintf(int *count, FILE *restrict strea
|
||||
FAIL_ZERO_RETURN(e, count, AKERR_NULLPOINTER, "count=%p, stream=%p, format=%p", (void *)count, (void *)stream, (void *)format);
|
||||
FAIL_ZERO_RETURN(e, stream, AKERR_NULLPOINTER, "count=%p, stream=%p, format=%p", (void *)count, (void *)stream, (void *)format);
|
||||
FAIL_ZERO_RETURN(e, format, AKERR_NULLPOINTER, "count=%p, stream=%p, format=%p", (void *)count, (void *)stream, (void *)format);
|
||||
va_start(args, format);
|
||||
*count = vfprintf(stream, format, args);
|
||||
FAIL_NONZERO_RETURN(e, (*count == -1), errno, "Short write");
|
||||
SUCCEED_RETURN(e);
|
||||
@@ -174,3 +176,146 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_realpath(const char *restrict path, char
|
||||
FAIL_ZERO_RETURN(e, result, errno, "path=%s, dest=%s", path, resolved_path);
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_push(aksl_ListNode *list, aksl_ListNode *obj)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
|
||||
FAIL_ZERO_RETURN(e, obj, AKERR_NULLPOINTER, "obj");
|
||||
aksl_ListNode *slow = list;
|
||||
aksl_ListNode *fast = list;
|
||||
aksl_ListNode *tail = list;
|
||||
do {
|
||||
if ( fast != NULL && fast->next != NULL ) {
|
||||
fast = fast->next->next;
|
||||
}
|
||||
tail = slow;
|
||||
slow = slow->next;
|
||||
if ( fast != NULL && fast == slow) {
|
||||
FAIL(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
|
||||
}
|
||||
} while ( slow != NULL || (fast != NULL && fast->next != NULL) );
|
||||
tail->next = obj;
|
||||
obj->next = NULL;
|
||||
obj->prev = slow;
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_pop(aksl_ListNode *node)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
|
||||
if ( node->prev != NULL ) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
if ( node->next != NULL ) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over a tree structure in breadth or depth first order, executing a callback function on each node.
|
||||
*
|
||||
* This function recursively calls itself to traverse a binary tree datastructure.
|
||||
*
|
||||
* @param[in] root The tree structure to search
|
||||
* @param[in] iter An aksl_TreeNodeIterator function which will be called for each node found
|
||||
* @param[in] lalloc An aksl_AllocFunc function which will be used to allocate aksl_ListNode elements for the search, or NULL to use the default allocator (aksl_malloc)
|
||||
* @param[in] lfree An aksl_FreeFunc function which will be used to free the elements procured with lalloc, or NULL to use the default free function (aksl_free)
|
||||
* @param[in] searchmode One of the AKSL_TREE_SEARCH_BFS* defines
|
||||
* @param[in] data Any user data that should be provided when the iterator is called
|
||||
* @param[in] queue The linked list node to use as the head of the queue. The caller should pass NULL here.
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER On null pointer inputs
|
||||
* @return akerr_ErrorContext
|
||||
*/
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_tree_iterate(
|
||||
aksl_TreeNode *root,
|
||||
aksl_TreeNodeIterator iter,
|
||||
aksl_AllocFunc lalloc,
|
||||
aksl_FreeFunc lfree,
|
||||
uint8_t searchmode,
|
||||
void *data,
|
||||
aksl_ListNode *queue)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, root, AKERR_NULLPOINTER, "root");
|
||||
FAIL_ZERO_RETURN(e, iter, AKERR_NULLPOINTER, "iter");
|
||||
if ( lalloc == NULL ) {
|
||||
lalloc = &aksl_malloc;
|
||||
}
|
||||
if ( lfree == NULL ) {
|
||||
lfree = &aksl_free;
|
||||
}
|
||||
switch ( searchmode ) {
|
||||
case AKSL_TREE_SEARCH_DFS_PREORDER:
|
||||
PASS(e, iter(root, data));
|
||||
if ( root->left != NULL ) {
|
||||
PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL));
|
||||
}
|
||||
if ( root-> right != NULL ) {
|
||||
PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL));
|
||||
}
|
||||
break;
|
||||
case AKSL_TREE_SEARCH_DFS_POSTORDER:
|
||||
if ( root->left != NULL ) {
|
||||
PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL));
|
||||
}
|
||||
if ( root-> right != NULL ) {
|
||||
PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL));
|
||||
}
|
||||
PASS(e, iter(root, data));
|
||||
break;
|
||||
case AKSL_TREE_SEARCH_DFS_INORDER:
|
||||
if ( root->left != NULL ) {
|
||||
PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL));
|
||||
}
|
||||
PASS(e, iter(root, data));
|
||||
if ( root-> right != NULL ) {
|
||||
PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL));
|
||||
}
|
||||
break;
|
||||
case AKSL_TREE_SEARCH_BFS:
|
||||
case AKSL_TREE_SEARCH_BFS_RIGHT:
|
||||
FAIL_RETURN(e, AKERR_NOT_IMPLEMENTED, "Searchmode %d", searchmode);
|
||||
break;
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over a linked list and execute a callback function on each node
|
||||
*
|
||||
* @param[in] list The linked list to iterate
|
||||
* @param[in] iter An aksl_ListNodeIterator function which will be called for each node found
|
||||
* @param[in] data Any user data that should be provided when the iterator is called
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer inputs
|
||||
* @throws AKERR_CIRCULAR_REFERENCE when the linked list contains a circular reference
|
||||
*
|
||||
* @return akerr_ErrorContext
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate(aksl_ListNode *list, aksl_ListNodeIterator iter, void *data)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
|
||||
FAIL_ZERO_RETURN(e, iter, AKERR_NULLPOINTER, "iter");
|
||||
aksl_ListNode *slow = list;
|
||||
aksl_ListNode *fast = list;
|
||||
aksl_ListNode *tail = list;
|
||||
do {
|
||||
if ( fast != NULL && fast->next != NULL ) {
|
||||
fast = fast->next->next;
|
||||
}
|
||||
PASS(e, iter(slow, data));
|
||||
slow = slow->next;
|
||||
if ( fast != NULL && fast == slow) {
|
||||
FAIL(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
|
||||
}
|
||||
} while ( slow != NULL || (fast != NULL && fast->next != NULL) );
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user