Compare commits

...

10 Commits

Author SHA1 Message Date
5793f6a178 Add tree search test
Some checks failed
libakstdlib CI Build / cmake_build (push) Failing after 2m41s
2026-06-27 13:13:17 -04:00
57929be1af Fix the cycle detection in iterate() and rename push() to append()
Some checks failed
libakstdlib CI Build / cmake_build (push) Failing after 2m40s
2026-06-27 12:11:27 -04:00
3e3ea41dc8 Add CI build
Some checks failed
libakstdlib CI Build / cmake_build (push) Failing after 2m41s
2026-06-27 10:40:06 -04:00
e4597aef7d Add support for tree structures. Search function with DFS, BFS currently unimplemented. Improve linked list handling; fix bug in circular list detection. 2026-06-27 08:21:13 -04:00
06b2c8ad8a Add a DJB2 string hashing function 2026-06-02 17:11:38 -04:00
485b241595 Added aksl_atof 2026-05-30 10:30:00 -04:00
def4175d0a Fix aksl_sprintf, wasnt properly using va_args 2026-05-24 19:56:55 -04:00
a8108178ee Merge commit '36f161a9cce7b6f460b3884dc825240891b40d5b' 2026-05-24 09:56:54 -04:00
36f161a9cc Added atol, atoi, atoll, and realpath 2026-05-24 09:52:24 -04:00
dda645e188 Fix builds when in a submodule 2026-05-12 21:29:20 -04:00
10 changed files with 3362 additions and 3 deletions

28
.gitea/workflows/ci.yaml Normal file
View File

@@ -0,0 +1,28 @@
name: libakstdlib CI Build
run-name: ${{ gitea.actor }} libakstdlib test
on: [push]
jobs:
cmake_build:
runs-on: ubuntu-latest
steps:
- run: echo "Triggered by ${{ gitea.event_name }} from ${{ gitea.repository }}@${{ gitea.ref }}. Building on ${{ runner.os }}."
- name: Check out repository code
uses: actions/checkout@v4
- name: dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y cmake gcc moreutils
# Depends on libakerror@main
git clone https://source.starfort.tech/andrew/libakerror.git
cd libakerror
cmake -S . -B build
cmake --build build
cmake --install build
- name: build and test
run: |
cmake -S . -B build
cmake --build build
sudo cmake --install build
cmake --build build --target test
- run: echo "🍏 This job's status is ${{ job.status }}."

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "deps/libakerror"]
path = deps/libakerror
url = https://source.starfort.tech/andrew/libakerror.git

View File

