Write singly linked list including test cases
This commit is contained in:
parent
7570251185
commit
45bb5399f0
@ -1,4 +1,85 @@
|
|||||||
#ifndef _SINGLY_LINKED_LIST_H_
|
#ifndef _SINGLY_LINKED_LIST_H_
|
||||||
#define _SINGLY_LINKED_LIST_H_
|
#define _SINGLY_LINKED_LIST_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct singly_linked_list SlList;
|
||||||
|
|
||||||
|
struct singly_linked_list {
|
||||||
|
void *data; /**< @brief Pointer to the data */
|
||||||
|
SlList *next; /**< @brief Pointer to next element */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define sl_list_next(sll) ((sll)->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append element to list
|
||||||
|
* @param list List to append to. May be NULL
|
||||||
|
* @param data data to stor ein the element
|
||||||
|
* @return New Head of list. Store this.
|
||||||
|
*/
|
||||||
|
SlList *sl_list_append(SlList *list, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepend an element to list
|
||||||
|
* @param list List to prepend data. May be NULL
|
||||||
|
* @param data Data to store
|
||||||
|
* @return New head of list. Store this
|
||||||
|
*/
|
||||||
|
SlList *sl_list_prepend(SlList *list, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert element into list at position.
|
||||||
|
*
|
||||||
|
* If the position is larger than the list's size,
|
||||||
|
* the element is appended at the end.
|
||||||
|
*
|
||||||
|
* @param list List to insert
|
||||||
|
* @param position Position (0 based. 0 equals head)
|
||||||
|
* @param data Data to append
|
||||||
|
* @return New list head
|
||||||
|
*/
|
||||||
|
SlList *sl_list_insert(SlList *list, uint32_t position, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove an elemnt from the list
|
||||||
|
*
|
||||||
|
* If the elemnt is not found, nothing is removed.
|
||||||
|
* If multiple elments contain this datum, only the first is rmeoved.
|
||||||
|
*
|
||||||
|
* @param list List ot remove from
|
||||||
|
* @param data Pointer to remove.
|
||||||
|
* @return New list head
|
||||||
|
*/
|
||||||
|
SlList *sl_list_remove(SlList *list, const void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free a SlList
|
||||||
|
* @param list List to free
|
||||||
|
* @warning This function does not deallocate the data stored. Use @ref sl_list_free_full for that.
|
||||||
|
*/
|
||||||
|
void sl_list_free(SlList *list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free a list including its data items
|
||||||
|
* @param list List to fully free
|
||||||
|
* @param destroy_element Destruction function for the data items
|
||||||
|
*/
|
||||||
|
void sl_list_free_full(SlList *list, void (*destroy_element)(void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get Length of list
|
||||||
|
* @param list List
|
||||||
|
* @return Length of list
|
||||||
|
*/
|
||||||
|
uint32_t sl_list_length(SlList *list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get nth element in list.
|
||||||
|
* @param list List
|
||||||
|
* @param n Position of element
|
||||||
|
* @return nth Element or NULL in case list is to short.
|
||||||
|
*/
|
||||||
|
SlList *sl_list_nth(SlList *list, uint32_t n);
|
||||||
|
|
||||||
#endif /* _SINGLY_LINKED_LIST_H_ */
|
#endif /* _SINGLY_LINKED_LIST_H_ */
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
#include <linklist-lib/singly-linked-list.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static SlList *sl_list_alloc()
|
||||||
|
{
|
||||||
|
return (SlList *)malloc(sizeof(SlList));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_list_dealloc(SlList *list)
|
||||||
|
{
|
||||||
|
if (list)
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
SlList *sl_list_append(SlList *list, void *data)
|
||||||
|
{
|
||||||
|
SlList *new_element;
|
||||||
|
SlList **next_iter;
|
||||||
|
|
||||||
|
/* Allocate new element for data */
|
||||||
|
new_element = sl_list_alloc();
|
||||||
|
new_element->data = data;
|
||||||
|
new_element->next = NULL;
|
||||||
|
|
||||||
|
for (next_iter = &list; *next_iter; next_iter = &(*next_iter)->next);
|
||||||
|
|
||||||
|
*next_iter = new_element;
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlList *sl_list_prepend(SlList *list, void *data)
|
||||||
|
{
|
||||||
|
SlList *new_element;
|
||||||
|
|
||||||
|
/* Allocate new element for data */
|
||||||
|
new_element = sl_list_alloc();
|
||||||
|
new_element->data = data;
|
||||||
|
new_element->next = list;
|
||||||
|
|
||||||
|
return new_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlList *sl_list_insert(SlList *list, uint32_t position, void *data)
|
||||||
|
{
|
||||||
|
uint32_t idx;
|
||||||
|
SlList *new_element;
|
||||||
|
SlList **next_iter;
|
||||||
|
|
||||||
|
new_element = sl_list_alloc();
|
||||||
|
new_element->data = data;
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
for (next_iter = &list; next_iter; next_iter = &(*next_iter)->next) {
|
||||||
|
if (idx == position || !*next_iter) {
|
||||||
|
new_element->next = *next_iter;
|
||||||
|
*next_iter = new_element;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlList *sl_list_remove(SlList *list, const void *data)
|
||||||
|
{
|
||||||
|
SlList **next_iter;
|
||||||
|
SlList *tmp;
|
||||||
|
|
||||||
|
for (next_iter = &list; next_iter; next_iter = &(*next_iter)->next) {
|
||||||
|
if (*next_iter == NULL)
|
||||||
|
break;
|
||||||
|
if ((*next_iter)->data == data) {
|
||||||
|
tmp = (*next_iter)->next;
|
||||||
|
sl_list_dealloc(*next_iter);
|
||||||
|
*next_iter = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sl_list_free(SlList *list)
|
||||||
|
{
|
||||||
|
sl_list_free_full(list, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sl_list_free_full(SlList *list, void (*destroy_element)(void *))
|
||||||
|
{
|
||||||
|
SlList *next;
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
next = list->next;
|
||||||
|
if (destroy_element)
|
||||||
|
destroy_element(list->data);
|
||||||
|
sl_list_dealloc(list);
|
||||||
|
list = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sl_list_length(SlList *list)
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
for (; list; list = sl_list_next(list))
|
||||||
|
count++;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlList *sl_list_nth(SlList *list, uint32_t n)
|
||||||
|
{
|
||||||
|
uint32_t idx;
|
||||||
|
SlList *ret = NULL;
|
||||||
|
|
||||||
|
for (idx = 0; list; list = sl_list_next(list), idx++) {
|
||||||
|
if (n == idx) {
|
||||||
|
ret = list;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
project(base64-test)
|
project(linklist-lib-test)
|
||||||
|
|
||||||
add_custom_target(test "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}" "-r compact" "-s" DEPENDS ${PROJECT_NAME})
|
add_custom_target(test "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}" "-r compact" "-s" DEPENDS ${PROJECT_NAME})
|
||||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/catch-framework")
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/catch-framework")
|
||||||
aux_source_directory("src" TEST_SOURCES)
|
aux_source_directory("src" TEST_SOURCES)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${TEST_SOURCES})
|
add_executable(${PROJECT_NAME} ${TEST_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME} base64-lib)
|
target_link_libraries(${PROJECT_NAME} linklist-lib)
|
||||||
|
|
||||||
|
@ -2,3 +2,255 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <linklist-lib/singly-linked-list.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Append first element", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (void *)0x1234;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Append second element", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (void *)0x1234;
|
||||||
|
void *ptr2 = (void *)0x585796;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr2);
|
||||||
|
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
REQUIRE(list->next != NULL);
|
||||||
|
REQUIRE(list->next->data == ptr2);
|
||||||
|
|
||||||
|
if (list->next)
|
||||||
|
free(list->next);
|
||||||
|
if (list)
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Prepend element", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (void *)0x12345;
|
||||||
|
|
||||||
|
list = sl_list_prepend(list, ptr);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
if (list)
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Prepend second element", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (void *)0x12345;
|
||||||
|
void *ptr2 = (void *)0x1AA45;
|
||||||
|
SlList *list_backup;
|
||||||
|
|
||||||
|
list = sl_list_prepend(list, ptr);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
list_backup = list;
|
||||||
|
|
||||||
|
list = sl_list_prepend(list, ptr2);
|
||||||
|
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next == list_backup);
|
||||||
|
REQUIRE(list->data == ptr2);
|
||||||
|
|
||||||
|
if (list->next)
|
||||||
|
free(list->next);
|
||||||
|
if (list)
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Insert element empty list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (void *)0xAABB;
|
||||||
|
|
||||||
|
list = sl_list_insert(list, 0, ptr);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Insert element at beginning of list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAABB;
|
||||||
|
void *ptr2 = (void *)0x454;
|
||||||
|
|
||||||
|
list = sl_list_insert(list, 0, ptr);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
|
||||||
|
|
||||||
|
list = sl_list_insert(list, 0, ptr2);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next != NULL);
|
||||||
|
REQUIRE(list->data == ptr2);
|
||||||
|
REQUIRE(list->next->data == ptr);
|
||||||
|
REQUIRE(list->next->next == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Insert element at second position of list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAABB;
|
||||||
|
void *ptr2 = (void *)0x454;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
|
||||||
|
list = sl_list_insert(list, 1, ptr2);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next != NULL);
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
REQUIRE(list->next->data == ptr2);
|
||||||
|
REQUIRE(list->data == ptr);
|
||||||
|
REQUIRE(list->next->next != NULL);
|
||||||
|
REQUIRE(list->next->next->data == ptr);
|
||||||
|
REQUIRE(list->next->next->next == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Insert element at overflow position of list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAABB;
|
||||||
|
void *ptr2 = (void *)0x454;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
|
||||||
|
list = sl_list_insert(list, 300, ptr2);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next != NULL);
|
||||||
|
REQUIRE(list->next->next != NULL);
|
||||||
|
REQUIRE(list->next->next->data == ptr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Remove 1st element of empty list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
|
||||||
|
list = sl_list_remove(list, (void *)0x0);
|
||||||
|
REQUIRE(list == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Remove 1st element of list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAAB54B;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
|
||||||
|
list = sl_list_remove(list, (void *)0x0);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
|
||||||
|
list = sl_list_remove(list, ptr);
|
||||||
|
REQUIRE(list == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Remove 2nd element of list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAAB54B;
|
||||||
|
void *ptr2 = (char *)0xAA23B54B;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
list = sl_list_append(list, ptr2);
|
||||||
|
|
||||||
|
list = sl_list_remove(list, (void *)0x0);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next != NULL);
|
||||||
|
|
||||||
|
list = sl_list_remove(list, ptr2);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Remove 4th element of list", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAAB54B;
|
||||||
|
void *ptr2 = (char *)0xAA23B54B;
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
list = sl_list_append(list, ptr2);
|
||||||
|
|
||||||
|
list = sl_list_remove(list, (void *)0x0);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next != NULL);
|
||||||
|
|
||||||
|
list = sl_list_remove(list, ptr2);
|
||||||
|
REQUIRE(list != NULL);
|
||||||
|
REQUIRE(list->next->next->next == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("List length", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAAB54B;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
len = sl_list_length(list);
|
||||||
|
REQUIRE(len == 0);
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
len = sl_list_length(list);
|
||||||
|
REQUIRE(len == 1);
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
len = sl_list_length(list);
|
||||||
|
REQUIRE(len == 2);
|
||||||
|
|
||||||
|
list = sl_list_prepend(list, ptr);
|
||||||
|
len = sl_list_length(list);
|
||||||
|
REQUIRE(len == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nth element", "[SLL]")
|
||||||
|
{
|
||||||
|
SlList *list = NULL;
|
||||||
|
void *ptr = (char *)0xAAB54B;
|
||||||
|
SlList *nth;
|
||||||
|
|
||||||
|
nth = sl_list_nth(list, 0);
|
||||||
|
REQUIRE(nth == NULL);
|
||||||
|
nth = sl_list_nth(list, 1);
|
||||||
|
REQUIRE(nth == NULL);
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
nth = sl_list_nth(list, 0);
|
||||||
|
REQUIRE(nth == list);
|
||||||
|
nth = sl_list_nth(list, 1);
|
||||||
|
REQUIRE(nth == NULL);
|
||||||
|
|
||||||
|
list = sl_list_append(list, ptr);
|
||||||
|
nth = sl_list_nth(list, 0);
|
||||||
|
REQUIRE(nth == list);
|
||||||
|
nth = sl_list_nth(list, 1);
|
||||||
|
REQUIRE(nth == list->next);
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user