377 lines
7.9 KiB
C
377 lines
7.9 KiB
C
#include <gint/kmalloc.h>
|
|
#include <stdarg.h>
|
|
#include "linked_list.h"
|
|
|
|
elem_t *elem_create(const linked_list_t *linked_list)
|
|
{
|
|
elem_t *tmp;
|
|
tmp = kmalloc(sizeof(elem_t), NULL);
|
|
if(!tmp) return NULL;
|
|
|
|
tmp->data = kmalloc(linked_list->data_size, NULL);
|
|
if(!tmp->data)
|
|
{
|
|
kfree(tmp);
|
|
return NULL;
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
inline void destroy_elem(elem_t *elem, const deleter_t elem_deleter)
|
|
{
|
|
if(!elem) return;
|
|
|
|
if(elem_deleter)
|
|
elem_deleter(elem->data);
|
|
else
|
|
kfree(elem->data);
|
|
|
|
kfree(elem);
|
|
}
|
|
|
|
void linked_list_init(linked_list_t *linked_list, const size_t data_size, deleter_t elem_deleter)
|
|
{
|
|
linked_list->first = NULL;
|
|
linked_list->last = NULL;
|
|
linked_list->size = 0;
|
|
|
|
linked_list->data_size = data_size;
|
|
linked_list->elem_deleter = elem_deleter;
|
|
}
|
|
|
|
void linked_list_push_back_elem(linked_list_t *linked_list, elem_t *elem)
|
|
{
|
|
if(!elem) return;
|
|
|
|
elem->prev = linked_list->last;
|
|
elem->next = NULL;
|
|
|
|
if(linked_list->last)
|
|
linked_list->last->next = elem;
|
|
else
|
|
linked_list->first = elem;
|
|
|
|
linked_list->last = elem;
|
|
|
|
linked_list->size++;
|
|
}
|
|
|
|
void linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem)
|
|
{
|
|
if(!elem) return;
|
|
|
|
elem->next = linked_list->first;
|
|
elem->prev = NULL;
|
|
|
|
if(linked_list->first)
|
|
linked_list->first->prev = elem;
|
|
else
|
|
linked_list->last = elem;
|
|
|
|
linked_list->first = elem;
|
|
|
|
linked_list->size++;
|
|
}
|
|
|
|
void linked_list_push_back(linked_list_t *linked_list, void *data)
|
|
{
|
|
elem_t *tmp = kmalloc(sizeof(elem_t), NULL);
|
|
if(!tmp) return;
|
|
tmp->data = data;
|
|
|
|
linked_list_push_back_elem(linked_list, tmp);
|
|
}
|
|
|
|
void linked_list_push_front(linked_list_t *linked_list, void *data)
|
|
{
|
|
elem_t *tmp = kmalloc(sizeof(elem_t), NULL);
|
|
if(!tmp) return;
|
|
tmp->data = data;
|
|
|
|
linked_list_push_front_elem(linked_list, tmp);
|
|
}
|
|
|
|
void linked_list_pop_back(linked_list_t *linked_list)
|
|
{
|
|
elem_t *tmp = linked_list->last;
|
|
if(!tmp) return;
|
|
|
|
linked_list->last = tmp->prev;
|
|
|
|
if(linked_list->last)
|
|
linked_list->last->next = NULL;
|
|
else
|
|
linked_list->first = NULL;
|
|
|
|
destroy_elem(tmp, linked_list->elem_deleter);
|
|
|
|
linked_list->size--;
|
|
}
|
|
|
|
void linked_list_pop_front(linked_list_t *linked_list)
|
|
{
|
|
elem_t *tmp = linked_list->first;
|
|
if(!tmp) return;
|
|
|
|
linked_list->first = tmp->next;
|
|
|
|
if(linked_list->first)
|
|
linked_list->first->prev = NULL;
|
|
else
|
|
linked_list->last = NULL;
|
|
|
|
destroy_elem(tmp, linked_list->elem_deleter);
|
|
|
|
linked_list->size--;
|
|
}
|
|
|
|
void linked_list_clear(linked_list_t *linked_list)
|
|
{
|
|
elem_t *actual_elem = linked_list->first;
|
|
elem_t *tmp;
|
|
|
|
while(actual_elem)
|
|
{
|
|
tmp = actual_elem;
|
|
|
|
destroy_elem(tmp, linked_list->elem_deleter);
|
|
|
|
actual_elem = actual_elem->next;
|
|
}
|
|
|
|
linked_list->first = NULL;
|
|
linked_list->last = NULL;
|
|
|
|
linked_list->size = 0;
|
|
}
|
|
|
|
inline bool linked_list_is_empty(const linked_list_t *linked_list)
|
|
{
|
|
return !linked_list->first;
|
|
}
|
|
|
|
inline bool linked_list_is_in_bound(const linked_list_t *linked_list, const size_t index)
|
|
{
|
|
return index < linked_list->size;
|
|
}
|
|
|
|
elem_t *linked_list_get_elem(const linked_list_t *linked_list, const size_t index)
|
|
{
|
|
if(!linked_list_is_in_bound(linked_list, index)) return NULL;
|
|
|
|
if(index == 0)
|
|
return linked_list->first;
|
|
if(index == linked_list->size - 1)
|
|
return linked_list->last;
|
|
|
|
elem_t *actual_elem = linked_list->first;
|
|
if(!actual_elem) return NULL;
|
|
|
|
for (size_t i = 0; i < index; i++)
|
|
{
|
|
actual_elem = actual_elem->next;
|
|
}
|
|
|
|
return actual_elem;
|
|
}
|
|
|
|
void *linked_list_get(const linked_list_t *linked_list, const size_t index)
|
|
{
|
|
elem_t *tmp = linked_list_get_elem(linked_list, index);
|
|
if(!tmp) return NULL;
|
|
return tmp->data;
|
|
}
|
|
|
|
void linked_list_insert_elem(linked_list_t *linked_list, elem_t *elem, const size_t index)
|
|
{
|
|
if(!elem) return;
|
|
if(!linked_list_is_in_bound(linked_list, index)) return;
|
|
|
|
if(index == 0)
|
|
{
|
|
linked_list_push_front(linked_list, elem);
|
|
}
|
|
else if(index == (linked_list->size - 1))
|
|
{
|
|
linked_list_push_back(linked_list, elem);
|
|
}
|
|
else
|
|
{
|
|
elem_t *next_insert_elem = linked_list_get_elem(linked_list, index);
|
|
elem_t *prev_insert_elem = next_insert_elem->prev;
|
|
|
|
elem->prev = prev_insert_elem;
|
|
elem->next = next_insert_elem;
|
|
|
|
prev_insert_elem->next = elem;
|
|
next_insert_elem->prev = elem;
|
|
|
|
linked_list->size++;
|
|
}
|
|
}
|
|
|
|
void linked_list_insert(linked_list_t *linked_list, void *data, const size_t index)
|
|
{
|
|
elem_t *tmp = kmalloc(sizeof(elem_t), NULL);
|
|
if(!tmp) return;
|
|
tmp->data = data;
|
|
|
|
linked_list_insert_elem(linked_list, tmp, index);
|
|
}
|
|
|
|
void linked_list_remove_elem(linked_list_t *linked_list, elem_t *elem)
|
|
{
|
|
if(!elem) return;
|
|
if(!elem->prev && !elem->next) return;
|
|
|
|
if(elem == linked_list->first)
|
|
{
|
|
linked_list_pop_front(linked_list);
|
|
}
|
|
else if(elem == linked_list->last)
|
|
{
|
|
linked_list_pop_back(linked_list);
|
|
}
|
|
else
|
|
{
|
|
elem_t *prev_insert_elem = elem->prev;
|
|
elem_t *next_insert_elem = elem->next;
|
|
|
|
prev_insert_elem->next = next_insert_elem;
|
|
next_insert_elem->prev = prev_insert_elem;
|
|
|
|
destroy_elem(elem, linked_list->elem_deleter);
|
|
|
|
linked_list->size--;
|
|
}
|
|
}
|
|
|
|
void linked_list_remove(linked_list_t *linked_list, const size_t index)
|
|
{
|
|
if(!linked_list_is_in_bound(linked_list, index)) return;
|
|
|
|
elem_t *tmp = linked_list_get_elem(linked_list, index);
|
|
if(tmp) linked_list_remove_elem(linked_list, tmp);
|
|
}
|
|
|
|
elem_t *linked_list_get_elem_if(const linked_list_t *linked_list, const condition_t condition, ...)
|
|
{
|
|
if(!condition) return NULL;
|
|
|
|
va_list args;
|
|
va_start(args, condition);
|
|
|
|
elem_t *actual_elem = linked_list->first;
|
|
elem_t *next_elem;
|
|
|
|
while(actual_elem)
|
|
{
|
|
next_elem = actual_elem->next;
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
|
|
if(condition(actual_elem, args_copy))
|
|
{
|
|
va_end(args_copy);
|
|
va_end(args);
|
|
|
|
return actual_elem;
|
|
}
|
|
|
|
va_end(args_copy);
|
|
|
|
actual_elem = next_elem;
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...)
|
|
{
|
|
if(!condition) return NULL;
|
|
|
|
va_list args;
|
|
va_start(args, condition);
|
|
|
|
elem_t *actual_elem = linked_list->first;
|
|
elem_t *next_elem;
|
|
|
|
while(actual_elem)
|
|
{
|
|
next_elem = actual_elem->next;
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
|
|
if(condition(actual_elem, args_copy))
|
|
{
|
|
va_end(args_copy);
|
|
va_end(args);
|
|
|
|
return actual_elem->data;
|
|
}
|
|
|
|
va_end(args_copy);
|
|
|
|
actual_elem = next_elem;
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, ...)
|
|
{
|
|
if(!condition) return;
|
|
|
|
va_list args;
|
|
va_start(args, condition);
|
|
|
|
elem_t *actual_elem = linked_list->first;
|
|
elem_t *next_elem;
|
|
|
|
while(actual_elem)
|
|
{
|
|
next_elem = actual_elem->next;
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
|
|
if(condition(actual_elem, args_copy))
|
|
{
|
|
linked_list_remove_elem(linked_list, actual_elem);
|
|
}
|
|
|
|
va_end(args_copy);
|
|
|
|
actual_elem = next_elem;
|
|
}
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
void linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...)
|
|
{
|
|
if(!action) return;
|
|
|
|
va_list args;
|
|
va_start(args, action);
|
|
|
|
for(elem_t *actual_elem = linked_list->first; actual_elem; actual_elem = actual_elem->next)
|
|
{
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
|
|
action(actual_elem, args_copy);
|
|
|
|
va_end(args_copy);
|
|
}
|
|
|
|
va_end(args);
|
|
}
|