Initial garbage colletor implementation
This commit is contained in:
114
src/list.c
114
src/list.c
@ -4,31 +4,26 @@
|
||||
*/
|
||||
#include "refcount/list.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Build a #RefcountList from a number of elements.
|
||||
*
|
||||
* > that this will return NULL if count is 0 or if a memory allocation error
|
||||
* > occurred. However, as no allocation is preformed is count is 0, these
|
||||
* > errors should be mutually exclusive.
|
||||
*
|
||||
* Like #refcount_list_build, but lets you specify the allocator to use and
|
||||
* takes a va_list instead of variable arguments.
|
||||
* @param count The number of elements given
|
||||
* @param ... The elements from which to build the list
|
||||
* @param alloc The allocator to use
|
||||
* @param args The va_list to use to get the elements
|
||||
* @return The built list, or NULL if a memory allocation error occurred
|
||||
*/
|
||||
RefcountList *refcount_list_build(int count, ...) {
|
||||
va_list args;
|
||||
va_start(args, count);
|
||||
RefcountList *refcount_list_build_full_va(int count,
|
||||
const RefcountAllocator *alloc,
|
||||
va_list args) {
|
||||
RefcountList *start = NULL;
|
||||
RefcountList *end;
|
||||
while (count--) {
|
||||
RefcountList *new_list = refcount_malloc(sizeof(RefcountList));
|
||||
RefcountList *new_list = refcount_malloc(alloc, sizeof(RefcountList));
|
||||
if (!new_list) {
|
||||
refcount_list_free(start, NULL);
|
||||
va_end(args);
|
||||
return NULL;
|
||||
}
|
||||
new_list->data = va_arg(args, void *);
|
||||
@ -43,28 +38,30 @@ RefcountList *refcount_list_build(int count, ...) {
|
||||
end = new_list;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new #RefcountList that is a copy of list. This does no allocation if
|
||||
* the input list is NULL.
|
||||
* Same as #refcount_list_copy, but lets you specify the allocator.
|
||||
* @param list The list to copy
|
||||
* @param callback The function to copy each element of the list, or NULL
|
||||
* @param user_data Extra data to be passed to the copy callback
|
||||
* @param alloc The allocator to use
|
||||
* @return The copy, or NULL if an allocation error occurred
|
||||
*/
|
||||
RefcountList *refcount_list_copy(RefcountList *list,
|
||||
refcount_list_copy_callback_t callback) {
|
||||
RefcountList *refcount_list_copy_full(const RefcountList *list,
|
||||
refcount_list_copy_callback_t callback,
|
||||
void *user_data,
|
||||
const RefcountAllocator *alloc) {
|
||||
RefcountList *start = NULL;
|
||||
RefcountList *end;
|
||||
while (list) {
|
||||
RefcountList *new_end = refcount_malloc(sizeof(RefcountList));
|
||||
RefcountList *new_end = refcount_malloc(alloc, sizeof(RefcountList));
|
||||
if (!new_end) {
|
||||
refcount_list_free(start, NULL);
|
||||
refcount_list_free_full(start, NULL, alloc);
|
||||
return NULL;
|
||||
}
|
||||
new_end->data = callback ? callback(list->data) : list->data;
|
||||
new_end->data = callback ? callback(list->data, user_data) : list->data;
|
||||
new_end->next = NULL;
|
||||
if (!start) {
|
||||
start = new_end;
|
||||
@ -101,16 +98,18 @@ RefcountList *refcount_list_reverse(RefcountList *list) {
|
||||
/**
|
||||
* Free a #RefcountList.
|
||||
* @param list The list to free
|
||||
* @param alloc The allocator to use
|
||||
* @param callback The function to call to free each member, or NULL
|
||||
*/
|
||||
void refcount_list_free(RefcountList *list,
|
||||
refcount_list_destroy_callback_t callback) {
|
||||
void refcount_list_free_full(RefcountList *list,
|
||||
refcount_list_destroy_callback_t callback,
|
||||
const RefcountAllocator *alloc) {
|
||||
while (list) {
|
||||
RefcountList *next = list->next;
|
||||
if (callback) {
|
||||
callback(list->data);
|
||||
}
|
||||
refcount_free(list);
|
||||
refcount_free(alloc, list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
@ -120,16 +119,17 @@ void refcount_list_free(RefcountList *list,
|
||||
* @param list The list to free
|
||||
* @param callback The function to call to free each member, or NULL
|
||||
* @param data Extra data to pass to the second argument of the callback
|
||||
* @param alloc The allocator to use
|
||||
*/
|
||||
void refcount_list_free_with_data(RefcountList *list,
|
||||
refcount_list_foreach_callback_t callback,
|
||||
void *data) {
|
||||
void refcount_list_free_with_data_full(
|
||||
RefcountList *list, refcount_list_destroy_with_data_callback_t callback,
|
||||
void *data, const RefcountAllocator *alloc) {
|
||||
while (list) {
|
||||
RefcountList *next = list->next;
|
||||
if (callback) {
|
||||
callback(list->data, data);
|
||||
}
|
||||
refcount_free(list);
|
||||
refcount_free(alloc, list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
@ -139,7 +139,7 @@ void refcount_list_free_with_data(RefcountList *list,
|
||||
* @param list The list
|
||||
* @return The length of the list
|
||||
*/
|
||||
size_t refcount_list_length(RefcountList *list) {
|
||||
size_t refcount_list_length(const RefcountList *list) {
|
||||
size_t len = 0;
|
||||
while (list) {
|
||||
list = list->next;
|
||||
@ -171,41 +171,23 @@ RefcountList *refcount_list_drop(RefcountList *list, size_t n) {
|
||||
* @param n The index of the element
|
||||
* @return The Nth element of the list
|
||||
*/
|
||||
void *refcount_list_nth(RefcountList *list, size_t n) {
|
||||
RefcountList *link = refcount_list_drop(list, n);
|
||||
void *refcount_list_nth(const RefcountList *list, size_t n) {
|
||||
RefcountList *link = refcount_list_drop((RefcountList *) list, n);
|
||||
return link ? link->data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the first element from a #RefcountList. Note that you must save the
|
||||
* return value as it is the new value of the list. If the list is a sub-list,
|
||||
* the state of the larger list is undefined after this call.
|
||||
*
|
||||
* @param list The list
|
||||
* @param callback The function to call to free the removed, or NULL
|
||||
* @return The new value of the list
|
||||
*
|
||||
* @see refcount_list_remove
|
||||
*/
|
||||
RefcountList *refcount_list_pop(RefcountList *list,
|
||||
refcount_list_destroy_callback_t callback) {
|
||||
return refcount_list_remove(list, list, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a link from a #RefcountList. Note that you must save the return
|
||||
* value as it is the new value of the list.
|
||||
*
|
||||
* If the given list or link is NULL, this does nothing. It is undefined
|
||||
* behavior if link is not in list.
|
||||
*
|
||||
* The same as #refcount_list_remove, but lets you specify the allocator to use.
|
||||
* @param list The list
|
||||
* @param link The link to remove, or NULL
|
||||
* @param callback The function to call to free the member, or NULL
|
||||
* @param alloc The allocator to use
|
||||
* @return The new value of the list
|
||||
*/
|
||||
RefcountList *refcount_list_remove(RefcountList *list, RefcountList *link,
|
||||
refcount_list_destroy_callback_t callback) {
|
||||
RefcountList *
|
||||
refcount_list_remove_full(RefcountList *list, RefcountList *link,
|
||||
refcount_list_destroy_callback_t callback,
|
||||
const RefcountAllocator *alloc) {
|
||||
if (!list || !link) {
|
||||
return list;
|
||||
}
|
||||
@ -219,20 +201,22 @@ RefcountList *refcount_list_remove(RefcountList *list, RefcountList *link,
|
||||
if (callback) {
|
||||
callback(link->data);
|
||||
}
|
||||
refcount_free(link);
|
||||
refcount_free(alloc, link);
|
||||
return list == link ? rest : list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element to the start of a #RefcountList. Note that you must save the
|
||||
* return value as it is the new value of the list.
|
||||
* The same as #refcount_list_push, but lets you specify the allocator to
|
||||
* use.
|
||||
* @param list The list
|
||||
* @param element The element to add
|
||||
* @param alloc The allocator to use
|
||||
* @return The new value of the list, or NULL if allocation of the new node
|
||||
* failed
|
||||
*/
|
||||
RefcountList *refcount_list_push(RefcountList *list, void *element) {
|
||||
RefcountList *new_head = refcount_malloc(sizeof(RefcountList));
|
||||
RefcountList *refcount_list_push_full(RefcountList *list, void *element,
|
||||
const RefcountAllocator *alloc) {
|
||||
RefcountList *new_head = refcount_malloc(alloc, sizeof(RefcountList));
|
||||
if (!new_head) {
|
||||
return NULL;
|
||||
}
|
||||
@ -283,15 +267,17 @@ RefcountList *refcount_list_join(RefcountList *list1, RefcountList *list2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element to the end of a #RefcountList. Note that you must save the
|
||||
* return value as it is the new value of the list.
|
||||
* The same as #refcount_list_push_back, but lets you specify the allocator to
|
||||
* use.
|
||||
* @param list The list
|
||||
* @param element The element to add
|
||||
* @param alloc The allocator to use
|
||||
* @return The new value of the list, or NULL if allocation of the new node
|
||||
* failed
|
||||
*/
|
||||
RefcountList *refcount_list_push_back(RefcountList *list, void *element) {
|
||||
RefcountList *new_end = refcount_malloc(sizeof(RefcountList));
|
||||
RefcountList *refcount_list_push_back_full(RefcountList *list, void *element,
|
||||
const RefcountAllocator *alloc) {
|
||||
RefcountList *new_end = refcount_malloc(alloc, sizeof(RefcountList));
|
||||
if (!new_end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user