diff --git a/Makefile.include b/Makefile.include index 3792125..b41fb54 100644 --- a/Makefile.include +++ b/Makefile.include @@ -19,6 +19,7 @@ ifdef NO_MEMRCHR obj-compat = src/compat/memrchr.o endif obj-xalloc = src/xalloc.o src/die.o +obj-list = src/list.o $(obj-xalloc) obj-str-list = src/str-list.o $(obj-xalloc) obj-strbuf = src/strbuf.o $(obj-xalloc) src/die.o obj-path = src/path.o $(obj-strbuf) diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..02a2ee1 --- /dev/null +++ b/src/list.c @@ -0,0 +1,122 @@ +/* list.c + * + * Copyright (C) 2010 Henrik Hautakoski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ + +#include +#include "xalloc.h" +#include "list.h" + +static void resize(struct list *l) { + + if (!l->nr) { + xfree(l->items); + l->items = NULL; + return; + } + l->items = xrealloc(l->items, sizeof(l->items) * l->nr); +} + +struct list* list_create(void) { + + struct list *list = xmalloc(sizeof(struct list)); + list->items = NULL; + list->nr = 0; + return list; +} + +int list_destroy(struct list *list) { + + list_clear_fn(list, NULL); + xfree(list); + return 0; +} + +void list_clear(struct list *list) { + + list_clear_fn(list, NULL); +} + +void list_clear_fn(struct list *list, clear_fn_t *fn) { + + if (list->items) { + if (fn) { + int i; + for(i=0; i < list->nr; i++) + fn(list->items[i]); + } + xfree(list->items); + } + list->items = NULL; + list->nr = 0; +} + +int list_insert(struct list *list, const void *item) { + + if (!list) + return -1; + + list->items = xrealloc(list->items, sizeof(list->items) * (++list->nr)); + list->items[list->nr - 1] = (void *) item; + + return list->nr; +} + +void* list_remove(struct list *list, unsigned index) { + + void *item = NULL; + + if (list && index < list->nr) { + if (index < --list->nr) { + memmove(list->items + index, list->items + index + 1, + sizeof(list->items) * (list->nr - index)); + } + resize(list); + } + return item; +} + +void* list_reduce(struct list *list) { + + void *item = NULL; + + if (list && list->nr) { + item = list->items[--list->nr]; + resize(list); + } + return item; +} + +int list_indexof(struct list *list, const void *item) { + + int i; + + for(i=0; i < list->nr; i++) { + + if (list->items[i] == item) + return i; + } + return -1; +} + +void* list_lookup(struct list *list, const void *item, cmp_fn_t *fn) { + + int i; + + if (fn) { + for(i=0; i < list->nr; i++) { + if (fn(list->items[i], item) == 0) + return list->items[i]; + } + } else { + i = list_indexof(list, item); + if (i >= 0) + return list->items[i]; + } + return NULL; +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..74af5e1 --- /dev/null +++ b/src/list.h @@ -0,0 +1,48 @@ +/* list.h + * + * Copyright (C) 2010 Henrik Hautakoski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ + +#ifndef __LIST_H +#define __LIST_H + +#include + +struct list { + void **items; + unsigned nr; +}; + +typedef void (clear_fn_t)(void*); +typedef int (cmp_fn_t)(const void *, const void *b); + +struct list* list_create(void); + +int list_destroy(struct list *list); + +void list_clear(struct list *list); + +void list_clear_fn(struct list *list, clear_fn_t *fn); + +int list_insert(struct list *list, const void *item); + +void* list_remove(struct list *list, unsigned index); + +void* list_reduce(struct list *list); + +int list_indexof(struct list *list, const void *item); + +void* list_lookup(struct list *list, const void *item, cmp_fn_t *fn); + +#define list_has(l, i, f) list_lookup(l, i, f) != NULL + +#define list_size(l) ((l) ? (l)->nr : 0) + +#define list_isempty(l) (!(l) || (l)->nr == 0) + +#endif /* __LIST_H */ diff --git a/test/Makefile b/test/Makefile index a09e9e3..3d2b526 100644 --- a/test/Makefile +++ b/test/Makefile @@ -23,6 +23,7 @@ inotify-map : $(addprefix $(ROOT),$(obj-inotify-map)) inotify-watch : $(addprefix $(ROOT), $(obj-xalloc)) $(addprefix $(ROOT), $(obj-path)) $(ROOT)src/tree.o ../src/inotify-watch.o log : $(addprefix $(ROOT),$(obj-log)) tree : $(addprefix $(ROOT),$(obj-xalloc)) $(ROOT)src/tree.o +list : $(addprefix $(ROOT),$(obj-list)) str-list : unit.c $(addprefix $(ROOT),$(obj-str-list)) clean : diff --git a/test/t_list.c b/test/t_list.c new file mode 100644 index 0000000..6524f3f --- /dev/null +++ b/test/t_list.c @@ -0,0 +1,135 @@ + +#include +#include + +#include "../src/list.h" + +int itemcmp(const void *a, const void *b) { + + return strcmp(a, b); +} + +void test_insert() { + + int i; + char ref[4] = { 'a', 'b', 'c', 'd' }; + struct list *l = list_create(); + + for(i=0; i < 4; i++) + list_insert(l, &ref[i]); + for(i=0; i < 4; i++) + assert(l->items[i] == &ref[i]); + + list_destroy(l); +} + +void test_remove() { + + int i; + char ref[4] = { 'a', 'b', 'c', 'd' }; + struct list *l = list_create(); + + for(i=0; i < 4; i++) + list_insert(l, &ref[i]); + + list_remove(l, 1); + list_remove(l, 2); + + assert(list_size(l) == 2); + assert(l->items[0] == &ref[0]); + assert(l->items[1] == &ref[2]); + + list_remove(l, 0); + list_remove(l, 0); + + assert(list_size(l) == 0); + list_destroy(l); +} + + +void test_isempty() { + + struct list *l = NULL; + + assert(list_isempty(l)); + l = list_create(); + assert(list_isempty(l)); + list_insert(l, NULL); + assert(list_isempty(l) == 0); + + list_destroy(l); +} + +void test_size() { + + struct list *l = NULL; + + assert(list_size(l) == 0); + l = list_create(); + assert(list_size(l) == 0); + list_insert(l, NULL); + list_insert(l, NULL); + assert(list_size(l) == 2); + + list_destroy(l); +} + +void test_indexof() { + + int i; + char ref[4] = { 'a', 'b', 'c', 'd' }; + struct list *l = list_create(); + + assert(list_indexof(l, &ref[2]) == -1); + + for(i=0; i < 4; i++) + list_insert(l, &ref[i]); + + for(i=0; i < 4; i++) + assert(list_indexof(l, &ref[i]) == i); + + list_destroy(l); +} + +void test_has() { + + int i; + char *ref[4] = { "a", "b", "c", "d" }; + struct list *l = list_create(); + + for(i=0; i < 4; i++) + list_insert(l, ref[i]); + + assert(list_has(l, "b", itemcmp)); + assert(list_has(l, "e", itemcmp) == 0); + + list_destroy(l); +} + +void test_lookup() { + + int i; + char *ref[4] = { "a", "b", "c", "d" }; + struct list *l = list_create(); + + for(i=0; i < 4; i++) + list_insert(l, ref[i]); + + assert(list_lookup(l, "b", itemcmp) == ref[1]); + assert(list_lookup(l, "e", itemcmp) == NULL); + + list_destroy(l); +} + +int main() { + + test_insert(); + test_remove(); + test_isempty(); + test_size(); + test_indexof(); + test_has(); + test_lookup(); + + return 0; +}