parent
ac62f6ccb5
commit
7cdcf0fbe3
@ -0,0 +1,29 @@
|
||||
SRC:=src/*.c
|
||||
INCLUDE:=include/
|
||||
CFLAGS:=-g -Wall -pedantic
|
||||
LFLAGS:=
|
||||
BUILD:=build
|
||||
OBJ:=obj
|
||||
|
||||
TEST_SRC:=src/test/main.c
|
||||
|
||||
ifeq ($(shell uname), Linux)
|
||||
TARGET_TEST_EXT =
|
||||
else
|
||||
TARGET_TEST_EXT = .exe
|
||||
endif
|
||||
|
||||
all: clean test
|
||||
|
||||
clean:
|
||||
rm -f $(BUILD)/*
|
||||
rm -f $(OBJ)/*
|
||||
|
||||
liblist:
|
||||
gcc -c $(CFLAGS) -I$(INCLUDE) $(SRC)
|
||||
mv *.o $(OBJ)/
|
||||
ar rcs $(BUILD)/$@.a $(OBJ)/*.o
|
||||
|
||||
test: liblist
|
||||
gcc $(TEST_SRC) $(CFLAGS) -I$(INCLUDE) -o $(BUILD)/$@$(TARGET_TEST_EXT) $(LFLAGS) $(BUILD)/liblist.a
|
||||
$(BUILD)/$@$(TARGET_TEST_EXT)
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,101 @@
|
||||
#ifndef _LIST_H
|
||||
#define _LIST_H
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define L_DEFAULT_BLOCKSIZE 16
|
||||
|
||||
/* Functional Macros */
|
||||
|
||||
#define l_create_d(type) l_create(type, L_DEFAULT_BLOCKSIZE)
|
||||
#define l_create_from_d(from, length, type) l_create_from(from,length, type, L_DEFAULT_BLOCKSIZE)
|
||||
#define l_get_v(list,index, type) *(type*)l_get(list,index)
|
||||
|
||||
/** Returns 1 if <index> is a valid index for <t> **/
|
||||
#define l_bcheck(t, index) (index>=0&&index<t->length)
|
||||
|
||||
/* Enums */
|
||||
|
||||
typedef enum {
|
||||
QUICKSORT
|
||||
} _l_sort_alg;
|
||||
|
||||
/* Structures */
|
||||
|
||||
struct l_block {
|
||||
struct l_block* next;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
size_t type;
|
||||
int blocksize;
|
||||
struct l_block* block0;
|
||||
} list_t;
|
||||
|
||||
typedef struct {
|
||||
list_t *list;
|
||||
void* element;
|
||||
int index;
|
||||
} l_iterator;
|
||||
|
||||
/* Function Pointers */
|
||||
|
||||
#define L_P_FUNCTION(name) int lp_ ## name(const list_t *list, int index)
|
||||
#define L_A_FUNCTION(name) void la_ ## name(const list_t *list, int index)
|
||||
#define L_C_FUNCTION(name) int lc_ ## name(const list_t *list, int i1, int i2)
|
||||
typedef int (*_l_predicate)(const list_t *, int); /** Takes (list), (index). Returns non-zero if true **/
|
||||
typedef int (*_l_comparator)(const list_t*, int,int); /** Takes (list), (i1), (i2). Returns 0 if equal, -1 if <i1> goes before <i2>, +1 if <i1> goes after <i2> **/
|
||||
typedef void (*_l_action)(const list_t*, int); /** Takes (list), (index) **/
|
||||
|
||||
/* Functions */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
list_t* l_create(size_t type,int blocksize); /** Allocates new list_t aligned to size <type> (e.g. "sizeof(int)"), and first block with <blocksize> (use l_create_d(size_t) to use default blocksize) **/
|
||||
list_t* l_create_from(void* from, int items, size_t type, int bs); /** Allocates new list_t and copies elements from <from> into it **/
|
||||
void l_destroy(list_t *t); /** Frees all memory alocated to <t> and then frees <t> **/
|
||||
void l_add(list_t *t, const void* o); /** Adds new element at end of array with copy of data at <o>, then updates ->length pointer **/
|
||||
void* l_get(const list_t *t, int index); /** Returns pointer to element at <index> **/
|
||||
void l_nullify(list_t *t, int index); /** Writes over element at <index> with 0s (bytes) **/
|
||||
void l_copy(const list_t* src,int so,list_t* de, int o,int len); /** Copies <len> elements from <src> (offset by <so>) to <de> (offset by <o>) **/
|
||||
void l_copy_ar(const list_t* src, int so, void* dest, int len); /** Copies <len> elements from <src> (offset by <so>) to <dest> **/
|
||||
void* l_toarray_n(const list_t *t, int* size, _l_predicate p); /** Creates a new array and copies each element that satisfies <p>, or if <p> is NULL, all of them. Size of the new array is returned in <size> unless <size> is NULL **/
|
||||
void l_toarray(const list_t *t, void* dest, size_t len); /** Copies <len> elements from <t> to <dest> **/
|
||||
int l_isnull(const list_t *t, int index); /** Returns 1 if all bytes of element at <index> are 0 **/
|
||||
void l_nullify_if(list_t *t, _l_predicate f); /** Nullifies elements that satisfy <f> **/
|
||||
void l_do(list_t *t, _l_action act); /** Calls <act> on all elements of <t> **/
|
||||
void l_do_if(list_t *t, _l_action act, _l_predicate f); /** Calls <act> on elements that satisfy <f> **/
|
||||
void l_swap(list_t *t, int index1, int index2); /** Swap elements at <index1> and <index2> **/
|
||||
void l_sort(list_t *t, _l_sort_alg alg, _l_comparator comp); /** Sorts <t> with algorithm <alg> using comparator <comp> **/
|
||||
list_t* l_clone(const list_t *t); /** Creates new list from <t> **/
|
||||
list_t* l_clone_if(const list_t *t, _l_predicate f); /** Creates new list from <t> with all elements that satisfy <f> **/
|
||||
|
||||
l_iterator li_create(list_t *list); /** Creates iterator from <list> and initialises at index 0 **/
|
||||
int li_next(l_iterator *it); /** Updates current element and increments pointer in <it> and returns non-zero if index is in bounds **/
|
||||
void* li_get(l_iterator *i); /** Updates and returns current element of iterator, or NULL if not in bounds **/
|
||||
void* li_iterate(l_iterator *i); /** Updates and returns current element of iterator and increments pointer, or returns NULL if not in bounds **/
|
||||
void* li_set(l_iterator *i,int index); /** Sets current index to <index> then updates and returns current element, or NULL if index is not in bounds **/
|
||||
|
||||
|
||||
/* Predefined Predicates */
|
||||
|
||||
L_P_FUNCTION(not_null); /** Allows all non-null elements **/
|
||||
|
||||
/* Predefined Actions */
|
||||
|
||||
L_A_FUNCTION(assert_zero); /** Call assert(0) **/
|
||||
|
||||
/* Predefined Comparators */
|
||||
|
||||
L_C_FUNCTION(int_a); /** Ascending sort for (int) type **/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIST_H */
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,335 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <list.h>
|
||||
|
||||
#define l_block struct l_block
|
||||
|
||||
void _l_quicksort(list_t *arr, int left, int right, _l_comparator comp);
|
||||
|
||||
static int _mem_isnull(unsigned char* data, size_t le)
|
||||
{
|
||||
unsigned char b = 0;
|
||||
register int i=0;
|
||||
for(;b==0&&i<le;i++)
|
||||
b |= data[i];
|
||||
return b==0;
|
||||
}
|
||||
|
||||
static l_block* _l_create_block(size_t type,int blocksize)
|
||||
{
|
||||
l_block* block= (l_block*) malloc(sizeof(l_block*) + ( blocksize*type));
|
||||
memset(block, 0, sizeof(l_block*) + ( blocksize*type));
|
||||
return block;
|
||||
}
|
||||
|
||||
static l_block* _l_next_block(l_block* block)
|
||||
{
|
||||
return block->next;
|
||||
}
|
||||
|
||||
static l_block* _l_block_skip(l_block* block, int skip)
|
||||
{
|
||||
l_block* c = block;
|
||||
register int i=0;
|
||||
for(;i<skip;i++) if( (c = c->next) == NULL) break;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void* _l_at(l_block* block, size_t size, int index)
|
||||
{
|
||||
return (void*)(&block->data[index*size]);
|
||||
}
|
||||
|
||||
list_t *l_create(size_t type,int bs)
|
||||
{
|
||||
list_t *list = (list_t*)malloc(sizeof(list_t));
|
||||
list->length=0;
|
||||
list->blocksize = bs;
|
||||
list->type = type;
|
||||
list->block0 = _l_create_block(type,bs);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void l_destroy(list_t *t)
|
||||
{
|
||||
l_block* next=NULL;
|
||||
l_block* current = t->block0;
|
||||
do
|
||||
{
|
||||
next = _l_next_block(current);
|
||||
free(current);
|
||||
current = next;
|
||||
} while(next!=NULL);
|
||||
free(t);
|
||||
}
|
||||
|
||||
void l_copy(const list_t* src,int src_offset,list_t* dest, int dest_offset,int len)
|
||||
{
|
||||
register int i=0;
|
||||
|
||||
for(;i<len;i++)
|
||||
{
|
||||
void* s_ptr = l_get(src, src_offset+i);
|
||||
if(i<dest->length) {
|
||||
void* d_ptr = l_get(dest, dest_offset+i);
|
||||
memcpy(d_ptr, s_ptr, src->type);
|
||||
} else l_add(dest, s_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void l_copy_ar(const list_t* src, int src_offset, void* dest, int len)
|
||||
{
|
||||
register int i=0;
|
||||
unsigned char* by = (unsigned char*) dest;
|
||||
|
||||
for(;i<len;i++)
|
||||
{
|
||||
void* s_ptr = l_get(src, src_offset+i);
|
||||
memcpy( by, s_ptr, src->type);
|
||||
by+=src->type;
|
||||
}
|
||||
}
|
||||
|
||||
list_t* l_create_from(void* from, int items, size_t type, int bs)
|
||||
{
|
||||
list_t *l = l_create(type, bs);
|
||||
register int i=0;
|
||||
|
||||
for(;i<items;i++)
|
||||
l_add(l, (void*)(((unsigned char*)from)+(i*type)));
|
||||
return l;
|
||||
}
|
||||
|
||||
/*
|
||||
static l_block* _l_last_block(l_block* b0)
|
||||
{
|
||||
while(b0->next!=NULL)
|
||||
{
|
||||
b0 = b0->next;
|
||||
}
|
||||
return b0;
|
||||
}*/ /** currently unused **/
|
||||
|
||||
void l_add(list_t *t,const void* o)
|
||||
{
|
||||
int real_i = t->length%t->blocksize;
|
||||
int block_skip = t->length/t->blocksize;
|
||||
l_block *wbl;
|
||||
|
||||
if(t->length>0 && ((t->length%t->blocksize)==0))
|
||||
{
|
||||
l_block *prev = _l_block_skip(t->block0, block_skip-1);
|
||||
wbl = prev->next = _l_create_block(t->type,t->blocksize);
|
||||
}
|
||||
else
|
||||
wbl = _l_block_skip(t->block0, block_skip);
|
||||
memcpy(_l_at(wbl, t->type, real_i), o, t->type);
|
||||
t->length+=1;
|
||||
}
|
||||
|
||||
void l_nullify(list_t *t, int index)
|
||||
{
|
||||
memset(l_get(t, index), 0, t->length);
|
||||
}
|
||||
|
||||
void* l_get(const list_t *t, int index)
|
||||
{
|
||||
int real_i = index%t->blocksize;
|
||||
int block_skip = index/t->blocksize;
|
||||
l_block *wbl= _l_block_skip(t->block0, block_skip);
|
||||
|
||||
return _l_at(wbl, t->type, real_i);
|
||||
}
|
||||
|
||||
static void* _l_ptoarray(const list_t* t,int *size, _l_predicate p)
|
||||
{
|
||||
void* output0 = calloc(t->length, t->type);
|
||||
void* output;
|
||||
register int i=0,j=0;
|
||||
|
||||
for(;i<t->length;i++)
|
||||
{
|
||||
if(p(t, i)) {
|
||||
memcpy( (void*)(((unsigned char*)output0)+(j*t->type)), l_get(t, i), t->type);
|
||||
j+=1;
|
||||
}
|
||||
}
|
||||
|
||||
output = calloc(j, t->type);
|
||||
memcpy(output, output0, t->type*j);
|
||||
free(output0);
|
||||
|
||||
if(size!=NULL) *size = j;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void* l_toarray_n(const list_t *t, int* size, _l_predicate p)
|
||||
{
|
||||
if(p==NULL)
|
||||
{
|
||||
void* output = calloc(t->length, t->type);
|
||||
register int i=0;
|
||||
|
||||
for(;i<t->length;i++)
|
||||
memcpy( (void*)(((unsigned char*)output)+(i*t->type)), l_get(t, i), t->type);
|
||||
|
||||
if(size!=NULL) *size= (t->length);
|
||||
return output;
|
||||
}
|
||||
else return _l_ptoarray(t,size,p);
|
||||
}
|
||||
|
||||
void l_toarray(const list_t *t, void* dest, size_t len)
|
||||
{
|
||||
int real_i = len%t->blocksize;
|
||||
int block_skip = len/t->blocksize;
|
||||
l_block* b = t->block0;
|
||||
register int i=0;
|
||||
|
||||
for(;i<block_skip;i++)
|
||||
{
|
||||
memcpy( (void*)(((unsigned char*)dest)+((i*t->blocksize)*t->type)), b->data, t->type*t->blocksize);
|
||||
|
||||
b = b->next;
|
||||
|
||||
}
|
||||
|
||||
memcpy( (void*)(((unsigned char*)dest)+((block_skip*t->blocksize)*t->type)), b->data, t->type* real_i);
|
||||
|
||||
}
|
||||
|
||||
int l_isnull(const list_t *t, int index)
|
||||
{
|
||||
void* ptr = l_get(t, index);
|
||||
return _mem_isnull((unsigned char*)ptr, t->type);
|
||||
}
|
||||
|
||||
void l_nullify_if(list_t *t, _l_predicate f)
|
||||
{
|
||||
register int i=0;
|
||||
for(;i<t->length;i++)
|
||||
if(f(t, i)) l_nullify(t, i);
|
||||
}
|
||||
|
||||
void l_do_if(list_t *t, _l_action act, _l_predicate f)
|
||||
{
|
||||
register int i=0;
|
||||
for(;i<t->length;i++)
|
||||
if(f(t, i)) act(t, i);
|
||||
}
|
||||
|
||||
void l_do(list_t *t, _l_action act)
|
||||
{
|
||||
register int i=0;
|
||||
for(;i<t->length;i++)
|
||||
act(t, i);
|
||||
}
|
||||
|
||||
|
||||
void l_swap(list_t *t, int index1, int index2)
|
||||
{
|
||||
void* temp = malloc(t->type);
|
||||
memcpy(temp, l_get(t, index1), t->type);
|
||||
memcpy(l_get(t, index1), l_get(t,index2), t->type);
|
||||
memcpy(l_get(t,index2), temp, t->type);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
void l_sort(list_t *t, _l_sort_alg algorithm, _l_comparator comp)
|
||||
{
|
||||
switch(algorithm)
|
||||
{
|
||||
case QUICKSORT:
|
||||
_l_quicksort(t, 0, t->length-1, comp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_t* l_clone(const list_t *t)
|
||||
{
|
||||
list_t *n = l_create(t->type, t->blocksize);
|
||||
l_copy(t, 0, n, 0, t->length);
|
||||
return n;
|
||||
}
|
||||
|
||||
list_t* l_clone_if(const list_t *t , _l_predicate f)
|
||||
{
|
||||
list_t *n = l_create(t->type, t->blocksize);
|
||||
register int i=0;
|
||||
for(;i<t->length;i++)
|
||||
if(f(t, i)) l_add(n, l_get(t,i));
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Iterator stuff */
|
||||
|
||||
int li_next(l_iterator *it)
|
||||
{
|
||||
it->index+=1;
|
||||
it->element = NULL;
|
||||
return it->index<it->list->length;
|
||||
}
|
||||
|
||||
l_iterator li_create(list_t *list)
|
||||
{
|
||||
l_iterator i;
|
||||
i.index = 0;
|
||||
i.list = list;
|
||||
i.element = NULL;
|
||||
return i;
|
||||
}
|
||||
|
||||
void* li_set(l_iterator *i,int index)
|
||||
{
|
||||
i->index = index;
|
||||
return li_get(i);
|
||||
}
|
||||
|
||||
void* li_get(l_iterator *i)
|
||||
{
|
||||
if(i->index<i->list->length) {
|
||||
return i->element = l_get(i->list, i->index);
|
||||
}
|
||||
else return i->element = NULL;
|
||||
}
|
||||
|
||||
void* li_iterate(l_iterator *i)
|
||||
{
|
||||
if(i->index<i->list->length) {
|
||||
void* p = l_get(i->list, i->index);
|
||||
li_next(i);
|
||||
return i->element = p;
|
||||
}
|
||||
else return i->element = NULL;
|
||||
}
|
||||
|
||||
/* Predefined predicates */
|
||||
|
||||
L_P_FUNCTION(not_null)
|
||||
{
|
||||
return !l_isnull(list,index);
|
||||
}
|
||||
|
||||
/* Predefined Actions */
|
||||
|
||||
L_A_FUNCTION(assert_zero)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* Predefined Comparators */
|
||||
|
||||
L_C_FUNCTION(int_a)
|
||||
{
|
||||
int v1 = l_get_v(list, i1, int);
|
||||
int v2 = l_get_v(list, i2, int);
|
||||
int comp_res = v1>v2?1:(((v1==v2)?0:-1));
|
||||
return comp_res;
|
||||
}
|
||||
|
||||
#undef l_block
|
@ -0,0 +1,22 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <list.h>
|
||||
|
||||
void _l_quicksort(list_t *arr, int left, int right, _l_comparator comp)
|
||||
{
|
||||
int m = (left+right)/2;
|
||||
int l = left, r = right;
|
||||
while (l <= r) {
|
||||
while (l_bcheck(arr, l) && (comp(arr, l, m) < 0)) l+=1;
|
||||
while (l_bcheck(arr, r) && (comp(arr, r, m) > 0)) r-=1;
|
||||
if (l <= r) {
|
||||
l_swap(arr, l, r);
|
||||
l+=1; r-=1;
|
||||
}
|
||||
}
|
||||
if (r > left) _l_quicksort(arr, left, r, comp);
|
||||
if (l < right) _l_quicksort(arr, l, right, comp);
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <list.h>
|
||||
|
||||
void p_show(list_t *list);
|
||||
void p_show_sorted(const list_t *list);
|
||||
|
||||
int main()
|
||||
{
|
||||
list_t *list;
|
||||
int size=100;
|
||||
int i;
|
||||
l_iterator iter;
|
||||
|
||||
/* Create list for type "int" of default blocksize */
|
||||
list = l_create_d(sizeof(int));
|
||||
|
||||
/* Add numbers */
|
||||
for(i=0;i<size;i++) {
|
||||
int random = rand();
|
||||
l_add(list, &random);
|
||||
}
|
||||
|
||||
p_show_sorted(list);
|
||||
|
||||
/* Create iterator */
|
||||
iter = li_create(list);
|
||||
|
||||
/* Iterate over list */
|
||||
while( li_iterate(&iter) != NULL)
|
||||
{
|
||||
/* Current iterator item is in (void*) <iterator>.element */
|
||||
printf("%d ", *(int*)iter.element );
|
||||
}
|
||||
printf("\r\n");
|
||||
|
||||
p_show(list);
|
||||
|
||||
printf("\r\n");
|
||||
|
||||
/* Free all memory allocated */
|
||||
l_destroy(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Create function "lp_is_even" with params (list_t*)list, (int)index for predicate */
|
||||
L_P_FUNCTION(is_even)
|
||||
{
|
||||
return *(int*)l_get(list,index)%2==0;
|
||||
}
|
||||
|
||||
L_P_FUNCTION(is_ten)
|
||||
{
|
||||
return l_get_v(list,index,int)%10==0;
|
||||
}
|
||||
|
||||
/* Create function "la_print" with params (list_t*)list, (int)index for action */
|
||||
L_A_FUNCTION(print)
|
||||
{
|
||||
printf("%d ",*(int*)l_get(list,index));
|
||||
}
|
||||
|
||||
void p_show_sorted(const list_t *list)
|
||||
{
|
||||
/* Create copy of list to sort */
|
||||
list_t* sorted = l_clone(list);
|
||||
|
||||
/* Sort using default int ascending comparator & quicksort algorithm */
|
||||
l_sort(sorted, QUICKSORT, &lc_int_a);
|
||||
|
||||
/* Print values */
|
||||
l_do(sorted, &la_print);
|
||||
|
||||
printf("\r\n");
|
||||
|
||||
/* Destroy copy of list */
|
||||
l_destroy(sorted);
|
||||
}
|
||||
|
||||
void p_show(list_t *list)
|
||||
{
|
||||
int* newdata;
|
||||
int newsize;
|
||||
register int i=0;
|
||||
|
||||
/* Copy all elements that satisfy lp_is_even into new array */
|
||||
newdata = (int*)l_toarray_n(list, &newsize, &lp_is_even);
|
||||
|
||||
for(;i<newsize;i++) printf("%d ", newdata[i]);
|
||||
|
||||
/* Free new array */
|
||||
free(newdata);
|
||||
|
||||
printf("\r\n");
|
||||
|
||||
/* Call la_print on all elements that satisfy lp_is_ten */
|
||||
l_do_if(list, &la_print, &lp_is_ten);
|
||||
}
|
Loading…
Reference in new issue