Add forward_list

This commit is contained in:
Bailey Thompson
2017-10-19 23:46:58 -04:00
committed by GitHub
parent cea2826bc4
commit 99706ea51b
5 changed files with 527 additions and 9 deletions

348
src/forward_list.c Normal file
View File

@@ -0,0 +1,348 @@
/*
* Copyright (c) 2017 Bailey Thompson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include "forward_list.h"
struct _forward_list {
size_t data_size;
int space;
struct node *head;
};
struct node {
void *data;
struct node *next;
};
/**
* Initializes a singly-linked list.
*
* @param data_size The size of data to store.
*
* @return The singly-linked list, or NULL if memory could not be allocated.
*/
forward_list forward_list_init(const size_t data_size) {
struct _forward_list *const init = malloc(sizeof(struct _forward_list));
if (init == NULL) {
return NULL;
}
init->data_size = data_size;
init->space = 0;
init->head = NULL;
return init;
}
/**
* Gets the amount of elements in the singly-linked list.
*
* @param me The singly-linked list to check.
*
* @return The amount of elements.
*/
int forward_list_size(forward_list me) {
return me->space;
}
/**
* Determines if the singly-linked list is empty.
*
* @param me The singly-linked list to check.
*
* @return If the list is empty.
*/
bool forward_list_is_empty(forward_list me) {
return forward_list_size(me) == 0;
}
/**
* Copies the nodes of the singly-linked list to an array.
*
* @param array The array to copy the list to.
* @param me The list to copy to the array.
*/
void forward_list_to_array(void *const array, forward_list me) {
struct node *traverse = me->head;
int offset = 0;
while (traverse != NULL) {
memcpy(array + offset, traverse->data, me->data_size);
offset += me->data_size;
traverse = traverse->next;
}
}
/*
* Get the node at the specified index.
*/
static struct node *get_node_at(forward_list me, const int index) {
struct node *traverse = me->head;
for (int i = 0; i < index; i++) {
traverse = traverse->next;
}
return traverse;
}
/**
* Adds data at the first index in the singly-linked list.
*
* @param me The list to add data to.
* @param data The data to add to the list.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int forward_list_add_first(forward_list me, void *data) {
return forward_list_add_at(me, 0, data);
}
/**
* Adds data at a specified index in the singly-linked list.
*
* @param me The list to add data to.
* @param index The index to add the data at.
* @param data The data to add to the list.
*
* @return 0 No error.
* -ENOMEM Out of memory.
* -EINVAL Invalid argument.
*/
int forward_list_add_at(forward_list me, int index, void *data) {
if (index < 0 || index > me->space) {
return -EINVAL;
}
struct node *const add = malloc(sizeof(struct node));
if (add == NULL) {
return -ENOMEM;
}
add->data = malloc(me->data_size);
if (add->data == NULL) {
free(add);
return -ENOMEM;
}
memcpy(add->data, data, me->data_size);
if (index == 0) {
add->next = me->head;
me->head = add;
} else {
struct node *const traverse = get_node_at(me, index - 1);
add->next = traverse->next;
traverse->next = add;
}
me->space++;
return 0;
}
/**
* Adds data at the last index in the singly-linked list.
*
* @param me The list to add data to.
* @param data The data to add to the list.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int forward_list_add_last(forward_list me, void *data) {
return forward_list_add_at(me, me->space, data);
}
/*
* Determines if the input is illegal.
*/
static bool is_illegal_input(forward_list me, const int index) {
return index < 0 || index >= me->space || me->space == 0;
}
/**
* Removes the first piece of data from the singly-linked list.
*
* @param me The list to remove data from.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_remove_first(forward_list me) {
return forward_list_remove_at(me, 0);
}
/**
* Removes data from the singly-linked list at the specified index.
*
* @param me The list to remove data from.
* @param index The index to remove from.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_remove_at(forward_list me, int index) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
if (index == 0) {
struct node *const backup_head = me->head;
me->head = me->head->next;
free(backup_head);
} else if (index == me->space - 1) {
struct node *const traverse = get_node_at(me, index - 1);
free(traverse->next);
traverse->next = NULL;
} else {
struct node *const traverse = get_node_at(me, index - 1);
struct node *const backup = traverse->next;
traverse->next = traverse->next->next;
free(backup);
}
me->space--;
return 0;
}
/**
* Removes the last piece of data from the singly-linked list.
*
* @param me The list to remove data from.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_remove_last(forward_list me) {
return forward_list_remove_at(me, me->space - 1);
}
/**
* Sets the data at the first index in the singly-linked list.
*
* @param me The list to set data for.
* @param data The data to set in the list.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_set_first(forward_list me, void *data) {
return forward_list_set_at(me, 0, data);
}
/**
* Sets the data at the specified index in the singly-linked list.
*
* @param me The list to set data for.
* @param index The index to set data in the list.
* @param data The data to set in the list.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_set_at(forward_list me, int index, void *data) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
struct node *const traverse = get_node_at(me, index);
memcpy(traverse->data, data, me->data_size);
return 0;
}
/**
* Sets the data at the last index in the singly-linked list.
*
* @param me The list to set data for.
* @param data The data to set in the list.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_set_last(forward_list me, void *data) {
return forward_list_set_at(me, me->space - 1, data);
}
/**
* Gets the data at the first index in the singly-linked list.
*
* @param data The data to get.
* @param me The list to get data from.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_get_first(void *data, forward_list me) {
return forward_list_get_at(data, me, 0);
}
/**
* Gets the data at the specified index in the singly-linked list.
*
* @param data The data to get.
* @param me The list to get data from.
* @param index The index to get data from.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_get_at(void *data, forward_list me, int index) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
struct node *const traverse = get_node_at(me, index);
memcpy(data, traverse->data, me->data_size);
return 0;
}
/**
* Gets the data at the last index in the singly-linked list.
*
* @param data The data to get.
* @param me The list to get data from.
*
* @return 0 No error.
* -EINVAL Invalid argument.
*/
int forward_list_get_last(void *data, forward_list me) {
return forward_list_get_at(data, me, me->space - 1);
}
/**
* Clears all elements from the singly-linked list.
*
* @param me The list to clear.
*/
void forward_list_clear(forward_list me) {
struct node *traverse = me->head;
while (traverse != NULL) {
struct node *const temp = traverse;
traverse = traverse->next;
free(temp);
}
me->head = NULL;
me->space = 0;
}
/**
* Destroys the singly-linked list.
*
* @param me The list to destroy.
*
* @return NULL
*/
forward_list forward_list_destroy(forward_list me) {
forward_list_clear(me);
free(me);
return NULL;
}

