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:
+82
-8
@@ -59,6 +59,15 @@ typedef struct List
|
|||||||
int len;
|
int len;
|
||||||
} List;
|
} List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @ref ListItr direction
|
||||||
|
*/
|
||||||
|
enum ListItrDirection
|
||||||
|
{
|
||||||
|
LIST_ITR_FORWARD,
|
||||||
|
LIST_ITR_REVERSE,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief An iterator into a list
|
* @brief An iterator into a list
|
||||||
*/
|
*/
|
||||||
@@ -80,6 +89,11 @@ typedef struct
|
|||||||
* The node of the most recently returned data from @ref list_itr_next() .
|
* The node of the most recently returned data from @ref list_itr_next() .
|
||||||
*/
|
*/
|
||||||
ListNode* current_node;
|
ListNode* current_node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The direction of the iterator
|
||||||
|
*/
|
||||||
|
enum ListItrDirection direction;
|
||||||
} ListItr;
|
} ListItr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,24 +142,75 @@ void list_push_front(List* list, void* data);
|
|||||||
void list_push_back(List* list, void* data);
|
void list_push_back(List* list, void* data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a List's node at it's nth index
|
* Insert data into a @ref List a specific index
|
||||||
|
*
|
||||||
|
* If the index specified is larger than the length of the list
|
||||||
|
* it will @ref list_push_back() the data instead;
|
||||||
|
*
|
||||||
|
* Performs the following operation:
|
||||||
|
*
|
||||||
|
* ┌─────┐
|
||||||
|
* │ node│
|
||||||
|
* └─────┘
|
||||||
|
* ┌─────┐ ┌─────┐ ┌─────┐
|
||||||
|
* │idx-1│◄─►│ idx │◄─►│idx+1│
|
||||||
|
* └─────┘ └─────┘ └─────┘
|
||||||
|
*
|
||||||
|
* 1. Set new `node` `prev` to the node at idx - 1
|
||||||
|
* 2. Set new `node` `next` to the node at idx
|
||||||
|
* 3. Set node at idx - 1 `next` to new `node`
|
||||||
|
* 4. Set node at idx `prev` to the new `node`
|
||||||
|
*
|
||||||
|
* Result:
|
||||||
|
*
|
||||||
|
* ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
|
||||||
|
* │idx-1│◄─►│ node│◄─►│ idx │◄─►│idx+1│
|
||||||
|
* └─────┘ └─────┘ └─────┘ └─────┘
|
||||||
|
*
|
||||||
|
* Finally, the list is now updated with new `node` now at the labeled idx:
|
||||||
|
*
|
||||||
|
* ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
|
||||||
|
* │idx-1│◄─►│ idx │◄─►│idx+1│◄─►│idx+2│
|
||||||
|
* └─────┘ └─────┘ └─────┘ └─────┘
|
||||||
*
|
*
|
||||||
* @param list pointer to a @ref List
|
* @param list pointer to a @ref List
|
||||||
* @param n index of the desired @ref ListNode in the list
|
* @param data pointer to data to put into the @ref List
|
||||||
*
|
* @param idx desired index to insert
|
||||||
* @return a pointer to the data at the nth @ref ListNode, or NULL if out-of-bounds
|
|
||||||
*/
|
*/
|
||||||
void* list_get_at_idx(List *list, int n);
|
void list_insert(List* list, void* data, unsigned int idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a List's node at it's nth index
|
* Swap the data pointers at the specified indices of a @ref List
|
||||||
|
*
|
||||||
|
* If either indices are larger than the length of the list, return false.
|
||||||
*
|
*
|
||||||
* @param list pointer to a @ref List
|
* @param list pointer to a @ref List
|
||||||
* @param n index of the desired @ref ListNode in the list
|
* @param idx_a desired index to swap with idx_b
|
||||||
|
* @param idx_b desired index to swap with idx_a
|
||||||
|
*
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
bool list_swap(List* list, unsigned int idx_a, unsigned int idx_b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a List's node at the specified index
|
||||||
|
*
|
||||||
|
* @param list pointer to a @ref List
|
||||||
|
* @param idx index of the desired @ref ListNode in the list
|
||||||
|
*
|
||||||
|
* @return a pointer to the data at the index of the list, or NULL if out-of-bounds
|
||||||
|
*/
|
||||||
|
void* list_get_at_idx(List *list, unsigned int idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a List's node at the specified index
|
||||||
|
*
|
||||||
|
* @param list pointer to a @ref List
|
||||||
|
* @param idx index of the desired @ref ListNode in the list
|
||||||
*
|
*
|
||||||
* @return `true` if successfully removed, `false` if out-of-bounds
|
* @return `true` if successfully removed, `false` if out-of-bounds
|
||||||
*/
|
*/
|
||||||
bool list_remove_at_idx(List *list, int n);
|
bool list_remove_at_idx(List *list, unsigned int idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of elements in a @ref List
|
* Get the number of elements in a @ref List
|
||||||
@@ -165,6 +230,15 @@ int list_get_len(const List* list);
|
|||||||
*/
|
*/
|
||||||
ListItr list_itr_create(List* list);
|
ListItr list_itr_create(List* list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare a reverse @ref ListItr
|
||||||
|
*
|
||||||
|
* @param list pointer to a @ref List
|
||||||
|
*
|
||||||
|
* @return A new reverse @ref ListItr
|
||||||
|
*/
|
||||||
|
ListItr rev_list_itr_create(List* list);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next data entry in a @ref ListItr
|
* Get the next data entry in a @ref ListItr
|
||||||
*
|
*
|
||||||
|
|||||||
+98
-9
@@ -1,5 +1,4 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
|
|
||||||
@@ -100,6 +99,81 @@ void list_push_back(List *list, void* data)
|
|||||||
list->len++;
|
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)
|
static void _list_remove_node(List *list, ListNode *node)
|
||||||
{
|
{
|
||||||
if(node->prev && !node->next) // end of list
|
if(node->prev && !node->next) // end of list
|
||||||
@@ -133,9 +207,9 @@ int list_get_len(const List* list)
|
|||||||
return list->len;
|
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;
|
int curr_idx = 0;
|
||||||
ListItr itr = list_itr_create(list);
|
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)))
|
while((data = list_itr_next(&itr)))
|
||||||
{
|
{
|
||||||
if (n == curr_idx++) return data;
|
if (idx == curr_idx++) return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
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;
|
int len = 0;
|
||||||
ListItr itr = list_itr_create(list);
|
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)))
|
while((ln = _list_itr_node_next(&itr)))
|
||||||
{
|
{
|
||||||
if(n == len++)
|
if(idx == len++)
|
||||||
{
|
{
|
||||||
_list_remove_node(list, ln);
|
_list_remove_node(list, ln);
|
||||||
return true;
|
return true;
|
||||||
@@ -175,6 +249,20 @@ ListItr list_itr_create(List* list)
|
|||||||
.list = list,
|
.list = list,
|
||||||
.next_node = !list_is_empty(list) ? list->head : NULL,
|
.next_node = !list_is_empty(list) ? list->head : NULL,
|
||||||
.current_node = 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;
|
return itr;
|
||||||
@@ -193,10 +281,11 @@ static ListNode* _list_itr_node_next(ListItr* itr)
|
|||||||
itr->current_node = itr->next_node;
|
itr->current_node = itr->next_node;
|
||||||
|
|
||||||
ListNode* ln = 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;
|
return ln;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -286,6 +286,382 @@ void push_back_three_remove_push_front_three_entries(void)
|
|||||||
assert(list_is_empty(&my_cool_list));
|
assert(list_is_empty(&my_cool_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test inserting at head, middle, and tail of list
|
||||||
|
// - list_create
|
||||||
|
// - list_push_back
|
||||||
|
// - list_insert
|
||||||
|
// - list_is_empty
|
||||||
|
// - list_get_len
|
||||||
|
// - list_itr_create
|
||||||
|
// - rev_list_itr_create
|
||||||
|
// - list_itr_next
|
||||||
|
// - list_clear
|
||||||
|
// - list_get_at_idx
|
||||||
|
void test_list_insertion(void)
|
||||||
|
{
|
||||||
|
List my_cool_list = list_create();
|
||||||
|
|
||||||
|
// verify no data
|
||||||
|
assert(my_cool_list.head == NULL);
|
||||||
|
assert(my_cool_list.tail == NULL);
|
||||||
|
assert(list_get_len(&my_cool_list) == 0);
|
||||||
|
assert(list_is_empty(&my_cool_list));
|
||||||
|
|
||||||
|
const int initial_list_size = 5;
|
||||||
|
int test_data[initial_list_size];
|
||||||
|
|
||||||
|
for(int i = 0; i < initial_list_size; i++)
|
||||||
|
{
|
||||||
|
test_data[i] = i;
|
||||||
|
list_push_back(&my_cool_list, &test_data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(list_get_len(&my_cool_list) == initial_list_size);
|
||||||
|
|
||||||
|
int head_val = 0xDEADBEEF;
|
||||||
|
int middle_val = 0x1337;
|
||||||
|
int tail_val = 0x10101010;
|
||||||
|
int last_tail_val = 0x12345678;
|
||||||
|
|
||||||
|
// insert at head of list
|
||||||
|
list_insert(&my_cool_list, &head_val, 0);
|
||||||
|
|
||||||
|
ListItr itr = list_itr_create(&my_cool_list);
|
||||||
|
void* data;
|
||||||
|
int test_data_itr = 0;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == head_val);
|
||||||
|
assert(data_from_get_at_idx == head_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[test_data_itr]);
|
||||||
|
assert(data_from_get_at_idx == test_data[test_data_itr]);
|
||||||
|
test_data_itr++;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(list_get_len(&my_cool_list) == initial_list_size + 1);
|
||||||
|
|
||||||
|
// insert at tail of list, use large value of 100 to force it to append it
|
||||||
|
// to the end of the list
|
||||||
|
list_insert(&my_cool_list, &tail_val, 100);
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
test_data_itr = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == head_val);
|
||||||
|
assert(data_from_get_at_idx == head_val);
|
||||||
|
}
|
||||||
|
else if(index == initial_list_size + 1) // for head and tail insertion
|
||||||
|
{
|
||||||
|
assert(data_itr == tail_val);
|
||||||
|
assert(data_from_get_at_idx == tail_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[test_data_itr]);
|
||||||
|
assert(data_from_get_at_idx == test_data[test_data_itr]);
|
||||||
|
test_data_itr++;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(list_get_len(&my_cool_list) == initial_list_size + 2);
|
||||||
|
|
||||||
|
// insert at "middle" of list
|
||||||
|
int insert_loc = 2;
|
||||||
|
test_data_itr = 0;
|
||||||
|
list_insert(&my_cool_list, &middle_val, insert_loc);
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == head_val);
|
||||||
|
assert(data_from_get_at_idx == head_val);
|
||||||
|
}
|
||||||
|
else if(index == insert_loc)
|
||||||
|
{
|
||||||
|
assert(data_itr == middle_val);
|
||||||
|
assert(data_from_get_at_idx == middle_val);
|
||||||
|
}
|
||||||
|
else if(index == initial_list_size + 2) // for head+middle+tail
|
||||||
|
{
|
||||||
|
assert(data_itr == tail_val);
|
||||||
|
assert(data_from_get_at_idx == tail_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[test_data_itr]);
|
||||||
|
assert(data_from_get_at_idx == test_data[test_data_itr]);
|
||||||
|
test_data_itr++;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
ListItr rev_itr = rev_list_itr_create(&my_cool_list);
|
||||||
|
index = initial_list_size + 2;
|
||||||
|
test_data_itr = initial_list_size - 1;
|
||||||
|
while((data = list_itr_next(&rev_itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == head_val);
|
||||||
|
assert(data_from_get_at_idx == head_val);
|
||||||
|
}
|
||||||
|
else if(index == insert_loc)
|
||||||
|
{
|
||||||
|
assert(data_itr == middle_val);
|
||||||
|
assert(data_from_get_at_idx == middle_val);
|
||||||
|
}
|
||||||
|
else if(index == initial_list_size + 2) // for head+middle+tail
|
||||||
|
{
|
||||||
|
assert(data_itr == tail_val);
|
||||||
|
assert(data_from_get_at_idx == tail_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[test_data_itr]);
|
||||||
|
assert(data_from_get_at_idx == test_data[test_data_itr]);
|
||||||
|
test_data_itr--;
|
||||||
|
}
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(list_get_len(&my_cool_list) == initial_list_size + 3);
|
||||||
|
|
||||||
|
// insert at the real end of the list, to make sure
|
||||||
|
// it works in conjunction with the previous "out of range" insertion for the tail
|
||||||
|
int tail_idx = list_get_len(&my_cool_list) - 1;
|
||||||
|
test_data_itr = 0;
|
||||||
|
list_insert(&my_cool_list, &last_tail_val, tail_idx);
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == head_val);
|
||||||
|
assert(data_from_get_at_idx == head_val);
|
||||||
|
}
|
||||||
|
else if(index == insert_loc)
|
||||||
|
{
|
||||||
|
assert(data_itr == middle_val);
|
||||||
|
assert(data_from_get_at_idx == middle_val);
|
||||||
|
}
|
||||||
|
else if(index == initial_list_size + 2) // for head+middle+tail
|
||||||
|
{
|
||||||
|
assert(data_itr == last_tail_val);
|
||||||
|
assert(data_from_get_at_idx == last_tail_val);
|
||||||
|
}
|
||||||
|
else if(index == initial_list_size + 3) // for head+middle+tail+last_tail
|
||||||
|
{
|
||||||
|
assert(data_itr == tail_val);
|
||||||
|
assert(data_from_get_at_idx == tail_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[test_data_itr]);
|
||||||
|
assert(data_from_get_at_idx == test_data[test_data_itr]);
|
||||||
|
test_data_itr++;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(list_get_len(&my_cool_list) == initial_list_size + 4);
|
||||||
|
|
||||||
|
// clear the list
|
||||||
|
list_clear(&my_cool_list);
|
||||||
|
|
||||||
|
// verify no data
|
||||||
|
assert(my_cool_list.head == NULL);
|
||||||
|
assert(my_cool_list.tail == NULL);
|
||||||
|
assert(list_is_empty(&my_cool_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test inserting at head, middle, and tail of list
|
||||||
|
// - list_create
|
||||||
|
// - list_push_back
|
||||||
|
// - list_swap
|
||||||
|
// - list_is_empty
|
||||||
|
// - list_get_len
|
||||||
|
// - list_itr_create
|
||||||
|
// - list_itr_next
|
||||||
|
// - list_clear
|
||||||
|
// - list_get_at_idx
|
||||||
|
void test_list_swap(void)
|
||||||
|
{
|
||||||
|
List my_cool_list = list_create();
|
||||||
|
|
||||||
|
// verify no data
|
||||||
|
assert(my_cool_list.head == NULL);
|
||||||
|
assert(my_cool_list.tail == NULL);
|
||||||
|
assert(list_get_len(&my_cool_list) == 0);
|
||||||
|
assert(list_is_empty(&my_cool_list));
|
||||||
|
|
||||||
|
const int initial_list_size = 5;
|
||||||
|
int test_data[initial_list_size];
|
||||||
|
|
||||||
|
for(int i = 0; i < initial_list_size; i++)
|
||||||
|
{
|
||||||
|
// 0 -> 1 -> 2 -> 3 -> 4
|
||||||
|
test_data[i] = i;
|
||||||
|
list_push_back(&my_cool_list, &test_data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(list_get_len(&my_cool_list) == initial_list_size);
|
||||||
|
|
||||||
|
|
||||||
|
ListItr itr = list_itr_create(&my_cool_list);
|
||||||
|
void* data;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
// 0 -> 1 -> 2 -> 3 -> 4
|
||||||
|
assert(*(int*)list_get_at_idx(&my_cool_list, index) == test_data[index]);
|
||||||
|
assert(*(int*)data == test_data[index]);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap nothing, out of range
|
||||||
|
assert(!list_swap(&my_cool_list, 100, 100));
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
// 0 -> 1 -> 2 -> 3 -> 4
|
||||||
|
assert(*(int*)list_get_at_idx(&my_cool_list, index) == test_data[index]);
|
||||||
|
assert(*(int*)data == test_data[index]);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap nothing, in range
|
||||||
|
assert(list_swap(&my_cool_list, 0, 0));
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
// 0 -> 1 -> 2 -> 3 -> 4
|
||||||
|
assert(*(int*)list_get_at_idx(&my_cool_list, index) == test_data[index]);
|
||||||
|
assert(*(int*)data == test_data[index]);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap head and "middle"
|
||||||
|
int mid_idx = initial_list_size / 2;
|
||||||
|
assert(list_swap(&my_cool_list, 0, mid_idx));
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
// 2 -> 1 -> 0 -> 3 -> 4
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[mid_idx]);
|
||||||
|
assert(data_from_get_at_idx == test_data[mid_idx]);
|
||||||
|
}
|
||||||
|
else if(index == mid_idx)
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[0]);
|
||||||
|
assert(data_from_get_at_idx == test_data[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[index]);
|
||||||
|
assert(data_from_get_at_idx == test_data[index]);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap tail and "middle"
|
||||||
|
assert(list_swap(&my_cool_list, initial_list_size - 1, mid_idx));
|
||||||
|
|
||||||
|
itr = list_itr_create(&my_cool_list);
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while((data = list_itr_next(&itr)))
|
||||||
|
{
|
||||||
|
int data_itr = *(int*)data;
|
||||||
|
int data_from_get_at_idx = *(int*)list_get_at_idx(&my_cool_list, index);
|
||||||
|
|
||||||
|
// 2 -> 1 -> 4 -> 3 -> 0
|
||||||
|
if(index == 0)
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[mid_idx]);
|
||||||
|
assert(data_from_get_at_idx == test_data[mid_idx]);
|
||||||
|
}
|
||||||
|
else if(index == mid_idx)
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[initial_list_size - 1]);
|
||||||
|
assert(data_from_get_at_idx == test_data[initial_list_size - 1]);
|
||||||
|
}
|
||||||
|
else if(index == initial_list_size - 1)
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[0]);
|
||||||
|
assert(data_from_get_at_idx == test_data[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(data_itr == test_data[index]);
|
||||||
|
assert(data_from_get_at_idx == test_data[index]);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the list
|
||||||
|
list_clear(&my_cool_list);
|
||||||
|
|
||||||
|
// verify no data
|
||||||
|
assert(my_cool_list.head == NULL);
|
||||||
|
assert(my_cool_list.tail == NULL);
|
||||||
|
assert(list_is_empty(&my_cool_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
printf("Testing List Create and Clear.\n");
|
printf("Testing List Create and Clear.\n");
|
||||||
@@ -296,9 +672,16 @@ int main(void)
|
|||||||
|
|
||||||
printf("Testing List Push Front.\n");
|
printf("Testing List Push Front.\n");
|
||||||
push_front_one_entry();
|
push_front_one_entry();
|
||||||
|
|
||||||
printf("Testing List Complete Exercise.\n");
|
printf("Testing List Complete Exercise.\n");
|
||||||
push_back_three_remove_push_front_three_entries();
|
push_back_three_remove_push_front_three_entries();
|
||||||
|
|
||||||
|
printf("Testing List Insertion.\n");
|
||||||
|
test_list_insertion();
|
||||||
|
|
||||||
|
printf("Testing List Swap.\n");
|
||||||
|
test_list_swap();
|
||||||
|
|
||||||
printf("-------------------------------------------------------------------------------\n");
|
printf("-------------------------------------------------------------------------------\n");
|
||||||
printf("List Tests Passed :)\n");
|
printf("List Tests Passed :)\n");
|
||||||
printf("-------------------------------------------------------------------------------\n");
|
printf("-------------------------------------------------------------------------------\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user