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:
+98
-9
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user