56
src/forward_list.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2017 Bailey Thompson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CONTAINERS_FORWARD_LIST_H
#define CONTAINERS_FORWARD_LIST_H
#include <stdbool.h>
typedef struct _forward_list *forward_list;
// Starting
forward_list forward_list_init(size_t data_size);
// Utility
int forward_list_size(forward_list me);
bool forward_list_is_empty(forward_list me);
void forward_list_to_array(void *array, forward_list me);
// Adding
int forward_list_add_first(forward_list me, void *data);
int forward_list_add_at(forward_list me, int index, void *data);
int forward_list_add_last(forward_list me, void *data);
// Removing
int forward_list_remove_first(forward_list me);
int forward_list_remove_at(forward_list me, int index);
int forward_list_remove_last(forward_list me);
// Setting
int forward_list_set_first(forward_list me, void *data);
int forward_list_set_at(forward_list me, int index, void *data);
int forward_list_set_last(forward_list me, void *data);
// Getting
int forward_list_get_first(void *data, forward_list me);
int forward_list_get_at(void *data, forward_list me, int index);
int forward_list_get_last(void *data, forward_list me);
// Ending
void forward_list_clear(forward_list me);
forward_list forward_list_destroy(forward_list me);
#endif /* CONTAINERS_FORWARD_LIST_H */

View File