@@ -1,11 +1,28 @@
cmake_minimum_required(VERSION 3.10)
project(akstdlib LANGUAGES C)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -pg")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g -ggdb -pg")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -g -ggdb -pg")
if(TARGET akerror::akerror)
message(STATUS "FOUND akerror::akerror")
else()
message(STATUS "MISSING akerror::akerror")
endif()
include(CTest)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL)
else()
if(NOT TARGET akerror::akerror)
find_package(PkgConfig REQUIRED)
find_package(akerror REQUIRED)
endif()
endif()
set(akstdlib_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/akstdlib")
set(prefix ${CMAKE_INSTALL_PREFIX})
@@ -41,7 +58,7 @@ install(FILES "include/akstdlib.h" DESTINATION "include/")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/akstdlib.pc DESTINATION "lib/pkgconfig/")
install(EXPORT akstdlib
install(EXPORT akstdlibTargets
FILE akstdlibTargets.cmake
NAMESPACE akstdlib::
DESTINATION ${akstdlib_install_cmakedir}
@@ -58,4 +75,13 @@ install(FILES
DESTINATION ${akstdlib_install_cmakedir}
)
add_executable(test_linkedlist tests/test_linkedlist.c)
target_link_libraries(test_linkedlist PRIVATE akstdlib)
add_test(NAME linkedlist COMMAND test_linkedlist)
add_executable(test_tree tests/test_tree.c)
target_link_libraries(test_tree PRIVATE akstdlib)
add_test(NAME tree COMMAND test_tree)
# pkgconfig

2863
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# README
![build badge](https://source.starfort.tech/andrew/libakstdlib/actions/workflows/ci.yaml/badge.svg?branch=main)

1
deps/libakerror vendored Submodule

Submodule deps/libakerror added at 4fad0cec59

View File

@@ -5,6 +5,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct aksl_ListNode {
void *data;
struct aksl_ListNode *next;
struct aksl_ListNode *prev;
} aksl_ListNode;
typedef struct aksl_TreeNode {
struct aksl_TreeNode *parent;
struct aksl_TreeNode *left;
struct aksl_TreeNode *right;
void *leaf;
} aksl_TreeNode;
#define AKSL_TREE_SEARCH_BFS 0 /** Breadth-first search mode for tree nodes. Currently unsupported. */
#define AKSL_TREE_SEARCH_BFS_RIGHT 1 /** Right-hand breadth-first search mode for tree nodes. Currentl unsupported. */
#define AKSL_TREE_SEARCH_DFS 2 /** Alias for AKSL_TREE_SEARCH_DFS_PREORDER */
#define AKSL_TREE_SEARCH_DFS_PREORDER 2 /** Depth first pre-order (root, left, right) search mode for tree nodes */
#define AKSL_TREE_SEARCH_DFS_INORDER 3 /** Depth first in-order (left, root, right) search mode for tree nodes. Currently unsupported. */
#define AKSL_TREE_SEARCH_DFS_POSTORDER 4 /** Depth first post-order (left, right, root) search mode for tree nodes. Currently unsupported. */
#define AKSL_TREE_SEARCH_VISIT 5 /** Used when iterating through a tree structure as a control flag: don't traverse the children, just visit the node */
typedef akerr_ErrorContext AKERR_NOIGNORE *(*aksl_ListNodeIterator)(aksl_ListNode *node, void *data);
typedef akerr_ErrorContext AKERR_NOIGNORE *(*aksl_TreeNodeIterator)(aksl_TreeNode *node, void *data);
typedef akerr_ErrorContext AKERR_NOIGNORE *(*aksl_AllocFunc)(size_t size, void **dest);
typedef akerr_ErrorContext AKERR_NOIGNORE *(*aksl_FreeFunc)(void *ptr);
akerr_ErrorContext AKERR_NOIGNORE *aksl_fopen(char *pathname, char *mode, FILE **fp);
akerr_ErrorContext AKERR_NOIGNORE *aksl_fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
@@ -16,10 +43,25 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_memset(void *s, int c, size_t n);
akerr_ErrorContext AKERR_NOIGNORE *aksl_memcpy(void *d, void *s, size_t n);
akerr_ErrorContext AKERR_NOIGNORE *aksl_free(void *ptr);
akerr_ErrorContext AKERR_NOIGNORE *aksl_printf(int *count, const char *restrict format, ...);
akerr_ErrorContext AKERR_NOIGNORE *aksl_fprintf(int *count, FILE *restrict stream, const char *restrict format, ...);
akerr_ErrorContext AKERR_NOIGNORE *aksl_sprintf(int *count, char *restrict str, const char *restrict format, ...);
akerr_ErrorContext AKERR_NOIGNORE *aksl_atoi(const char *nptr, int *dest);
akerr_ErrorContext AKERR_NOIGNORE *aksl_atol(const char *nptr, long *dest);
akerr_ErrorContext AKERR_NOIGNORE *aksl_atoll(const char *nptr, long long *dest);
akerr_ErrorContext AKERR_NOIGNORE *aksl_atof(const char *nptr, double *dest);
akerr_ErrorContext AKERR_NOIGNORE *aksl_realpath(const char *restrict path, char *restrict resolved_path);
akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2(char *str, size_t len, uint32_t *hashval);
// Linked list functions
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_append(aksl_ListNode *list, aksl_ListNode *obj);
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_pop(aksl_ListNode *node);
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate(aksl_ListNode *list, aksl_ListNodeIterator iter, void *data);
// Tree functions
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);
#endif

View File

@@ -3,6 +3,8 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
akerr_ErrorContext AKERR_NOIGNORE *aksl_malloc(size_t size, void **dst)
{
@@ -97,6 +99,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);
@@ -110,6 +113,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);
@@ -122,7 +126,225 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_sprintf(int *count, char *restrict str,
FAIL_ZERO_RETURN(e, count, AKERR_NULLPOINTER, "count=%p, str=%p, format=%p", (void *)count, (void *)str, (void *)format);
FAIL_ZERO_RETURN(e, str, AKERR_NULLPOINTER, "count=%p, str=%p, format=%p", (void *)count, (void *)str, (void *)format);
FAIL_ZERO_RETURN(e, format, AKERR_NULLPOINTER, "count=%p, str=%p, format=%p", (void *)count, (void *)str, (void *)format);
va_start(args, format);
*count = vsprintf(str, format, args);
FAIL_NONZERO_RETURN(e, (*count == -1), errno, "Short write");
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_atoi(const char *nptr, int *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atoi(nptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_atol(const char *nptr, long *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atol(nptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_atoll(const char *nptr, long long *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atoll(nptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_atof(const char *nptr, double *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atof(nptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_realpath(const char *restrict path, char *restrict resolved_path)
{
char *result = NULL;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "path=%p, dest=%p", (void *)path, (void *)resolved_path);
result = realpath(path, resolved_path);
FAIL_ZERO_RETURN(e, result, errno, "path=%s, dest=%s", path, resolved_path);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2(char *str, size_t len, uint32_t *hashval)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, str, AKERR_NULLPOINTER, "str");
FAIL_ZERO_RETURN(e, hashval, AKERR_NULLPOINTER, "hashval");
uint32_t h = 5381;
while (len--) {
h = ((h << 5) + h) + *str++;
}
*hashval = h;
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_append(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;
while ( fast != NULL && fast->next != NULL ) {
tail = slow;
slow = slow->next;
fast = fast->next->next;
if ( fast == slow) {
FAIL_RETURN(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
}
}
if ( fast != NULL ) {
tail = fast;
}
tail->next = obj;
obj->next = NULL;
obj->prev = tail;
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;
}
ATTEMPT {
switch ( searchmode ) {
case AKSL_TREE_SEARCH_DFS_PREORDER:
CATCH(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));
}
CATCH(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));
}
CATCH(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;
}
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_ITERATOR_BREAK) {
// This is not an error condition, it's just telling us to stop early
SUCCEED_RETURN(e);
} FINISH(e, true);
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;
while ( fast != NULL && fast->next != NULL ) {
slow = slow->next;
fast = fast->next->next;
if ( fast == slow) {
FAIL_RETURN(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
}
}
while ( slow != NULL ) {
ATTEMPT {
CATCH(e, iter(slow, data));
slow = slow->next;
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_ITERATOR_BREAK) {
// This is not an error condition, it's just telling us to stop early
SUCCEED_RETURN(e);
} FINISH(e, true);
}
SUCCEED_RETURN(e);
}

75
tests/test_linkedlist.c Normal file
View File

@@ -0,0 +1,75 @@
#include <stdio.h>
#include <akstdlib.h>
// This iterator does nothing but print the node names it is visiting
akerr_ErrorContext AKERR_NOIGNORE *myiter(aksl_ListNode *node, void *data)
{
int count = 0;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
FAIL_ZERO_RETURN(e, node->data, AKERR_NULLPOINTER, "node->data");
PASS(e, aksl_fprintf(&count, stderr, "Visiting node : %s\n", node->data));
SUCCEED_RETURN(e);
}
// This iterator function exits early once the index in `(int *)data` is reached
akerr_ErrorContext AKERR_NOIGNORE *myiter_earlyhalt(aksl_ListNode *node, void *data)
{
int *idx;
int count = 0;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
FAIL_ZERO_RETURN(e, node->data, AKERR_NULLPOINTER, "node->data");
FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data");
idx = (int *)data;
if ( *idx == 1 ) {
// This exception is eaten by the iterator, we will never see it
FAIL_RETURN(e, AKERR_ITERATOR_BREAK, "stop");
}
*idx += 1;
SUCCEED_RETURN(e);
}
int main(void)
{
PREPARE_ERROR(e);
int idx = 0;
int count = 0;
aksl_ListNode mylist;
aksl_ListNode node1;
aksl_ListNode node2;
ATTEMPT {
memset((void *)&mylist, 0x00, sizeof(aksl_ListNode));
memset((void *)&node1, 0x00, sizeof(aksl_ListNode));
memset((void *)&node2, 0x00, sizeof(aksl_ListNode));
mylist.data = "Root";
node1.data = "Node 1";
CATCH(e, aksl_list_append(&mylist, &node1));
node2.data = "Node 2";
CATCH(e, aksl_list_append(&mylist, &node2));
// Iterate over all nodes in the list using the myiter() function
CATCH(e, aksl_list_iterate(&mylist, &myiter, NULL));
// Iterate over up to the first 2 nodes in the list and then exit early
idx = 0;
CATCH(e, aksl_list_iterate(&mylist, &myiter_earlyhalt, &idx));
CATCH(e, aksl_fprintf(&count, stderr, "Iterator exited early at index %d\n", idx));
// Break the list with a circular reference, and iterate it again
node2.next = &mylist;
CATCH(e, aksl_list_iterate(&mylist, &myiter, NULL));
} CLEANUP {
} PROCESS(e) {
} HANDLE(e, AKERR_CIRCULAR_REFERENCE) {
fprintf(stderr, "Circular reference error caught\n");
} FINISH_NORETURN(e);
return 0;
}

96
tests/test_tree.c Normal file
View File

@@ -0,0 +1,96 @@
#include <stdio.h>
#include <akstdlib.h>
#define MAX_LEAVES 7
typedef struct TreeSearchParams
{
void *value;
int steps;
aksl_TreeNode *node;
} TreeSearchParams;
// This iterator does nothing but print the node names it is visiting
akerr_ErrorContext AKERR_NOIGNORE *myiter(aksl_TreeNode *node, void *data)
{
int count = 0;
TreeSearchParams *parms = NULL;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data");
parms = (TreeSearchParams *)data;
parms->steps += 1;
if ( node->leaf == parms->value ) {
parms->node = node;
FAIL_RETURN(e, AKERR_ITERATOR_BREAK, "stop");
}
SUCCEED_RETURN(e);
}
int main(void)
{
PREPARE_ERROR(e);
aksl_TreeNode tree[MAX_LEAVES];
TreeSearchParams parms = {
.value = (void *)17336,
.steps = 0,
.node = NULL
};
ATTEMPT {
memset((void *)&tree, 0x00, sizeof(aksl_TreeNode) * MAX_LEAVES);
/*
* Here we build a 3 level tree
*
* LEFT RIGHT
* TREE[0]
* +--------^^---------+
* | |
* TREE[1] TREE[2]
* +---^^---+ +---^^---+
* | | | |
*TREE[3] TREE[4] TREE[5] TREE[6]
*/
tree[0].left = &tree[1];
tree[0].right = &tree[2];
tree[1].left = &tree[3];
tree[1].right = &tree[4];
tree[2].left = &tree[5];
tree[2].right = &tree[6];
// Hide a value in tree[6]
tree[6].leaf = (void *)17336;
// Search for the value 17336 using DFS_PREORDER
CATCH(e, aksl_tree_iterate(&tree[0], &myiter, NULL, NULL, AKSL_TREE_SEARCH_DFS_PREORDER, &parms, NULL));
if ( parms.node != &tree[6] ) {
FAIL_BREAK(e, AKERR_API, "DFS_PREORDER_SEARCH didn't find the node");
}
if ( parms.steps != 7 ) {
FAIL_BREAK(e, AKERR_API, "DFS_PREORDER_SEARCH should've found the node in 7 steps, instead took %d", parms.steps);
}
// Search for the value 17336 using DFS_INORDER
CATCH(e, aksl_tree_iterate(&tree[0], &myiter, NULL, NULL, AKSL_TREE_SEARCH_DFS_INORDER, &parms, NULL));
if ( parms.node != &tree[6] ) {
FAIL_BREAK(e, AKERR_API, "DFS_INORDER_SEARCH didn't find the node");
}
if ( parms.steps != 7 ) {
FAIL_BREAK(e, AKERR_API, "DFS_INORDER_SEARCH should've found the node in 7 steps, instead took %d", parms.steps);
}
// Search for the value 17336 using DFS_PREORDER
CATCH(e, aksl_tree_iterate(&tree[0], &myiter, NULL, NULL, AKSL_TREE_SEARCH_DFS_POSTORDER, &parms, NULL));
if ( parms.node != &tree[6] ) {
FAIL_BREAK(e, AKERR_API, "DFS_POSTORDER_SEARCH didn't find the node");
}
if ( parms.steps != 7 ) {
FAIL_BREAK(e, AKERR_API, "DFS_POSTORDER_SEARCH should've found the node in 7 steps, instead took %d", parms.steps);
}
} CLEANUP {
} PROCESS(e) {
} FINISH_NORETURN(e);
return 0;
}