Files
exercism/c/linked-list/linked_list.c

139 lines
3.0 KiB
C

#include <malloc.h>
#include "list.h"
#include "linked_list.h"
/* How it works :
*
* The usual way to use linked lists is to have a list_head whith
* 'next' pointing to first node, and 'prev' pointing to last node.
* Each node has also 'prev' and 'next' pointers.
*
* Here, list_head points to the node own list_head structure,
* and each node list_head points to next/previous node list_head.
*
* Advantage: We don't need to manipulate the pointers, all lists
* use the same code, independently of the object (node) structure.
*/
struct list_node {
ll_data_t data;
struct list_head list;
};
/* duplicate of list_head struct
*/
struct list {
struct list_head *next, *prev;
};
/* constructs a new (empty) list
*/
struct list *list_create()
{
struct list_head *list;
if (!(list=malloc(sizeof (*list))))
return NULL;
INIT_LIST_HEAD(list);
return (struct list *) list;
}
/* counts the items on a list
*/
size_t list_count(const struct list *list_head)
{
size_t len = 0;
struct list_head *p;
list_for_each(p, (struct list_head *)list_head)
len++;
return len;
}
/* inserts item at back of a list
*/
void list_push(const struct list *list, const ll_data_t item_data)
{
struct list_node *p;
if ((p=malloc(sizeof(*p)))) {
p->data = item_data;
list_add_tail(&p->list, (struct list_head*)list);
}
}
/* deletes an element
*/
static ll_data_t _list_del(const struct list_head *list)
{
struct list_node *node;
ll_data_t data;
node = list_entry(list, struct list_node, list);
data = node->data;
list_del(&node->list);
free(node);
return data;
}
/* removes item from back of a list
*/
ll_data_t list_pop(const struct list *list)
{
return list_empty((struct list_head*)list) ? -1 : _list_del(list->prev);
}
/* inserts item at front of a list
*/
void list_unshift(const struct list *list, const ll_data_t item_data)
{
struct list_node *p;
if ((p=malloc(sizeof(*p)))) {
p->data = item_data;
list_add(&p->list, (struct list_head*)list);
}
}
/* removes item from front of a list
*/
ll_data_t list_shift(const struct list *list)
{
return list_empty((struct list_head*)list) ? -1 : _list_del(list->next);
}
/* finds a element that matches data
*/
static struct list_node *_node_find(const struct list *list, const ll_data_t data)
{
struct list_node *p;
list_for_each_entry(p, (struct list_head *)list, list) {
if (p->data == data)
return p;
}
return NULL;
}
/* deletes a node that holds the matching data
*/
void list_delete(const struct list *list, const ll_data_t data)
{
struct list_node *p;
if ((p = _node_find(list, data)))
_list_del(&p->list);
}
/* destroys an entire list
* list will be a dangling pointer after calling this method on it
*/
void list_destroy(struct list *list)
{
struct list_head *cur, *tmp;
list_for_each_safe(cur, tmp, (struct list_head *)list)
_list_del(cur);
free(list);
}