Fix the cycle detection in iterate() and rename push() to append()
Some checks failed
libakstdlib CI Build / cmake_build (push) Failing after 2m40s
Some checks failed
libakstdlib CI Build / cmake_build (push) Failing after 2m40s
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "deps/libakerror"]
|
||||||
|
path = deps/libakerror
|
||||||
|
url = https://source.starfort.tech/andrew/libakerror.git
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(akstdlib LANGUAGES C)
|
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)
|
if(TARGET akerror::akerror)
|
||||||
message(STATUS "FOUND akerror::akerror")
|
message(STATUS "FOUND akerror::akerror")
|
||||||
else()
|
else()
|
||||||
@@ -11,10 +15,14 @@ include(CTest)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL)
|
||||||
|
else()
|
||||||
if(NOT TARGET akerror::akerror)
|
if(NOT TARGET akerror::akerror)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
find_package(akerror REQUIRED)
|
find_package(akerror REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
set(akstdlib_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/akstdlib")
|
set(akstdlib_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/akstdlib")
|
||||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||||
|
|||||||
1
deps/libakerror
vendored
Submodule
1
deps/libakerror
vendored
Submodule
Submodule deps/libakerror added at 4fad0cec59
44
src/stdlib.c
44
src/stdlib.c
@@ -191,7 +191,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2(char *str, size_t len, uint
|
|||||||
SUCCEED_RETURN(e);
|
SUCCEED_RETURN(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_push(aksl_ListNode *list, aksl_ListNode *obj)
|
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_append(aksl_ListNode *list, aksl_ListNode *obj)
|
||||||
{
|
{
|
||||||
PREPARE_ERROR(e);
|
PREPARE_ERROR(e);
|
||||||
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
|
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
|
||||||
@@ -199,19 +199,20 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_push(aksl_ListNode *list, aksl_List
|
|||||||
aksl_ListNode *slow = list;
|
aksl_ListNode *slow = list;
|
||||||
aksl_ListNode *fast = list;
|
aksl_ListNode *fast = list;
|
||||||
aksl_ListNode *tail = list;
|
aksl_ListNode *tail = list;
|
||||||
do {
|
while ( fast != NULL && fast->next != NULL ) {
|
||||||
if ( fast != NULL && fast->next != NULL ) {
|
|
||||||
fast = fast->next->next;
|
|
||||||
}
|
|
||||||
tail = slow;
|
tail = slow;
|
||||||
slow = slow->next;
|
slow = slow->next;
|
||||||
if ( fast != NULL && fast == slow) {
|
fast = fast->next->next;
|
||||||
FAIL(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
|
if ( fast == slow) {
|
||||||
|
FAIL_RETURN(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( fast != NULL ) {
|
||||||
|
tail = fast;
|
||||||
}
|
}
|
||||||
} while ( slow != NULL || (fast != NULL && fast->next != NULL) );
|
|
||||||
tail->next = obj;
|
tail->next = obj;
|
||||||
obj->next = NULL;
|
obj->next = NULL;
|
||||||
obj->prev = slow;
|
obj->prev = tail;
|
||||||
SUCCEED_RETURN(e);
|
SUCCEED_RETURN(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,16 +321,23 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate(aksl_ListNode *list, aksl_L
|
|||||||
FAIL_ZERO_RETURN(e, iter, AKERR_NULLPOINTER, "iter");
|
FAIL_ZERO_RETURN(e, iter, AKERR_NULLPOINTER, "iter");
|
||||||
aksl_ListNode *slow = list;
|
aksl_ListNode *slow = list;
|
||||||
aksl_ListNode *fast = list;
|
aksl_ListNode *fast = list;
|
||||||
aksl_ListNode *tail = list;
|
while ( fast != NULL && fast->next != NULL ) {
|
||||||
do {
|
|
||||||
if ( fast != NULL && fast->next != NULL ) {
|
|
||||||
fast = fast->next->next;
|
|
||||||
}
|
|
||||||
PASS(e, iter(slow, data));
|
|
||||||
slow = slow->next;
|
slow = slow->next;
|
||||||
if ( fast != NULL && fast == slow) {
|
fast = fast->next->next;
|
||||||
FAIL(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
|
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);
|
||||||
}
|
}
|
||||||
} while ( slow != NULL || (fast != NULL && fast->next != NULL) );
|
|
||||||
SUCCEED_RETURN(e);
|
SUCCEED_RETURN(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,74 @@
|
|||||||
|
#include <stdio.h>
|
||||||
#include <akstdlib.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)
|
akerr_ErrorContext AKERR_NOIGNORE *myiter(aksl_ListNode *node, void *data)
|
||||||
{
|
{
|
||||||
|
int count = 0;
|
||||||
PREPARE_ERROR(e);
|
PREPARE_ERROR(e);
|
||||||
int count;
|
|
||||||
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
|
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
|
||||||
FAIL_ZERO_RETURN(e, node->data, AKERR_NULLPOINTER, "node->data");
|
FAIL_ZERO_RETURN(e, node->data, AKERR_NULLPOINTER, "node->data");
|
||||||
// This function doesn't use *data so we don't check it
|
PASS(e, aksl_fprintf(&count, stderr, "Visiting node : %s\n", node->data));
|
||||||
|
SUCCEED_RETURN(e);
|
||||||
|
}
|
||||||
|
|
||||||
PASS(e, aksl_fprintf(&count, stderr, "Visiting node : %s", node->data));
|
// 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);
|
SUCCEED_RETURN(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
PREPARE_ERROR(e);
|
PREPARE_ERROR(e);
|
||||||
|
int idx = 0;
|
||||||
aksl_ListNode mylist;
|
aksl_ListNode mylist;
|
||||||
char *node1str = "Node 1";
|
|
||||||
aksl_ListNode node1;
|
aksl_ListNode node1;
|
||||||
char *node2str = "Node 2";
|
|
||||||
aksl_ListNode node2;
|
aksl_ListNode node2;
|
||||||
|
|
||||||
node1->data = (void *)&node1str;
|
ATTEMPT {
|
||||||
PASS(e, aksl_list_push(&mylist, &node1));
|
memset((void *)&mylist, 0x00, sizeof(aksl_ListNode));
|
||||||
|
memset((void *)&node1, 0x00, sizeof(aksl_ListNode));
|
||||||
|
memset((void *)&node2, 0x00, sizeof(aksl_ListNode));
|
||||||
|
|
||||||
node2->data = (void *)&node2str;
|
mylist.data = "Root";
|
||||||
PASS(e, aksl_list_push(&mylist, &node2));
|
|
||||||
|
|
||||||
PASS(e, aksl_list_iterate(&mylist, &myiter, NULL));
|
node1.data = "Node 1";
|
||||||
|
CATCH(e, aksl_list_append(&mylist, &node1));
|
||||||
|
|
||||||
SUCCEED_RETURN(e);
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user