2021-11-22 17:32:54 +00:00
/*
* C_lib Copyright ( C ) 2021 Wael Karram .
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , version 3 of the License .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
*/
2021-08-29 14:26:31 +00:00
/* This file contains the function implementations for single linked lists. */
/* Include guard + includes. */
# ifndef SINGLE_LINKED_LIST_C
# define SINGLE_LINKED_LIST_C
# include "single_linked_list.h"
# endif /* SINGLE_LINKED_LIST_C */
/* This function initializes a new linked list, returns NULL on failure. */
2021-09-04 14:18:06 +00:00
linked_list_t * initialize_single_linked_list ( ) {
2021-08-29 14:26:31 +00:00
/* Variables. */
linked_list_t * result ;
/* Attempt to allocate. */
result = ( linked_list_t * ) malloc ( sizeof ( linked_list_t ) ) ;
/* Check if the allocation worked. */
if ( result = = NULL )
return NULL ;
/* Initialize the internal fields. */
result - > length = 0 ;
result - > head = NULL ;
/* Return the result. */
return result ;
}
/* This function appends a node to the given linked list, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int append_node_single_linked_list ( linked_list_t * list , node_t * node ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
if ( list = = NULL | | node = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
2021-10-21 09:32:13 +00:00
/* Set the next to NULL. */
node - > next = NULL ;
2021-08-29 14:26:31 +00:00
/* Check if we can append at the start. */
if ( list - > head = = NULL ) {
list - > head = node ;
( list - > length ) + + ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* Loop till we get to the end. */
node_t * current = list - > head ;
while ( current - > next ! = NULL ) {
current = current - > next ;
}
/* Got to the end, append and add. */
current - > next = node ;
( list - > length ) + + ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* This function prepends a node to the given linked list, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int prepend_node_single_linked_list ( linked_list_t * list , node_t * node ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
if ( list = = NULL | | node = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
2021-10-21 09:32:13 +00:00
/* Set the next to NULL. */
node - > next = NULL ;
2021-08-29 14:26:31 +00:00
/* Check if we can prepend at the start. */
if ( list - > head = = NULL ) {
list - > head = node ;
( list - > length ) + + ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* Set the node's next to the current head, and swap. */
node - > next = list - > head ;
list - > head = node ;
( list - > length ) + + ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* This function creates and appends a node to the given linked list, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int append_node_data_single_linked_list ( linked_list_t * list , void * data ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
if ( list = = NULL | | data = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Attempt to create a node. */
node_t * node = ( node_t * ) malloc ( sizeof ( node_t ) ) ;
if ( node = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Insert the data. */
node - > data = data ;
/* Delegate the work. */
2021-09-04 14:18:06 +00:00
return append_node_single_linked_list ( list , node ) ;
2021-08-29 14:26:31 +00:00
}
/* This function creates and prepends a node to the given linked list, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int prepend_node_data_single_linked_list ( linked_list_t * list , void * data ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
if ( list = = NULL | | data = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Attempt to create a node. */
node_t * node = ( node_t * ) malloc ( sizeof ( node_t ) ) ;
if ( node = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Insert the data. */
node - > data = data ;
/* Delegate the work. */
2021-09-04 14:18:06 +00:00
return prepend_node_single_linked_list ( list , node ) ;
2021-08-29 14:26:31 +00:00
}
/* This function inserts a node at the ith place, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int add_node_i_single_linked_list ( linked_list_t * list , node_t * node , int i ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
if ( list = = NULL | | node = = NULL | | list - > length < = i )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
2021-10-21 09:32:13 +00:00
/* Set the next to NULL. */
node - > next = NULL ;
2021-08-29 14:26:31 +00:00
/* Deal with special case of head. */
if ( i = = 0 ) {
node - > next = list - > head ;
list - > head = node ;
( list - > length ) + + ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* Loop till we get to the right place. */
node_t * current = list - > head ;
for ( ; i > 1 ; i - - )
current = current - > next ;
/* Insert the node. */
node - > next = current - > next ;
current - > next = node ;
( list - > length ) + + ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* This function creates and inserts a node at the ith place, returns 1 in success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int add_node_data_i_single_linked_list ( linked_list_t * list , void * data , int i ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
if ( list = = NULL | | list - > length < = i )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Attempt to create a node. */
node_t * node = ( node_t * ) malloc ( sizeof ( node_t ) ) ;
if ( node = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Insert the data. */
node - > data = data ;
/* Delegate. */
2021-09-04 14:18:06 +00:00
return add_node_i_single_linked_list ( list , node , i ) ;
2021-08-29 14:26:31 +00:00
}
/* This function reads the data at the ith node, returns NULL on failure or NULL data! */
2021-09-07 20:55:38 +00:00
/* Sets the error code in error (instead of returning it). */
void * read_node_i_single_linked_list ( linked_list_t * list , int i , int * error ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check. */
2021-09-26 19:54:52 +00:00
if ( error = = NULL )
return NULL ;
2021-09-07 20:55:38 +00:00
if ( list = = NULL | | list - > length < = i ) {
* error = FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
return NULL ;
2021-09-07 20:55:38 +00:00
}
2021-08-29 14:26:31 +00:00
/* Loop and read. */
node_t * current = list - > head ;
for ( ; i > 0 ; i - - )
current = current - > next ;
2021-09-07 20:55:38 +00:00
/* Set the error code. */
* error = SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
/* Got to the requested node, return the stored data. */
return current - > data ;
}
/* This function retrieves a pointer to the ith node, returns NULL on failure. */
2021-09-07 20:55:38 +00:00
/* Sets the error code in error (instead of returning it). */
node_t * get_node_i_single_linked_list ( linked_list_t * list , int i , int * error ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check */
2021-09-26 19:54:52 +00:00
if ( error = = NULL )
return NULL ;
if ( list = = NULL | | list - > length < = i ) {
2021-09-07 20:55:38 +00:00
* error = FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
return NULL ;
2021-09-07 20:55:38 +00:00
}
2021-08-29 14:26:31 +00:00
/* Loop. */
node_t * current = list - > head ;
for ( ; i > 0 ; i - - )
current = current - > next ;
2021-09-07 20:55:38 +00:00
/* Set the error code. */
* error = SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
/* Got to the requested node, return the pointer. */
return current ;
}
/* This function attempts to find the index of a given node, by pointer. */
2021-09-26 14:06:57 +00:00
/* Returns -2 on invalid input, and -1 when not found. */
2021-09-04 14:18:06 +00:00
int get_node_index_pointer_single_linked_list ( linked_list_t * list , node_t * node ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
if ( list = = NULL | | node = = NULL )
2021-09-04 14:18:06 +00:00
return INVALID_INPUT_CODE_SINGLE_LINKED_LIST_C ;
2021-09-26 14:06:57 +00:00
2021-08-29 14:26:31 +00:00
/* Local variables. */
node_t * current ;
int i = 0 ;
/* Attempt to search. */
if ( list - > head = = NULL )
2021-09-04 14:18:06 +00:00
return INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
current = list - > head ;
2021-09-26 14:06:57 +00:00
while ( current ! = NULL & & current ! = node ) {
current = current - > next ;
i + + ;
}
/* Check if we found it or not. */
return ( i > = list - > length ) ? INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C : i ;
}
/* This function attempts to find the index of a given node, by data. */
/* Returns -2 on invalid input, and -1 when not found. */
2021-10-20 07:45:42 +00:00
int get_node_index_data_single_linked_list ( linked_list_t * list , void * data , int ( * comparison_function ) ( const void * , const void * ) ) {
2021-09-26 14:06:57 +00:00
/* Sanity check. */
2021-10-20 07:45:42 +00:00
if ( list = = NULL | | comparison_function = = NULL )
2021-09-26 14:06:57 +00:00
return INVALID_INPUT_CODE_SINGLE_LINKED_LIST_C ;
/* Local variables. */
node_t * current ;
int i = 0 ;
/* Check if there is anything to search in the first place. */
if ( list - > head = = NULL )
return INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C ;
/* Set the start. */
current = list - > head ;
/* Attempt to search. */
while ( current ! = NULL & & comparison_function ( data , current - > data ) ! = 0 ) {
2021-08-29 14:26:31 +00:00
current = current - > next ;
i + + ;
}
/* Check if we found it or not. */
2021-09-04 14:18:06 +00:00
return ( i > = list - > length ) ? INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C : i ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes the ith node, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int remove_node_i_single_linked_list ( linked_list_t * list , int i ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check */
if ( list = = NULL | | list - > length < = i )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Deal with the special case of the head node. */
if ( i = = 0 ) {
if ( list - > head = = NULL )
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
node_t * tmp = list - > head ;
list - > head = tmp - > next ;
tmp - > next = NULL ;
free ( tmp ) ;
( list - > length ) - - ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* Loop. */
node_t * current = list - > head ;
for ( ; i > 1 ; i - - )
current = current - > next ;
/* Got to the requested node, delete it. */
node_t * tmp = current - > next ;
current - > next = tmp - > next ;
tmp - > next = NULL ;
free ( tmp ) ;
( list - > length ) - - ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* This function deletes the ith node with the data stored within it, returns 1 on success and 0 on failure. */
/* A free function pointer of NULL value causes the use of the internal stdlib free(). */
2021-09-08 12:11:55 +00:00
int remove_node_i_data_single_linked_list ( linked_list_t * list , int i , void ( * free_function ) ( void * ) ) {
2021-08-29 14:26:31 +00:00
/* Input sanity check */
if ( list = = NULL | | list - > length < = i )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Deal with the special case of the head node. */
if ( i = = 0 ) {
if ( list - > head = = NULL )
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
node_t * tmp = list - > head ;
list - > head = tmp - > next ;
tmp - > next = NULL ;
if ( free_function = = NULL )
free ( tmp - > data ) ;
else
free_function ( tmp - > data ) ;
free ( tmp ) ;
( list - > length ) - - ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* Loop. */
node_t * current = list - > head ;
for ( ; i > 1 ; i - - )
current = current - > next ;
/* Got to the requested node, delete it. */
node_t * tmp = current - > next ;
current - > next = tmp - > next ;
tmp - > next = NULL ;
if ( free_function = = NULL )
free ( tmp - > data ) ;
else
free_function ( tmp - > data ) ;
free ( tmp ) ;
( list - > length ) - - ;
return SUCCESS_CODE_SIGNLE_LINKED_LIST_C ;
}
/* This function reads the data at the first node, note that it will return NULL on invalid input or first node being NULL. */
2021-09-08 18:24:16 +00:00
/* Sets the error code in error (instead of returning it). */
void * read_node_head_single_linked_list ( linked_list_t * list , int * error ) {
2021-08-29 14:26:31 +00:00
/* Delegate. */
2021-09-08 18:24:16 +00:00
return read_node_i_single_linked_list ( list , INDEX_HEAD_SINGLE_LINKED_LIST_C , error ) ;
2021-08-29 14:26:31 +00:00
}
/* This function retrieves the first node, note that it will return NULL on invalid input or first node being NULL. */
2021-09-08 18:24:16 +00:00
/* Sets the error code in error (instead of returning it). */
node_t * get_node_head_single_linked_list ( linked_list_t * list , int * error ) {
2021-08-29 14:26:31 +00:00
/* Delegate. */
2021-09-08 18:24:16 +00:00
return get_node_i_single_linked_list ( list , INDEX_HEAD_SINGLE_LINKED_LIST_C , error ) ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes the first node, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int remove_node_head_single_linked_list ( linked_list_t * list ) {
2021-08-29 14:26:31 +00:00
/* Delegate. */
2021-09-07 21:17:24 +00:00
return remove_node_i_single_linked_list ( list , INDEX_HEAD_SINGLE_LINKED_LIST_C ) ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes the first node and the contents thereof, returns 1 on success and 0 on failure. */
/* If the free_function is NULL, will use stdlib's free() instead. */
2021-09-08 12:11:55 +00:00
int remove_node_head_data_single_linked_list ( linked_list_t * list , void ( * free_function ) ( void * ) ) {
2021-08-29 14:26:31 +00:00
/* Delegate. */
2021-09-07 21:17:24 +00:00
return remove_node_i_data_single_linked_list ( list , INDEX_HEAD_SINGLE_LINKED_LIST_C , free_function ) ;
2021-08-29 14:26:31 +00:00
}
/* This function reads the data at the last node, will return NULL on invalid input or first node being NULL. */
2021-09-08 18:24:16 +00:00
/* Sets the error code in error (instead of returning it). */
void * read_node_tail_single_linked_list ( linked_list_t * list , int * error ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
2021-09-26 19:54:52 +00:00
if ( error = = NULL )
return NULL ;
2021-08-29 14:26:31 +00:00
if ( list = = NULL | | list - > head = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Delegate. */
2021-09-08 18:24:16 +00:00
return read_node_i_single_linked_list ( list , list - > length - 1 , error ) ;
2021-08-29 14:26:31 +00:00
}
/* This function retrieves the last node, will return NULL on invalid input or the first node being NULL. */
2021-09-08 18:24:16 +00:00
/* Sets the error code in error (instead of returning it). */
node_t * get_node_tail_single_linked_list ( linked_list_t * list , int * error ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
2021-09-26 19:54:52 +00:00
if ( error = = NULL )
return NULL ;
2021-08-29 14:26:31 +00:00
if ( list = = NULL | | list - > head = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Delegate. */
2021-09-08 18:24:16 +00:00
return get_node_i_single_linked_list ( list , list - > length - 1 , error ) ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes the last node, returns 1 on success and 0 on failure. */
2021-09-04 14:18:06 +00:00
int remove_node_tail_single_linked_list ( linked_list_t * list ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
if ( list = = NULL | | list - > head = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Delegate. */
2021-09-04 14:18:06 +00:00
return remove_node_i_single_linked_list ( list , list - > length - 1 ) ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes the last node and the data thereof, returns 1 on success and 0 on failure. */
/* If the free_function is NULL, will use stdlib's free() instead. */
2021-09-08 12:11:55 +00:00
int remove_node_tail_data_single_linked_list ( linked_list_t * list , void ( * free_function ) ( void * ) ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
if ( list = = NULL | | list - > head = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Delegate. */
2021-09-04 14:18:06 +00:00
return remove_node_i_data_single_linked_list ( list , list - > length - 1 , free_function ) ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes all the nodes of the given list and the list itself. */
/* Note that it doesn't touch the data, returns 1 on success and 0 on failure - failure is potentially undefined behavior! */
/* Will return -1 when the list was freed successfully but it was initially malformed. */
2021-09-04 14:18:06 +00:00
int clear_list_single_linked_list ( linked_list_t * * list ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
if ( list = = NULL | | * list = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Local variables. */
node_t * current = ( * list ) - > head ;
node_t * tmp ;
int length ;
int count = 0 ;
/* Loop and free. */
while ( current ! = NULL ) {
count + + ;
tmp = current - > next ;
free ( current ) ;
current = tmp ;
}
/* Save the list's length. */
length = ( * list ) - > length ;
/* Should all be freed by now, free the list and return. */
free ( * list ) ;
* list = NULL ;
2021-09-04 14:18:06 +00:00
return ( count = = length ) ? SUCCESS_CODE_SIGNLE_LINKED_LIST_C : CODE_FREE_SUCCESS_MALFORMED_SINGLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
}
/* This function deletes all the nodes and data stored within of the given list and the list itself. */
/* Returns 1 on success and 0 on failure, undefined behavior in the latter. Will return -1 when the list was freed successfully but was initially malformed. */
/* If free_function is NULL will use STDLIB free instead. */
2021-09-08 12:11:55 +00:00
int clear_list_data_single_linked_list ( linked_list_t * * list , void ( * free_function ) ( void * ) ) {
2021-08-29 14:26:31 +00:00
/* Sanity check. */
if ( list = = NULL | | * list = = NULL )
return FAILURE_CODE_SIGNLE_LINKED_LIST_C ;
/* Local variables. */
node_t * current = ( * list ) - > head ;
node_t * tmp ;
int length ;
int count = 0 ;
/* Loop and free. */
while ( current ! = NULL ) {
count + + ;
tmp = current - > next ;
if ( free_function ! = NULL ) {
free_function ( current - > data ) ;
} else {
free ( current - > data ) ;
}
free ( current ) ;
current = tmp ;
}
/* Save the list's length. */
length = ( * list ) - > length ;
/* Should all be freed by now, free the list and return. */
free ( * list ) ;
* list = NULL ;
2021-09-04 14:18:06 +00:00
return ( count = = length ) ? SUCCESS_CODE_SIGNLE_LINKED_LIST_C : CODE_FREE_SUCCESS_MALFORMED_SINGLE_LINKED_LIST_C ;
2021-08-29 14:26:31 +00:00
}
2021-10-20 07:45:42 +00:00
/* This function attetmps to serialize a linked list into an array. */
/* The function will allocate and return a pointer to said array on success, NULL on failure. */
/* The length of the array is sent through the length pointer, and set to -1 on failure. */
void * * serialize_linked_list ( linked_list_t * list , int * length ) {
/* Local variables. */
void * * array ;
node_t * current ;
int i ;
/* Sanity check. */
if ( list = = NULL | | list - > head = = NULL | | length = = NULL | | list - > length < = 0 )
return NULL ;
/* Set the length. */
* length = list - > length ;
/* Attempt to allocate the array. */
array = ( void * * ) malloc ( ( * length ) * sizeof ( void * ) ) ;
/* Check for allocation failure. */
if ( array = = NULL ) {
* length = - 1 ;
return NULL ;
}
/* Fill the array. */
current = list - > head ;
for ( i = 0 ; i < * length ; i + + ) {
array [ i ] = current - > data ;
current = current - > next ;
}
/* Return the result. */
return array ;
}