I have written a ArrayList class in C and I just wanted some criticism on what I can improve on. Any criticism helps, and I was wondering if there is any better way of doing error handling other than returning a enum.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#define ARRAY_LIST_DEFAULT_SIZE 5
#define RESIZE_MULTIPLIER 2
typedef struct arraylist_t
{
void *array;
size_t sizeOfElement;
uint32_t sizeOfArray;
uint32_t lengthOfArray;
int32_t (*defaultCompare)(const void *, const void *);
void (*defaultPrint)(const void *);
}ArrayList;
enum data_structure_error{
E_SUCCESS = 0,
E_FAIL = -1,
E_MEMORY_FAIL = -2,
E_VAR_UNINI = -3,
E_VAR_TO_SMALL = -4,
E_OUT_OF_BOUNDS = -5,
E_PRINT_UNINI = -6,
E_COMPARE_UNINI = -7
};
struct data_structure_errordesc{
const int32_t code;
const char *message;
};
const struct data_structure_errordesc errordesc[] = {
{E_SUCCESS, "No error" },
{E_FAIL, "PANIC!!!!" },
{E_MEMORY_FAIL, "Could not allocate memory"},
{E_VAR_UNINI, "The variable passed in is uninitialized"},
{E_VAR_TO_SMALL, "The variable passed in is too small to hold data"},
{E_OUT_OF_BOUNDS, "Value passed in was out of bounds"},
{E_PRINT_UNINI, "The default and the passed in print is NULL"},
{E_COMPARE_UNINI, "The default and the passed in compare in NULL"}
};
void arraylist_error(enum data_structure_error error)
{
uint32_t i;
for(i = 0; i < sizeof(errordesc) / sizeof(errordesc[0]); i++)
{
if(error == errordesc[i].code)
{
printf("%s", errordesc[i].message);
return;
}
}
}
enum data_structure_error arraylist_create(ArrayList ** const user_list, const size_t size_of_element, int32_t (*compare)(const void *, const void *), void (*print)(const void *))
{
/*making 1 struct of type ArrayList*/
ArrayList *list;
if(user_list == NULL)
goto FAIL0;
list = malloc(sizeof(*list));
if(list == NULL)
goto FAIL1;
/*making an array of void pointers*/
list->array = malloc(size_of_element * ARRAY_LIST_DEFAULT_SIZE);
if(list->array == NULL)
goto FAIL1;
/*setting all default values of ArrayList struct*/
list->sizeOfElement = size_of_element;
list->sizeOfArray = 0;
list->lengthOfArray = ARRAY_LIST_DEFAULT_SIZE;
list->defaultCompare = compare;
list->defaultPrint = print;
*user_list = list;
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
free(list);
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_clear(ArrayList * const list)
{
if(list == NULL)
return E_VAR_UNINI;
list->sizeOfArray = 0;
}
enum data_structure_error arraylist_clone(const ArrayList * const list, ArrayList ** const new_list)
{
if(list == NULL)
goto FAIL0;
/*create an ArrayList struct*/
*new_list = malloc(sizeof(**new_list));
if(*new_list == NULL)
goto FAIL1;
/*copy data to new struct*/
memcpy(*new_list, list, sizeof(**new_list));
/*allocate space for new array in the new struct*/
(*new_list)->array = malloc(list->sizeOfElement * list->lengthOfArray);
if((*new_list)->array == NULL)
goto FAIL1;
/*copy the data from the old array to new array*/
memcpy((*new_list)->array, list->array, list->sizeOfElement * list->sizeOfArray);
FAIL0:
return E_VAR_UNINI;
FAIL1:
free(*new_list);
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_size(const ArrayList * const list, uint32_t * const size)
{
if(list == NULL)
return E_VAR_UNINI;
*size = list->sizeOfArray;
}
enum data_structure_error arraylist_isempty(const ArrayList * const list, bool * const empty)
{
if(list == NULL)
return E_VAR_UNINI;
*empty = list->sizeOfArray == 0 ? 1 : 0;
}
enum data_structure_error arraylist_set_compare(ArrayList * const list, int32_t (*compare)(const void *, const void *))
{
if(list == NULL)
return E_VAR_UNINI;
list->defaultCompare = compare;
}
enum data_structure_error arraylist_set_print(ArrayList * const list, void (*print)(const void *))
{
if(list == NULL)
return E_VAR_UNINI;
list->defaultPrint = print;
}
enum data_structure_error arraylist_print_index(const ArrayList * const list, void(*print)(const void *), const uint32_t index)
{
uint8_t *array;
void *temp_storage;
/*error checking*/
if(list == NULL)
goto FAIL0;
else if(print == NULL && list->defaultPrint == NULL)
goto FAIL1;
temp_storage = malloc(list->sizeOfElement);
if(temp_storage == NULL)
goto FAIL2;
/*Get the data from the array*/
array = list->array;
memcpy(temp_storage, array + index * list->sizeOfElement, list->sizeOfElement);
/*call the correct print function*/
if(print == NULL)
list->defaultPrint(temp_storage);
else
print(temp_storage);
free(temp_storage);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_PRINT_UNINI;
FAIL2:
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_print(const ArrayList * const list, void(*print)(const void *))
{
uint32_t i;
uint8_t *array;
void *temp_storage;
/*error checking*/
if(list == NULL)
goto FAIL0;
else if(print == NULL && list->defaultPrint == NULL)
goto FAIL1;
/*allocate temp storage*/
temp_storage = malloc(list->sizeOfElement);
if(temp_storage == NULL)
goto FAIL2;
/*copying pointer of array*/
array = list->array;
/*loop through array and call the correct print function*/
for(i = 0; i < list->sizeOfArray; i++)
{
memcpy(temp_storage, (array + i * list->sizeOfElement), list->sizeOfElement);
if(print == NULL)
list->defaultPrint(temp_storage);
else
print(temp_storage);
}
free(temp_storage);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_PRINT_UNINI;
FAIL2:
return E_MEMORY_FAIL;
}
static enum data_structure_error arraylist_resize(ArrayList * const list)
{
void *new_array;
/*try to allocate more memory for the array*/
new_array = realloc(list->array, list->sizeOfElement * list->lengthOfArray * RESIZE_MULTIPLIER);
if(new_array == NULL)
goto FAIL0;
/*update the struct*/
list->array = new_array;
list->lengthOfArray = list->lengthOfArray * RESIZE_MULTIPLIER;
return E_SUCCESS;
FAIL0:
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_add_index(ArrayList * const list, const void * const ptr_to_data, const uint32_t index)
{
uint8_t *array;
uint8_t *array_two;
enum data_structure_error error = E_SUCCESS;
/*error handeling*/
if(list == NULL || ptr_to_data == NULL)
goto FAIL0;
else if(index > list->sizeOfArray)
goto FAIL1;
else if(list->sizeOfArray >= list->lengthOfArray)
{
error = arraylist_resize(list);
if(error != E_SUCCESS)
goto FAIL2;
}
/*copying pointer of array*/
array = array_two = list->array;
/*the spot where the new value will be inserted*/
array = array + list->sizeOfElement * index;
/*the spot where all the elements will be shifted to*/
array_two = array_two + list->sizeOfElement * (index + 1);
/*shifting elements*/
memmove(array_two, array, list->sizeOfElement * (list->sizeOfArray - index));
/*inserting value*/
memcpy(array, ptr_to_data, list->sizeOfElement);
list->sizeOfArray++;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_OUT_OF_BOUNDS;
FAIL2:
return error;
}
enum data_structure_error arraylist_add_all_index(ArrayList * const list, const void * const ptr_to_array_data, const uint32_t length, const uint32_t index)
{
uint8_t *array;
uint8_t *array_two;
enum data_structure_error error = E_SUCCESS;
/*error checking*/
if(list == NULL || ptr_to_array_data == NULL)
goto FAIL0;
else if(index > list->sizeOfArray)
goto FAIL1;
else if(list->sizeOfArray >= list->lengthOfArray)
{
error = arraylist_resize(list);
if(error != E_SUCCESS)
goto FAIL2;
}
/*making sure array has enough space*/
while(length >= list->lengthOfArray - list->sizeOfArray)
{
error = arraylist_resize(list);
if(error != E_SUCCESS)
goto FAIL2;
}
/*copying pointer of array*/
array = array_two = list->array;
/*the spot where the new value/values will be inserted*/
array = array + list->sizeOfElement * index;
/*the spot where all the values will be shifted*/
array_two = array_two + list->sizeOfElement * (index + length);
/*shifting values*/
memmove(array_two, array, list->sizeOfElement * (list->sizeOfArray - index));
/*inserting new values into position*/
memcpy(array, ptr_to_array_data, list->sizeOfElement * length);
list->sizeOfArray = list->sizeOfArray + length;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_OUT_OF_BOUNDS;
FAIL2:
return error;
}
enum data_structure_error arraylist_add_all(ArrayList * const list, void *ptr_to_array_data, const uint32_t length)
{
/*adding to end of the arraylist*/
return arraylist_add_all_index(list, ptr_to_array_data, length, list->sizeOfArray);
}
enum data_structure_error arraylist_add(ArrayList * const list, const void * const ptr_to_data)
{
/*adding to end of the arraylist*/
return arraylist_add_index(list, ptr_to_data, list->sizeOfArray);
}
enum data_structure_error arraylist_get_index(const ArrayList * const list, void * const ptr_to_data, const uint32_t index)
{
uint8_t *array;
/*error checking*/
if(list == NULL || ptr_to_data == NULL)
goto FAIL0;
else if(index >= list->sizeOfArray)
goto FAIL1;
/*copying array pointer*/
array = list->array;
/*position of the value to get*/
array = array + list->sizeOfElement * index;
/*copying data*/
memcpy(ptr_to_data, array, list->sizeOfElement);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_OUT_OF_BOUNDS;
}
enum data_structure_error arraylist_contains(const ArrayList * const list, const void * const ptr_to_data, bool * const contains, int32_t (*compare)(const void *, const void *))
{
uint32_t i;
uint8_t *array;
void *temp_storage;
int32_t (*temp_compare)(const void *, const void *);
/*error cheking*/
if(list == NULL || ptr_to_data == NULL || contains == NULL)
goto FAIL0;
else if(compare == NULL && list->defaultCompare == NULL)
goto FAIL1;
/*allocating space*/
temp_storage = malloc(list->sizeOfElement);
if(temp_storage == NULL)
goto FAIL2;
/*if compare is not passed in use default compare*/
if(compare == NULL)
temp_compare = list->defaultCompare;
else
temp_compare = compare;
array = list->array;
/*set to false*/
*contains = 0;
for(i = 0; i < list->sizeOfArray; i++)
{
memcpy(temp_storage, array + list->sizeOfElement * i, list->sizeOfElement);
if(temp_compare(temp_storage, ptr_to_data) == 0)
{
*contains = 1;
break;
}
}
free(temp_storage);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_COMPARE_UNINI;
FAIL2:
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_indexof(const ArrayList * const list, const void * const ptr_to_data, int32_t * const index, int32_t (*compare)(const void *, const void *))
{
uint32_t i;
uint8_t *array;
void *temp_storage;
int32_t (*temp_compare)(const void *, const void *);
/*error checking*/
if(list == NULL || ptr_to_data == NULL || index == NULL)
goto FAIL0;
else if(compare == NULL && list->defaultCompare == NULL)
goto FAIL1;
temp_storage = malloc(list->sizeOfElement);
if(temp_storage == NULL)
goto FAIL2;
/*if compare is not passed in use default compare*/
if(compare == NULL)
temp_compare = list->defaultCompare;
else
temp_compare = compare;
array = list->array;
*index = -1;
for(i = 0; i < list->sizeOfArray; i++)
{
memcpy(temp_storage, array + list->sizeOfElement * i, list->sizeOfElement);
if(temp_compare(temp_storage, ptr_to_data) == 0)
{
*index = i;
break;
}
}
free(temp_storage);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_COMPARE_UNINI;
FAIL2:
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_lastindexof(const ArrayList * const list, const void * const ptr_to_data, int32_t * const index, int32_t (*compare)(const void *, const void *))
{
int32_t i;
uint8_t *array;
void *temp_storage;
int32_t (*temp_compare)(const void *, const void *);
/*error checking*/
if(list == NULL || ptr_to_data == NULL || index == NULL)
goto FAIL0;
else if(compare == NULL && list->defaultCompare == NULL)
goto FAIL1;
temp_storage = malloc(list->sizeOfElement);
if(temp_storage == NULL)
goto FAIL2;
/*if compare is not passed in use default compare*/
if(compare == NULL)
temp_compare = list->defaultCompare;
else
temp_compare = compare;
array = list->array;
*index = -1;
for(i = list->sizeOfArray - 1; i > -1; i--)
{
memcpy(temp_storage, array + list->sizeOfElement * i, list->sizeOfElement);
if(temp_compare(temp_storage, ptr_to_data) == 0)
{
*index = i;
break;
}
}
free(temp_storage);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_COMPARE_UNINI;
FAIL2:
return E_MEMORY_FAIL;
}
enum data_structure_error arraylist_set_index(const ArrayList * const list, const void * const ptr_to_data, const uint32_t index)
{
uint32_t i;
uint8_t *array;
/*error handeling*/
if(list == NULL || ptr_to_data == NULL)
goto FAIL0;
else if(index >= list->sizeOfArray)
goto FAIL1;
/*get pointer to array*/
array = list->array;
/*set the data*/
memcpy(array + list->sizeOfElement * index, ptr_to_data, list->sizeOfElement);
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_OUT_OF_BOUNDS;
}
enum data_structure_error arraylist_remove_index(ArrayList * const list, void * const ptr_to_data, const uint32_t index)
{
uint8_t *array;
uint8_t *array_two;
/*error handeling*/
if(list == NULL)
goto FAIL0;
else if(index >= list->sizeOfArray)
goto FAIL1;
/*get pointer to array*/
array = array_two = list->array;
/*set pointer to data to remove*/
array = array + list->sizeOfElement * index;
/*set pointer to index + 1*/
array_two = array_two + list->sizeOfElement * (index + 1);
/*get the data if pointer is not NULL*/
if(ptr_to_data != NULL)
memcpy(ptr_to_data, array + list->sizeOfElement * index, list->sizeOfElement);
/*shift the data*/
memcpy(array, array_two, list->sizeOfElement * (list->sizeOfArray - (index + 1)));
list->sizeOfArray = list->sizeOfArray - 1;
return E_SUCCESS;
FAIL0:
return E_VAR_UNINI;
FAIL1:
return E_OUT_OF_BOUNDS;
}
void arraylist_free(ArrayList * const list)
{
free(list->array);
free(list);
}
/*user code*/
void print_my_data(const void *data)
{
int32_t *temp;
temp = (int32_t *)data;
printf("%d\n", *temp);
}
int compare_my_data(const void *ptr1, const void *ptr2)
{
const int *data1;
const int *data2;
data1 = ptr1;
data2 = ptr2;
if(*data1 < *data2)
return -1;
else if(*data1 > *data2)
return 1;
return 0;
}
int main(void)
{
ArrayList *list;
arraylist_create(&list, sizeof(int), &compare_my_data, &print_my_data);
for(int i = 0; i < 10; i++)
{
arraylist_add(list, &i);
}
arraylist_print(list, NULL);
arraylist_free(list);
return 0;
}
```