@@ -43,7 +43,7 @@ struct node {
*
* @param data_size The size of data to store.
*
* @return The doubly-linked list, or NULL could not allocate memory.
* @return The doubly-linked list, or NULL if memory could not be allocated.
*/
list list_init(const size_t data_size) {
struct _list *const init = malloc(sizeof(struct _list));
@@ -237,7 +237,7 @@ int list_add_last(list me, void *const data) {
/*
* Determines if the input is illegal.
*/
static bool isIllegalInput(list me, const int index) {
static bool is_illegal_input(list me, const int index) {
return index < 0 || index >= me->space || me->space == 0;
}
@@ -263,7 +263,7 @@ int list_remove_first(list me) {
* -EINVAL Invalid argument.
*/
int list_remove_at(list me, const int index) {
if (isIllegalInput(me, index)) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
struct node *const traverse = get_node_at(me, index);
@@ -318,7 +318,7 @@ int list_set_first(list me, void *const data) {
* -EINVAL Invalid argument.
*/
int list_set_at(list me, const int index, void *const data) {
if (isIllegalInput(me, index)) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
struct node *const traverse = get_node_at(me, index);
@@ -363,7 +363,7 @@ int list_get_first(void *const data, list me) {
* -EINVAL Invalid argument.
*/
int list_get_at(void *const data, list me, const int index) {
if (isIllegalInput(me, index)) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
struct node *const traverse = get_node_at(me, index);

View File

@@ -200,7 +200,7 @@ int vector_add_last(vector me, void *const data) {
/*
* Determines if the input is illegal.
*/
static bool isIllegalInput(vector me, const int index) {
static bool is_illegal_input(vector me, const int index) {
return index < 0 || index >= me->offset || me->offset == 0;
}
@@ -226,7 +226,7 @@ int vector_remove_first(vector me) {
* -EINVAL Invalid argument.
*/
int vector_remove_at(vector me, const int index) {
if (isIllegalInput(me, index)) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
memmove(me->storage + index * me->data_size,
@@ -274,7 +274,7 @@ int vector_set_first(vector me, void *const data) {
* -EINVAL Invalid argument.
*/
int vector_set_at(vector me, const int index, void *const data) {
if (isIllegalInput(me, index)) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
memcpy(me->storage + index * me->data_size, data, me->data_size);
@@ -317,7 +317,7 @@ int vector_get_first(void *const data, vector me) {
* -EINVAL Invalid argument.
*/
int vector_get_at(void *const data, vector me, const int index) {
if (isIllegalInput(me, index)) {
if (is_illegal_input(me, index)) {
return -EINVAL;
}
memcpy(data, me->storage + index * me->data_size, me->data_size);

View File

@@ -3,6 +3,7 @@
#include <assert.h>
#include "../src/vector.h"
#include "../src/list.h"
#include "../src/forward_list.h"
static void test_vector(void) {
int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
@@ -230,8 +231,121 @@ static void test_list(void) {
assert(me == NULL);
}
static void test_forward_list(void) {
int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
forward_list me = forward_list_init(sizeof(int));
assert(me != NULL);
assert(forward_list_size(me) == 0);
assert(forward_list_is_empty(me));
for (int i = 0; i < 10; i++) {
forward_list_add_first(me, &val[i]);
assert(forward_list_size(me) == i + 1);
int get = 0;
forward_list_get_first(&get, me);
assert(get == val[i]);
}
assert(forward_list_size(me) == 10);
assert(!forward_list_is_empty(me));
int get_arr[10] = {0};
forward_list_to_array(get_arr, me);
for (int i = 0; i < 10; i++) {
int get = 0;
forward_list_get_at(&get, me, i);
assert(get == val[9 - i]);
assert(get_arr[i] == val[9 - i]);
}
for (int i = 0; i < 7; i++) {
forward_list_remove_last(me);
}
int trimmed[5] = {0};
forward_list_to_array(trimmed, me);
assert(forward_list_size(me) == 3);
for (int i = 0; i < 3; i++) {
assert(10 - i == trimmed[i]);
}
int add = 3;
forward_list_add_last(me, &add);
add = -1;
forward_list_add_at(me, 1, &add);
add = -2;
forward_list_add_last(me, &add);
assert(forward_list_size(me) == 6);
int aa = 456;
int a = 456;
int b = 456;
int c = 456;
int d = 456;
int e = 456;
int f = 456;
int ff = 456;
forward_list_get_first(&aa, me);
assert(aa == 10);
forward_list_get_at(&a, me, 0);
assert(a == 10);
forward_list_get_at(&b, me, 1);
assert(b == -1);
forward_list_get_at(&c, me, 2);
assert(c == 9);
forward_list_get_at(&d, me, 3);
assert(d == 8);
forward_list_get_at(&e, me, 4);
assert(e == 3);
forward_list_get_at(&f, me, 5);
assert(f == -2);
forward_list_get_last(&ff, me);
assert(ff == -2);
forward_list_remove_first(me);
forward_list_remove_at(me, 2);
forward_list_remove_last(me);
assert(forward_list_size(me) == 3);
int get = 345;
forward_list_get_first(&get, me);
assert(get == -1);
forward_list_get_at(&get, me, 1);
assert(get == 9);
forward_list_get_last(&get, me);
assert(get == 3);
int set = 12;
forward_list_set_first(me, &set);
set = 13;
forward_list_set_at(me, 1, &set);
set = 14;
forward_list_set_last(me, &set);
int arr[3] = {0};
forward_list_to_array(arr, me);
assert(arr[0] == 12);
assert(arr[1] == 13);
assert(arr[2] == 14);
set = -5;
forward_list_set_at(me, 0, &set);
set = -6;
forward_list_set_at(me, 1, &set);
set = -7;
forward_list_set_at(me, 2, &set);
forward_list_to_array(arr, me);
assert(arr[0] == -5);
assert(arr[1] == -6);
assert(arr[2] == -7);
assert(forward_list_set_at(me, 4, &set) == -EINVAL);
assert(forward_list_get_at(&set, me, 4) == -EINVAL);
assert(forward_list_remove_at(me, 4) == -EINVAL);
assert(forward_list_add_at(me, 5, &set) == -EINVAL);
assert(forward_list_set_at(me, -1, &set) == -EINVAL);
assert(forward_list_get_at(&set, me, -1) == -EINVAL);
assert(forward_list_remove_at(me, -1) == -EINVAL);
assert(forward_list_add_at(me, -1, &set) == -EINVAL);
forward_list_clear(me);
assert(forward_list_size(me) == 0);
assert(forward_list_is_empty(me));
assert(forward_list_remove_first(me) == -EINVAL);
assert(forward_list_remove_last(me) == -EINVAL);
me = forward_list_destroy(me);
assert(me == NULL);
}
int main() {
test_vector();
test_list();
test_forward_list();
return 0;
}