mirror of
https://github.com/UberGames/rpgxEF.git
synced 2024-11-10 07:11:34 +00:00
Copied list module to cgame for future use
This commit is contained in:
parent
6b2b41500c
commit
99dce191c3
3 changed files with 778 additions and 0 deletions
|
@ -5,6 +5,7 @@
|
||||||
#include "tr_types.h"
|
#include "tr_types.h"
|
||||||
#include "../game/bg_public.h"
|
#include "../game/bg_public.h"
|
||||||
#include "cg_public.h"
|
#include "cg_public.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
// The entire cgame module is unloaded and reloaded on each level change,
|
// The entire cgame module is unloaded and reloaded on each level change,
|
||||||
// so there is NO persistant data between levels on the client side.
|
// so there is NO persistant data between levels on the client side.
|
||||||
|
|
614
code/cgame/list.c
Normal file
614
code/cgame/list.c
Normal file
|
@ -0,0 +1,614 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2013 Ubergames
|
||||||
|
|
||||||
|
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 "list.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list_iter object for the linked_list list. The flag init can be
|
||||||
|
* either LIST_FRONT or LIST_BACK and indicates whether to start the iterator from the first
|
||||||
|
* or last item in the list
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param init indicator where to start from
|
||||||
|
* \return A new list iterator.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static list_iter_p list_iterator(list_p list, char init) {
|
||||||
|
list_iter_p iter = (list_iter_p)malloc(sizeof(struct list_iter));
|
||||||
|
|
||||||
|
if(iter == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(init == LIST_FRONT) {
|
||||||
|
iter->current = list->first;
|
||||||
|
} else if(init == LIST_BACK) {
|
||||||
|
iter->current = list->last;
|
||||||
|
} else { // asume front
|
||||||
|
iter->current = list->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->list = list;
|
||||||
|
iter->started = 0;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an item with the given value, type, and size to the list.
|
||||||
|
* The data is copied by value, so the original pointer must be freed if it
|
||||||
|
* was allocated on the heap.
|
||||||
|
* Returns the length of the list if succesfull else returns 0.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param data pointer to data
|
||||||
|
* \param type type of data
|
||||||
|
* \param size size of data
|
||||||
|
* \param end indicator where to add the data
|
||||||
|
* \return Count of elements in the list
|
||||||
|
*/
|
||||||
|
static int list_add(list_p list, void* data, dataType_t type, size_t size, char end) {
|
||||||
|
lnode_p node = (lnode_p)malloc(sizeof(struct linked_node));
|
||||||
|
|
||||||
|
node->cont = (container_p)malloc(sizeof(container));
|
||||||
|
if(node->cont == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->cont->type = type;
|
||||||
|
node->cont->data = malloc(size);
|
||||||
|
if(node->cont->data == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(node->cont->data, data, size);
|
||||||
|
node->cont->pointer = 0;
|
||||||
|
node->cont->size = size;
|
||||||
|
|
||||||
|
if(list->first == NULL) {
|
||||||
|
node->prev = NULL;
|
||||||
|
node->next = NULL;
|
||||||
|
list->first = node;
|
||||||
|
list->last = node;
|
||||||
|
} else if(end == LIST_BACK) {
|
||||||
|
list->last->next = node;
|
||||||
|
node->prev = list->last;
|
||||||
|
node->next = NULL;
|
||||||
|
list->last = node;
|
||||||
|
} else if(end == LIST_FRONT) {
|
||||||
|
list->first->prev = node;
|
||||||
|
node->next = list->first;
|
||||||
|
node->prev = NULL;
|
||||||
|
list->first = node;
|
||||||
|
} else { // assume back
|
||||||
|
list->last->next = node;
|
||||||
|
node->prev = list->last;
|
||||||
|
node->next = NULL;
|
||||||
|
list->last = node;
|
||||||
|
}
|
||||||
|
list->length++;
|
||||||
|
|
||||||
|
return list->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an item with the given calue, type, and size to the end of the list.
|
||||||
|
* The data is copied by value, so the original pointer must be freed if it
|
||||||
|
* was allocated on the heap.
|
||||||
|
* Returns the length of the list if successfull else returns 0.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param data pointer to data
|
||||||
|
* \param type type of data
|
||||||
|
* \param size size of data
|
||||||
|
* \return Count of elements in the list
|
||||||
|
*/
|
||||||
|
static int list_append(list_p list, void* data, dataType_t type, size_t size) {
|
||||||
|
return list_add(list, data, type, size, LIST_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an item with the given calue, type, and size to the front of the list.
|
||||||
|
* The data is copied by value, so the original pointer must be freed if it
|
||||||
|
* was allocated on the heap.
|
||||||
|
* Returns the length of the list if successfull else returns 0.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param data pointer to data
|
||||||
|
* \param type type of data
|
||||||
|
* \param size size of data
|
||||||
|
* \return Count of elements in the list
|
||||||
|
*/
|
||||||
|
static int list_prepend(list_p list, void* data, dataType_t type, size_t size) {
|
||||||
|
return list_add(list, data, type, size, LIST_FRONT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a pointer to an item with the given value and type to the list.
|
||||||
|
* Returns the length of the list if succesfull else returns 0.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param data pointer to data
|
||||||
|
* \param type type of the data
|
||||||
|
* \param end indicator where to insert
|
||||||
|
* \return Count of elements in the list
|
||||||
|
*/
|
||||||
|
static int list_add_ptr(list_p list, void* data, dataType_t type, char end) {
|
||||||
|
lnode_p node = (lnode_p)malloc(sizeof(struct linked_node));
|
||||||
|
|
||||||
|
node->cont = (container_p)malloc(sizeof(container));
|
||||||
|
if(node->cont == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->cont->type = type;
|
||||||
|
node->cont->data = data;
|
||||||
|
node->cont->pointer = 1;
|
||||||
|
node->cont->size = 0;
|
||||||
|
|
||||||
|
if(list->first == NULL) {
|
||||||
|
node->prev = NULL;
|
||||||
|
node->next = NULL;
|
||||||
|
list->first = node;
|
||||||
|
list->last = node;
|
||||||
|
} else if(end == LIST_BACK) {
|
||||||
|
list->last->next = node;
|
||||||
|
node->prev = list->last;
|
||||||
|
node->next = NULL;
|
||||||
|
list->last = node;
|
||||||
|
} else if(end == LIST_FRONT) {
|
||||||
|
list->first->prev = node;
|
||||||
|
node->next = list->first;
|
||||||
|
node->prev = NULL;
|
||||||
|
list->first = node;
|
||||||
|
} else { // assume back
|
||||||
|
list->last->next = node;
|
||||||
|
node->prev = list->last;
|
||||||
|
node->next = NULL;
|
||||||
|
list->last = node;
|
||||||
|
}
|
||||||
|
list->length++;
|
||||||
|
|
||||||
|
return list->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a pointer to an item with the given calue, type, and size to the end of the list.
|
||||||
|
* Returns the length of the list if successfull else returns 0.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param data pointer to data
|
||||||
|
* \param type type of data
|
||||||
|
* \return Count of elements in list
|
||||||
|
*/
|
||||||
|
static int list_append_ptr(list_p list, void* data, dataType_t type) {
|
||||||
|
return list_add_ptr(list, data, type, LIST_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a pointer to an item with the given calue, type, and size to the front of the list.
|
||||||
|
* Returns the length of the list if successfull else returns 0.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param data pointer to data
|
||||||
|
* \param type type of data
|
||||||
|
* \return Count of elements in list
|
||||||
|
*/
|
||||||
|
static int list_prepend_ptr(list_p list, void* data, dataType_t type) {
|
||||||
|
return list_add_ptr(list, data, type, LIST_FRONT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the data held by the current item pointed to by the iterator
|
||||||
|
*
|
||||||
|
* \param list pointer to a iterator
|
||||||
|
* \return container for the current element
|
||||||
|
*/
|
||||||
|
static container_p list_current(list_iter_p iter){
|
||||||
|
if(iter->started && iter->current != NULL) {
|
||||||
|
return iter->current->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances the iterator to the next item in the list and returns the data
|
||||||
|
* stored there.
|
||||||
|
*
|
||||||
|
* \param list pointer to a iterator
|
||||||
|
* \return container of the next element
|
||||||
|
*/
|
||||||
|
static container_p list_next(list_iter_p iter) {
|
||||||
|
if(!iter->started && iter->current != NULL) {
|
||||||
|
iter->started = 1;
|
||||||
|
return iter->current->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter->current != NULL) {
|
||||||
|
iter->current = iter->current->next;
|
||||||
|
return list_current(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances the iterator to the next item in the list and returns the data
|
||||||
|
* stored there. If the end of the list is reached it continues with the first
|
||||||
|
* element of the list.
|
||||||
|
*
|
||||||
|
* \param list pointer to a iterator
|
||||||
|
* \return container of the next element
|
||||||
|
*/
|
||||||
|
static container_p list_cycl_next(list_iter_p iter) {
|
||||||
|
if(!iter->started && iter->current != NULL) {
|
||||||
|
iter->started = 1;
|
||||||
|
return iter->current->cont;
|
||||||
|
}
|
||||||
|
if(iter->current != NULL) {
|
||||||
|
iter->current = iter->current->next;
|
||||||
|
if(iter->current == NULL) {
|
||||||
|
iter->current = iter->list->first;
|
||||||
|
}
|
||||||
|
return list_current(iter);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances the iterator to the previous item in the list and returns the data
|
||||||
|
* stored there.
|
||||||
|
*
|
||||||
|
* \param list pointer to a iterator
|
||||||
|
* \return container of the previous element
|
||||||
|
*/
|
||||||
|
static container_p list_prev(list_iter_p iter) {
|
||||||
|
if(!iter->started&&iter->current!=NULL) {
|
||||||
|
iter->started = 1;
|
||||||
|
return iter->current->cont;
|
||||||
|
}
|
||||||
|
if(iter->current!=NULL) {
|
||||||
|
iter->current = iter->current->prev;
|
||||||
|
return list_current(iter);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances the iterator to the previous item in the list and returns the data
|
||||||
|
* stored there. If the start of the list is reached it continues with the last
|
||||||
|
* element of the list.
|
||||||
|
*
|
||||||
|
* \param list pointer to a iterator
|
||||||
|
* \return container of the previous element
|
||||||
|
*/
|
||||||
|
static container_p list_cycl_prev(list_iter_p iter){
|
||||||
|
if(!iter->started && iter->current != NULL) {
|
||||||
|
iter->started =1 ;
|
||||||
|
return iter->current->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter->current!=NULL) {
|
||||||
|
iter->current = iter->current->prev;
|
||||||
|
if(iter->current == NULL) {
|
||||||
|
iter->current = iter->list->last;
|
||||||
|
}
|
||||||
|
return list_current(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data stored in the first item of the list or NULL if the list is empty
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \return container for the first element of the list
|
||||||
|
*/
|
||||||
|
static container_p list_first(list_p list) {
|
||||||
|
return list->first->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data stored in the last item of the list or NULL if the list is empty
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \return container for the last element of the list
|
||||||
|
*/
|
||||||
|
static container_p list_last(list_p list) {
|
||||||
|
return list->last->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the last item in the list (LIFO order) and returns the data stored
|
||||||
|
* there. The data returned must be freed later in order to remain memory safe.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \return container for the last element of the list
|
||||||
|
*/
|
||||||
|
static container_p list_pop(list_p list) {
|
||||||
|
container_p cont;
|
||||||
|
lnode_p last = list->last;
|
||||||
|
|
||||||
|
if(last == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->last = last->prev;
|
||||||
|
cont = last->cont;
|
||||||
|
|
||||||
|
if(last->prev != NULL) {
|
||||||
|
last->prev->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(last);
|
||||||
|
list->length--;
|
||||||
|
|
||||||
|
if(list->length == 0) {
|
||||||
|
list->last = list->first = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the first item in the list (FIFO order) and returns the data stored
|
||||||
|
* there. The data return must be freed later in order to remain memory safe.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \return container for the first element of the list
|
||||||
|
*/
|
||||||
|
static container_p list_poll(list_p list){
|
||||||
|
container_p cont;
|
||||||
|
lnode_p first = list->first;
|
||||||
|
|
||||||
|
if(first == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->first = first->next;
|
||||||
|
cont = first->cont;
|
||||||
|
|
||||||
|
if(first->next != NULL) {
|
||||||
|
first->next->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(first);
|
||||||
|
list->length--;
|
||||||
|
|
||||||
|
if(list->length == 0) {
|
||||||
|
list->last = list->first = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for completely destroying an item in the list. If the end
|
||||||
|
* flag is LIST_FRONT, an item will be polled from the front of the list and its data
|
||||||
|
* freed. If the end flag is set to LIST_BACK, an item will be popped off the end of
|
||||||
|
* the list and the data freed.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param end indicator where to remove
|
||||||
|
*/
|
||||||
|
static void list_remove(list_p list, char end) {
|
||||||
|
container_p cont;
|
||||||
|
|
||||||
|
if(end == LIST_FRONT) {
|
||||||
|
cont = list_poll(list);
|
||||||
|
} else if (end == LIST_BACK) {
|
||||||
|
cont = list_pop(list);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cont != NULL) {
|
||||||
|
if(cont->pointer == 0 && cont->data != NULL) {
|
||||||
|
list->destructor(cont->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for completely destroying an item in the list at a given index.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
* \param idx index of the element to remove
|
||||||
|
*/
|
||||||
|
static void list_remove_at(list_p list, int idx) {
|
||||||
|
container_p cont;
|
||||||
|
list_iter_p iter;
|
||||||
|
lnode_p target = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(idx < 0 || idx >= list->length || list->length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = list_iterator(list, LIST_FRONT);
|
||||||
|
for(cont = list_next(iter), i = 0; cont != NULL; cont = list_next(iter), i++) {
|
||||||
|
if(i == idx) {
|
||||||
|
target = iter->current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destroy_iterator(iter);
|
||||||
|
|
||||||
|
if(target == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(list->length == 1) {
|
||||||
|
list->first = list->last = NULL;
|
||||||
|
list->length--;
|
||||||
|
|
||||||
|
free(target);
|
||||||
|
} else {
|
||||||
|
target->prev->next = target->next;
|
||||||
|
target->next->prev = target->prev;
|
||||||
|
|
||||||
|
if(target == list->first) {
|
||||||
|
list->first = target->next;
|
||||||
|
}
|
||||||
|
if(target == list->last) {
|
||||||
|
list->last = target->prev;
|
||||||
|
}
|
||||||
|
list->length--;
|
||||||
|
|
||||||
|
free(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cont != NULL) {
|
||||||
|
if(cont->pointer == 0 && cont->data != NULL) {
|
||||||
|
list->destructor(cont->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_list(list_p list) {
|
||||||
|
lnode_p cur = list->first;
|
||||||
|
lnode_p next;
|
||||||
|
|
||||||
|
while(cur!=NULL){
|
||||||
|
next = cur->next;
|
||||||
|
if(list->destructor != NULL) { // only destroy data if there is a destructor set
|
||||||
|
if(cur->cont->pointer == 0 && cur->cont->data != NULL) {
|
||||||
|
list->destructor(cur->cont->data);
|
||||||
|
}
|
||||||
|
free(cur->cont);
|
||||||
|
}
|
||||||
|
free(cur);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all elements.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
*/
|
||||||
|
static void list_clear(list_p list) {
|
||||||
|
while(list->length > 0) {
|
||||||
|
list_remove(list, LIST_BACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_iterator(list_iter_p iter) {
|
||||||
|
if(iter == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the element at the given index.
|
||||||
|
*
|
||||||
|
* \param list a list
|
||||||
|
* \param idx index
|
||||||
|
* \return element at given index or NULL if index is out of bounds
|
||||||
|
*/
|
||||||
|
static container_p list_at(list_p list, int idx) {
|
||||||
|
list_iter_p iter;
|
||||||
|
container_p c = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(idx < 0 || idx >= list->length || list == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = list_iterator(list, LIST_FRONT);
|
||||||
|
for(c = list_next(iter), i = 0; c != NULL; c = list_next(iter), i++) {
|
||||||
|
if(i == idx) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_p create_list() {
|
||||||
|
list_p list = (list_p)malloc(sizeof(struct list));
|
||||||
|
|
||||||
|
if(list == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->length = 0;
|
||||||
|
list->first = NULL;
|
||||||
|
list->last = NULL;
|
||||||
|
list->destructor = free;
|
||||||
|
list->add = list_add;
|
||||||
|
list->add_ptr = list_add_ptr;
|
||||||
|
list->append = list_append;
|
||||||
|
list->append_ptr = list_append_ptr;
|
||||||
|
list->at = list_at;
|
||||||
|
list->clear = list_clear;
|
||||||
|
list->current = list_current;
|
||||||
|
list->cycl_next = list_cycl_next;
|
||||||
|
list->cycl_prev = list_cycl_prev;
|
||||||
|
list->end = list_first;
|
||||||
|
list->front = list_last;
|
||||||
|
list->iterator = list_iterator;
|
||||||
|
list->next = list_next;
|
||||||
|
list->poll = list_poll;
|
||||||
|
list->pop = list_pop;
|
||||||
|
list->prepend = list_prepend;
|
||||||
|
list->prepend_ptr = list_prepend_ptr;
|
||||||
|
list->prev = list_prev;
|
||||||
|
list->remove = list_remove;
|
||||||
|
list->removeAt = list_remove_at;
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_init(struct list * l, void (*destructor)(void*)) {
|
||||||
|
memset(l, 0, sizeof(struct list));
|
||||||
|
l->destructor = destructor;
|
||||||
|
l->add = list_add;
|
||||||
|
l->add_ptr = list_add_ptr;
|
||||||
|
l->append = list_append;
|
||||||
|
l->append_ptr = list_append_ptr;
|
||||||
|
l->at = list_at;
|
||||||
|
l->clear = list_clear;
|
||||||
|
l->current = list_current;
|
||||||
|
l->cycl_next = list_cycl_next;
|
||||||
|
l->cycl_prev = list_cycl_prev;
|
||||||
|
l->end = list_first;
|
||||||
|
l->front = list_last;
|
||||||
|
l->iterator = list_iterator;
|
||||||
|
l->next = list_next;
|
||||||
|
l->poll = list_poll;
|
||||||
|
l->pop = list_pop;
|
||||||
|
l->prepend = list_prepend;
|
||||||
|
l->prepend_ptr = list_prepend_ptr;
|
||||||
|
l->prev = list_prev;
|
||||||
|
l->remove = list_remove;
|
||||||
|
l->removeAt = list_remove_at;
|
||||||
|
}
|
||||||
|
|
163
code/cgame/list.h
Normal file
163
code/cgame/list.h
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2013 Ubergames
|
||||||
|
|
||||||
|
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 __LIBDS_LIST_H__
|
||||||
|
#define __LIBDS_LIST_H__
|
||||||
|
|
||||||
|
/* A C implementation of a doubly-linked list. Contains void pointer values.
|
||||||
|
Can be used as a LIFO stack of FIFO queue. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define LIST_FRONT 0
|
||||||
|
#define LIST_BACK 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible type the data in a container may have.
|
||||||
|
* LT_DATA means that a custom struct was added.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LT_BOOLEAN,
|
||||||
|
LT_CHAR,
|
||||||
|
LT_UNSIGNED_CHAR,
|
||||||
|
LT_SHORT,
|
||||||
|
LT_UNSIGNED_SHORT,
|
||||||
|
LT_INT,
|
||||||
|
LT_UNSIGNED_INT,
|
||||||
|
LT_LONG,
|
||||||
|
LT_UNSIGNED_LONG,
|
||||||
|
LT_DOUBLE,
|
||||||
|
LT_STRING,
|
||||||
|
LT_DATA,
|
||||||
|
LT_MAX
|
||||||
|
} dataType_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for data added to the list.
|
||||||
|
* Use of a container allows to add standard c types to the list
|
||||||
|
* without the need to embed them into a struct.
|
||||||
|
*/
|
||||||
|
struct container {
|
||||||
|
void* data; /*!< pointer to the data */
|
||||||
|
size_t size; /*!< size of the data */
|
||||||
|
dataType_t type; /*!< type of the data */
|
||||||
|
char pointer; /*!< determin if the data is a pointer */
|
||||||
|
} container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for a pointer to a container.
|
||||||
|
*/
|
||||||
|
typedef struct container* container_p;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node for a double linked list.
|
||||||
|
*/
|
||||||
|
struct linked_node {
|
||||||
|
container_p cont; /*!< cointainer with the data */
|
||||||
|
struct linked_node* next; /*!< next list element */
|
||||||
|
struct linked_node* prev; /*!< previous list element */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for a pointer to a node.
|
||||||
|
*/
|
||||||
|
typedef struct linked_node* lnode_p;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for a pointer to a list iterator.
|
||||||
|
*/
|
||||||
|
typedef struct list_iter * list_iter_p;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for a pointer to a list.
|
||||||
|
*/
|
||||||
|
typedef struct list * list_p;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct describing a list.
|
||||||
|
*/
|
||||||
|
struct list{
|
||||||
|
int length; /*!< count of elements in the list */
|
||||||
|
lnode_p first; /*!< first element of the list */
|
||||||
|
lnode_p last; /*!< last element of the list */
|
||||||
|
void (*destructor)(void*); /*!< pointer to destructor for data. Default is free. */
|
||||||
|
list_iter_p (*iterator)(list_p list, char init); /*!< creates a new list iterator */
|
||||||
|
int (*add_ptr)(list_p list, void* data, dataType_t type, char end); /*!< add a pointer to the list */
|
||||||
|
int (*append_ptr)(list_p list, void* data, dataType_t type); /*!< append a pointer to the list */
|
||||||
|
int (*prepend_ptr)(list_p list, void* data, dataType_t type); /*!< prepend a pointer to the list */
|
||||||
|
int (*add)(list_p list, void* data, dataType_t type, size_t size, char end); /*!< add data to the list */
|
||||||
|
int (*append)(list_p list, void* data, dataType_t type, size_t size); /*!< append data to the list */
|
||||||
|
int (*prepend)(list_p list, void* data, dataType_t type, size_t size); /*!< prepend data to the list */
|
||||||
|
container_p (*at)(list_p list, int idx); /*!< get container at given index */
|
||||||
|
void (*clear)(list_p list); /*!< clear the list */
|
||||||
|
container_p (*current)(list_iter_p iter); /*!< get the current element for the iterator */
|
||||||
|
container_p (*cycl_next)(list_iter_p iter); /*!< get the next element for the iterator (cyclic access) */
|
||||||
|
container_p (*cycl_prev)(list_iter_p iter); /*!< get the previous element for the iterator (cyclic acccess) */
|
||||||
|
container_p (*front)(list_p list); /*!< get the first element of the list */
|
||||||
|
container_p (*end)(list_p list); /*!< get the last element of the list */
|
||||||
|
container_p (*next)(list_iter_p iter); /*!< get the next element for the iterator */
|
||||||
|
container_p (*prev)(list_iter_p iter); /*!< get the previous element for the iterator */
|
||||||
|
container_p (*poll)(list_p list); /*<! poll */
|
||||||
|
container_p (*pop)(list_p list); /*<! pop */
|
||||||
|
void (*remove)(list_p list, char end); /*!< remove an element from the list */
|
||||||
|
void (*removeAt)(list_p list, int idx); /*!< remove an element at a specified index */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct describing a list iterator.
|
||||||
|
*/
|
||||||
|
struct list_iter {
|
||||||
|
list_p list; /*!< the list */
|
||||||
|
lnode_p current; /*!< current node */
|
||||||
|
char started; /*!< has iteration started */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a linked_list object. This pointer is created on the heap and must be
|
||||||
|
* cleared with a call to destroy_list to avoid memory leaks.
|
||||||
|
*
|
||||||
|
* \return A new list allocated on the heap.
|
||||||
|
*/
|
||||||
|
list_p create_list(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely free the data associated with the list.
|
||||||
|
*
|
||||||
|
* \param list pointer to a list
|
||||||
|
*/
|
||||||
|
void destroy_list(list_p list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a list iterator if allocated.
|
||||||
|
*
|
||||||
|
* \param list pointer to a iterator
|
||||||
|
*/
|
||||||
|
void destroy_iterator(list_iter_p iter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize list. For use on lists that are NOT allocated on the heap.
|
||||||
|
*
|
||||||
|
* \param l a list
|
||||||
|
* \param destructor pointer to destructor function
|
||||||
|
*/
|
||||||
|
void list_init(struct list * l, void (*destructor)(void*));
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue