Add list_swap() and list_insert() functions (#232)

* Add list_swap() and list_insert() functions

* Update docs for list_swap

* Add test case and fix list insert bug

* Fix silly bug with list length on insertion

* Initial changes for pr

* Add reverse iterator and update test for it

* Cleanup iterator next function

* update tests to cover list_get_at_idx
This commit is contained in:
Rickey
2025-11-18 18:19:00 -08:00
committed by GitHub
parent a4caa44580
commit 47b1bac31f
3 changed files with 563 additions and 17 deletions
+98 -9
View File
@@ -1,5 +1,4 @@
#include <stdbool.h>
#include <stdint.h>
#include "list.h"
#include "pool.h"
@@ -100,6 +99,81 @@ void list_push_back(List *list, void* data)
list->len++;
}
void list_insert(List* list, void* data, unsigned int idx)
{
if(idx >= list->len)
{
list_push_back(list, data);
return;
}
if(idx == 0)
{
list_push_front(list, data);
return;
}
// After the above two checks the index is guaranteed to be inbetween the
// `head` and `tail` of the `list`. This means the actual list doesn't need
// to modify it's head and tail, only it's length. Simplifying the code below:
unsigned int curr_idx = 0;
ListItr itr = list_itr_create(list);
ListNode* ln;
while((ln = _list_itr_node_next(&itr)))
{
if(idx == curr_idx++)
{
ListNode *node = POOL_GET(ListNode);
node->prev = ln->prev;
node->next = ln;
ln->prev->next = node;
ln->prev = node;
node->data = data;
list->len++;
return;
}
}
}
bool list_swap(List* list, unsigned int idx_a, unsigned int idx_b)
{
if(idx_a >= list->len || idx_b >= list->len) return false;
if(idx_a == idx_b) return true; // swapping with yourself isn't technically an error
unsigned int curr_idx = 0;
unsigned int max_idx = idx_a > idx_b ? idx_a : idx_b;
ListNode* node_a = NULL;
ListNode* node_b = NULL;
ListItr itr = list_itr_create(list);
ListNode* ln;
do
{
ln = _list_itr_node_next(&itr);
if(idx_a == curr_idx)
{
node_a = ln;
continue;
}
if(idx_b == curr_idx)
{
node_b = ln;
continue;
}
}
while(max_idx != curr_idx++);
// Just swap the data pointers
void* tmp = node_a->data;
node_a->data = node_b->data;
node_b->data = tmp;
return true;
}
static void _list_remove_node(List *list, ListNode *node)
{
if(node->prev && !node->next) // end of list
@@ -133,9 +207,9 @@ int list_get_len(const List* list)
return list->len;
}
void* list_get_at_idx(List* list, int n)
void* list_get_at_idx(List* list, unsigned int idx)
{
if(n >= list_get_len(list) || n < 0) return NULL;
if(idx >= list_get_len(list)) return NULL;
int curr_idx = 0;
ListItr itr = list_itr_create(list);
@@ -143,15 +217,15 @@ void* list_get_at_idx(List* list, int n)
while((data = list_itr_next(&itr)))
{
if (n == curr_idx++) return data;
if (idx == curr_idx++) return data;
}
return NULL;
}
bool list_remove_at_idx(List* list, int n)
bool list_remove_at_idx(List* list, unsigned int idx)
{
if(n >= list_get_len(list) || n < 0) return false;
if(idx >= list_get_len(list)) return false;
int len = 0;
ListItr itr = list_itr_create(list);
@@ -159,7 +233,7 @@ bool list_remove_at_idx(List* list, int n)
while((ln = _list_itr_node_next(&itr)))
{
if(n == len++)
if(idx == len++)
{
_list_remove_node(list, ln);
return true;
@@ -175,6 +249,20 @@ ListItr list_itr_create(List* list)
.list = list,
.next_node = !list_is_empty(list) ? list->head : NULL,
.current_node = NULL,
.direction = LIST_ITR_FORWARD,
};
return itr;
}
ListItr rev_list_itr_create(List* list)
{
ListItr itr =
{
.list = list,
.next_node = !list_is_empty(list) ? list->tail : NULL,
.current_node = NULL,
.direction = LIST_ITR_REVERSE,
};
return itr;
@@ -193,10 +281,11 @@ static ListNode* _list_itr_node_next(ListItr* itr)
itr->current_node = itr->next_node;
ListNode* ln = itr->next_node;
ListNode* next_itr_node = (itr->direction == LIST_ITR_FORWARD) ? ln->next : ln->prev;
if(ln->next)
if(next_itr_node)
{
itr->next_node = ln->next;
itr->next_node = next_itr_node;
return ln;
}