From 1de62163f0237e2fdd7d9b5ee7c29c57851ce87e Mon Sep 17 00:00:00 2001 From: Andrew Shadura Date: Thu, 17 Nov 2011 19:46:12 +0100 Subject: initial import --- src/Makefile | 4 + src/examples/Makefile | 3 + src/examples/dicttest/Makefile | 7 + src/examples/dicttest/dicttest.c | 79 +++ src/examples/formattertest/Makefile | 7 + src/examples/formattertest/formattertest.c | 46 ++ src/examples/listsort/Makefile | 7 + src/examples/listsort/listsort.c | 117 ++++ src/examples/patriciatest/Makefile | 7 + src/examples/patriciatest/patriciatest.c | 157 +++++ src/examples/patriciatest2/Makefile | 7 + src/examples/patriciatest2/patriciatest2.c | 153 +++++ src/examples/randomtest/Makefile | 7 + src/examples/randomtest/randomtest.c | 51 ++ src/libmowgli/Makefile | 77 +++ src/libmowgli/mowgli.h | 81 +++ src/libmowgli/mowgli_alloc.c | 133 ++++ src/libmowgli/mowgli_alloc.h | 31 + src/libmowgli/mowgli_allocation_policy.c | 70 ++ src/libmowgli/mowgli_allocation_policy.h | 45 ++ src/libmowgli/mowgli_allocator.c | 46 ++ src/libmowgli/mowgli_allocator.h | 31 + src/libmowgli/mowgli_argstack.c | 247 +++++++ src/libmowgli/mowgli_argstack.h | 57 ++ src/libmowgli/mowgli_assert.h | 105 +++ src/libmowgli/mowgli_bitvector.c | 238 +++++++ src/libmowgli/mowgli_bitvector.h | 41 ++ src/libmowgli/mowgli_config.h.in | 147 ++++ src/libmowgli/mowgli_dictionary.c | 914 +++++++++++++++++++++++++ src/libmowgli/mowgli_dictionary.h | 166 +++++ src/libmowgli/mowgli_error_backtrace.c | 109 +++ src/libmowgli/mowgli_error_backtrace.h | 38 ++ src/libmowgli/mowgli_exception.h | 37 + src/libmowgli/mowgli_formatter.c | 119 ++++ src/libmowgli/mowgli_formatter.h | 31 + src/libmowgli/mowgli_global_storage.c | 68 ++ src/libmowgli/mowgli_global_storage.h | 32 + src/libmowgli/mowgli_hash.c | 66 ++ src/libmowgli/mowgli_hash.h | 30 + src/libmowgli/mowgli_heap.c | 323 +++++++++ src/libmowgli/mowgli_heap.h | 50 ++ src/libmowgli/mowgli_hook.c | 146 ++++ src/libmowgli/mowgli_hook.h | 47 ++ src/libmowgli/mowgli_index.c | 175 +++++ src/libmowgli/mowgli_index.h | 51 ++ src/libmowgli/mowgli_init.c | 49 ++ src/libmowgli/mowgli_init.h | 29 + src/libmowgli/mowgli_ioevent.c | 195 ++++++ src/libmowgli/mowgli_ioevent.h | 55 ++ src/libmowgli/mowgli_iterator.h | 38 ++ src/libmowgli/mowgli_list.c | 386 +++++++++++ src/libmowgli/mowgli_list.h | 76 +++ src/libmowgli/mowgli_logger.c | 62 ++ src/libmowgli/mowgli_logger.h | 45 ++ src/libmowgli/mowgli_mempool.c | 199 ++++++ src/libmowgli/mowgli_mempool.h | 45 ++ src/libmowgli/mowgli_module.h | 33 + src/libmowgli/mowgli_module_posix.c | 69 ++ src/libmowgli/mowgli_module_win32.c | 62 ++ src/libmowgli/mowgli_object.c | 164 +++++ src/libmowgli/mowgli_object.h | 42 ++ src/libmowgli/mowgli_object_class.c | 132 ++++ src/libmowgli/mowgli_object_class.h | 61 ++ src/libmowgli/mowgli_object_messaging.c | 142 ++++ src/libmowgli/mowgli_object_messaging.h | 42 ++ src/libmowgli/mowgli_object_metadata.c | 104 +++ src/libmowgli/mowgli_object_metadata.h | 36 + src/libmowgli/mowgli_patricia.c | 1000 ++++++++++++++++++++++++++++ src/libmowgli/mowgli_patricia.h | 148 ++++ src/libmowgli/mowgli_queue.c | 209 ++++++ src/libmowgli/mowgli_queue.h | 44 ++ src/libmowgli/mowgli_random.c | 143 ++++ src/libmowgli/mowgli_random.h | 45 ++ src/libmowgli/mowgli_signal.c | 65 ++ src/libmowgli/mowgli_signal.h | 31 + src/libmowgli/mowgli_spinlock.c | 105 +++ src/libmowgli/mowgli_spinlock.h | 44 ++ src/libmowgli/mowgli_stdinc.h | 96 +++ src/libmowgli/mowgli_string.c | 121 ++++ src/libmowgli/mowgli_string.h | 48 ++ src/libmowgli/win32_support.c | 64 ++ src/libmowgli/win32_support.h | 47 ++ 82 files changed, 8679 insertions(+) create mode 100644 src/Makefile create mode 100644 src/examples/Makefile create mode 100644 src/examples/dicttest/Makefile create mode 100644 src/examples/dicttest/dicttest.c create mode 100644 src/examples/formattertest/Makefile create mode 100644 src/examples/formattertest/formattertest.c create mode 100644 src/examples/listsort/Makefile create mode 100644 src/examples/listsort/listsort.c create mode 100644 src/examples/patriciatest/Makefile create mode 100644 src/examples/patriciatest/patriciatest.c create mode 100644 src/examples/patriciatest2/Makefile create mode 100644 src/examples/patriciatest2/patriciatest2.c create mode 100644 src/examples/randomtest/Makefile create mode 100644 src/examples/randomtest/randomtest.c create mode 100644 src/libmowgli/Makefile create mode 100644 src/libmowgli/mowgli.h create mode 100644 src/libmowgli/mowgli_alloc.c create mode 100644 src/libmowgli/mowgli_alloc.h create mode 100644 src/libmowgli/mowgli_allocation_policy.c create mode 100644 src/libmowgli/mowgli_allocation_policy.h create mode 100644 src/libmowgli/mowgli_allocator.c create mode 100644 src/libmowgli/mowgli_allocator.h create mode 100644 src/libmowgli/mowgli_argstack.c create mode 100644 src/libmowgli/mowgli_argstack.h create mode 100644 src/libmowgli/mowgli_assert.h create mode 100644 src/libmowgli/mowgli_bitvector.c create mode 100644 src/libmowgli/mowgli_bitvector.h create mode 100644 src/libmowgli/mowgli_config.h.in create mode 100644 src/libmowgli/mowgli_dictionary.c create mode 100644 src/libmowgli/mowgli_dictionary.h create mode 100644 src/libmowgli/mowgli_error_backtrace.c create mode 100644 src/libmowgli/mowgli_error_backtrace.h create mode 100644 src/libmowgli/mowgli_exception.h create mode 100644 src/libmowgli/mowgli_formatter.c create mode 100644 src/libmowgli/mowgli_formatter.h create mode 100644 src/libmowgli/mowgli_global_storage.c create mode 100644 src/libmowgli/mowgli_global_storage.h create mode 100644 src/libmowgli/mowgli_hash.c create mode 100644 src/libmowgli/mowgli_hash.h create mode 100644 src/libmowgli/mowgli_heap.c create mode 100644 src/libmowgli/mowgli_heap.h create mode 100644 src/libmowgli/mowgli_hook.c create mode 100644 src/libmowgli/mowgli_hook.h create mode 100644 src/libmowgli/mowgli_index.c create mode 100644 src/libmowgli/mowgli_index.h create mode 100644 src/libmowgli/mowgli_init.c create mode 100644 src/libmowgli/mowgli_init.h create mode 100644 src/libmowgli/mowgli_ioevent.c create mode 100644 src/libmowgli/mowgli_ioevent.h create mode 100644 src/libmowgli/mowgli_iterator.h create mode 100644 src/libmowgli/mowgli_list.c create mode 100644 src/libmowgli/mowgli_list.h create mode 100644 src/libmowgli/mowgli_logger.c create mode 100644 src/libmowgli/mowgli_logger.h create mode 100644 src/libmowgli/mowgli_mempool.c create mode 100644 src/libmowgli/mowgli_mempool.h create mode 100644 src/libmowgli/mowgli_module.h create mode 100644 src/libmowgli/mowgli_module_posix.c create mode 100644 src/libmowgli/mowgli_module_win32.c create mode 100644 src/libmowgli/mowgli_object.c create mode 100644 src/libmowgli/mowgli_object.h create mode 100644 src/libmowgli/mowgli_object_class.c create mode 100644 src/libmowgli/mowgli_object_class.h create mode 100644 src/libmowgli/mowgli_object_messaging.c create mode 100644 src/libmowgli/mowgli_object_messaging.h create mode 100644 src/libmowgli/mowgli_object_metadata.c create mode 100644 src/libmowgli/mowgli_object_metadata.h create mode 100644 src/libmowgli/mowgli_patricia.c create mode 100644 src/libmowgli/mowgli_patricia.h create mode 100644 src/libmowgli/mowgli_queue.c create mode 100644 src/libmowgli/mowgli_queue.h create mode 100644 src/libmowgli/mowgli_random.c create mode 100644 src/libmowgli/mowgli_random.h create mode 100644 src/libmowgli/mowgli_signal.c create mode 100644 src/libmowgli/mowgli_signal.h create mode 100644 src/libmowgli/mowgli_spinlock.c create mode 100644 src/libmowgli/mowgli_spinlock.h create mode 100644 src/libmowgli/mowgli_stdinc.h create mode 100644 src/libmowgli/mowgli_string.c create mode 100644 src/libmowgli/mowgli_string.h create mode 100644 src/libmowgli/win32_support.c create mode 100644 src/libmowgli/win32_support.h (limited to 'src') diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..1c115a9 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,4 @@ +SUBDIRS = libmowgli ${EXAMPLES_BUILD} + +include ../buildsys.mk +include ../extra.mk diff --git a/src/examples/Makefile b/src/examples/Makefile new file mode 100644 index 0000000..d56d9ad --- /dev/null +++ b/src/examples/Makefile @@ -0,0 +1,3 @@ +SUBDIRS = randomtest listsort formattertest dicttest patriciatest patriciatest2 + +include ../../buildsys.mk diff --git a/src/examples/dicttest/Makefile b/src/examples/dicttest/Makefile new file mode 100644 index 0000000..f018538 --- /dev/null +++ b/src/examples/dicttest/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = dicttest${PROG_SUFFIX} +SRCS = dicttest.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli diff --git a/src/examples/dicttest/dicttest.c b/src/examples/dicttest/dicttest.c new file mode 100644 index 0000000..c5eaec5 --- /dev/null +++ b/src/examples/dicttest/dicttest.c @@ -0,0 +1,79 @@ +/* + * libmowgli: A collection of useful routines for programming. + * dicttest.c: Testing of the mowgli.dictionary engine. + * + * Copyright (c) 2007 William Pitcock + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef _WIN32 +#define strcasecmp _stricmp +#define snprintf _snprintf +#endif + +int main(int argc, const char *argv[]) +{ + mowgli_dictionary_t *test_dict; + mowgli_random_t *r; + char key[10]; + long ans[100], i; + int pass = 0, fail = 0; + + mowgli_init(); + + test_dict = mowgli_dictionary_create(strcasecmp); + r = mowgli_random_create(); + + for (i = 0; i < 100; i++) + { + ans[i] = mowgli_random_int(r); + snprintf(key, 10, "%ldkey%ld", i, i); + mowgli_dictionary_add(test_dict, key, (void *) ans[i]); + } + + for (i = 0; i < 100; i++) + { + snprintf(key, 10, "%ldkey%ld", i, i); + + if ( (long) mowgli_dictionary_retrieve(test_dict, key) != ans[i]) + { + printf("FAIL %ld %p[%p]\n", i, mowgli_dictionary_retrieve(test_dict, key), (void*) ans[i]); + fail++; + } + else + { + printf("PASS %ld %p[%p]\n", i, mowgli_dictionary_retrieve(test_dict, key), (void*) ans[i]); + pass++; + } + } + + printf("%d tests failed, %d tests passed.\n", fail, pass); + return 0; +} diff --git a/src/examples/formattertest/Makefile b/src/examples/formattertest/Makefile new file mode 100644 index 0000000..23c4517 --- /dev/null +++ b/src/examples/formattertest/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = formattertest${PROG_SUFFIX} +SRCS = formattertest.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli diff --git a/src/examples/formattertest/formattertest.c b/src/examples/formattertest/formattertest.c new file mode 100644 index 0000000..26a6e4b --- /dev/null +++ b/src/examples/formattertest/formattertest.c @@ -0,0 +1,46 @@ +/* + * libmowgli: A collection of useful routines for programming. + * formattertest.c: Testsuite for mowgli.formatter. + * + * Copyright (c) 2007 William Pitcock + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +int main(int argc, char *argv[]) +{ + char buf[65535]; + mowgli_init(); + + mowgli_formatter_format(buf, 65535, "%1! %2 %3 %4.", "sdpb", "Hello World", 1, 0xDEADBEEF, TRUE); + + puts(buf); + + return 0; +} diff --git a/src/examples/listsort/Makefile b/src/examples/listsort/Makefile new file mode 100644 index 0000000..2517a77 --- /dev/null +++ b/src/examples/listsort/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = listsort${PROG_SUFFIX} +SRCS = listsort.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli diff --git a/src/examples/listsort/listsort.c b/src/examples/listsort/listsort.c new file mode 100644 index 0000000..43b9745 --- /dev/null +++ b/src/examples/listsort/listsort.c @@ -0,0 +1,117 @@ +/* + * libmowgli: A collection of useful routines for programming. + * listsort.c: Testing of the list sorting routine. + * + * Copyright (c) 2007 William Pitcock + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef _WIN32 +#define strcasecmp _stricmp +#endif + +int str_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) +{ + int ret; + ret = strcasecmp(n->data, n2->data); + + return ret; +} + +void test_strings(void) +{ + mowgli_list_t l = { NULL, NULL, 0 }; + mowgli_node_t *n, *tn; + + mowgli_node_add("foo", mowgli_node_create(), &l); + mowgli_node_add("bar", mowgli_node_create(), &l); + mowgli_node_add("baz", mowgli_node_create(), &l); + mowgli_node_add("splork", mowgli_node_create(), &l); + mowgli_node_add("rabbit", mowgli_node_create(), &l); + mowgli_node_add("meow", mowgli_node_create(), &l); + mowgli_node_add("hi", mowgli_node_create(), &l); + mowgli_node_add("konnichiwa", mowgli_node_create(), &l); + mowgli_node_add("absolutely", mowgli_node_create(), &l); + mowgli_node_add("cat", mowgli_node_create(), &l); + mowgli_node_add("dog", mowgli_node_create(), &l); + mowgli_node_add("woof", mowgli_node_create(), &l); + mowgli_node_add("moon", mowgli_node_create(), &l); + mowgli_node_add("new", mowgli_node_create(), &l); + mowgli_node_add("delete", mowgli_node_create(), &l); + mowgli_node_add("alias", mowgli_node_create(), &l); + + mowgli_list_sort(&l, str_comparator, NULL); + + printf("\nString test results\n"); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, l.head) + { + printf(" %s\n", (char*) n->data); + mowgli_node_delete(n, &l); + } +} + +int int_comparator(mowgli_node_t *n, mowgli_node_t *n2, void *opaque) +{ + long a = (long) n->data; + long b = (long) n2->data; + + return a - b; +} + +void test_integers(void) +{ + mowgli_list_t l = { NULL, NULL, 0 }; + mowgli_node_t *n, *tn; + + mowgli_node_add((void *) 3, mowgli_node_create(), &l); + mowgli_node_add((void *) 2, mowgli_node_create(), &l); + mowgli_node_add((void *) 4, mowgli_node_create(), &l); + mowgli_node_add((void *) 1, mowgli_node_create(), &l); + + mowgli_list_sort(&l, int_comparator, NULL); + + printf("\nInteger test results\n"); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, l.head) + { + printf(" %ld\n", (long) n->data); + mowgli_node_delete(n, &l); + } +} + +int main(int argc, char *argv[]) +{ + mowgli_init(); + + test_strings(); + test_integers(); + return EXIT_SUCCESS; +} diff --git a/src/examples/patriciatest/Makefile b/src/examples/patriciatest/Makefile new file mode 100644 index 0000000..6669293 --- /dev/null +++ b/src/examples/patriciatest/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = patriciatest${PROG_SUFFIX} +SRCS = patriciatest.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli diff --git a/src/examples/patriciatest/patriciatest.c b/src/examples/patriciatest/patriciatest.c new file mode 100644 index 0000000..bf5f641 --- /dev/null +++ b/src/examples/patriciatest/patriciatest.c @@ -0,0 +1,157 @@ +/* + * libmowgli: A collection of useful routines for programming. + * patriciatest.c: Testing of the patricia tree. + * + * Copyright (c) 2008 Jilles Tjoelker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +int errors = 0; + +void str_canon(char *key) +{ + return; +} + +void statscb(const char *line, void *data) +{ + printf("%s\n", line); +} + +/* assumes data is key */ +static void check_all_retrievable(mowgli_patricia_t *dtree) +{ + mowgli_patricia_iteration_state_t state; + void *elem, *elem2; + unsigned int n1 = 0, n2; + + mowgli_patricia_stats(dtree, statscb, NULL); + printf("Checking consistency..."); + fflush(stdout); + n2 = mowgli_patricia_size(dtree); + MOWGLI_PATRICIA_FOREACH(elem, &state, dtree) + { + elem2 = mowgli_patricia_retrieve(dtree, (const char *)elem); + if (elem2 == NULL) + { + errors++; + printf("failed to find element %s\n", + (const char *)elem); + } + else if (strcmp(elem2, elem)) + { + printf("element %s != %s\n", + (const char *)elem, + (const char *)elem2); + errors++; + } + else + printf("."); + fflush(stdout); + n1++; + if (n1 > n2 * 2) + break; + } + if (n1 != n2) + { + errors++; + printf("number of iterated elements %u != size %u\n", n1, n2); + } + printf("\n"); + fflush(stdout); +} + +void test_patricia(void) +{ + mowgli_patricia_t *dtree; + mowgli_patricia_iteration_state_t state; + void *elem; + + dtree = mowgli_patricia_create(str_canon); +#define ADD(x) printf("Adding %s\n", x); mowgli_patricia_add(dtree, x, x); check_all_retrievable(dtree) + ADD("\1\1"); + ADD("alias"); + ADD("\377"); + ADD("\377\377\377"); + ADD("foo"); + ADD("bar"); + ADD("baz"); + ADD("splork"); + ADD("rabbit"); + ADD("\1"); + ADD("meow"); + ADD("hi"); + ADD("konnichiwa"); + ADD("absolutely"); + ADD("cat"); + ADD("dog"); + ADD("woof"); + ADD("moon"); + ADD("new"); + ADD("delete"); + + MOWGLI_PATRICIA_FOREACH(elem, &state, dtree) + { + printf("element -> %s\n", (const char *)elem); + } + printf("End of elements\n"); + mowgli_patricia_stats(dtree, statscb, NULL); + + check_all_retrievable(dtree); + +#define TESTRETRIEVE(x) elem = mowgli_patricia_retrieve(dtree, x); printf("element %s: %s\n", x, elem ? (errors++, "YES") : "NO") + TESTRETRIEVE("meows"); + TESTRETRIEVE("meo"); + TESTRETRIEVE("deletes"); + TESTRETRIEVE("z"); + TESTRETRIEVE("0"); + +#define TESTDELETE(x) mowgli_patricia_delete(dtree, x); elem = mowgli_patricia_retrieve(dtree, x); printf("deleting %s: %s\n", x, elem ? (errors++, "STILL PRESENT") : "GONE"); check_all_retrievable(dtree) + TESTDELETE("YYY"); + TESTDELETE("foo"); + TESTDELETE("splork"); + ADD("spork"); + ADD("foo"); + TESTDELETE("absolutely"); + TESTDELETE("cat"); + ADD("absolutely"); + TESTDELETE("dog"); + + mowgli_patricia_destroy(dtree, NULL, NULL); +} + +int main(int argc, char *argv[]) +{ + mowgli_init(); + + test_patricia(); + + return errors == 0 ? 0 : 1; +} diff --git a/src/examples/patriciatest2/Makefile b/src/examples/patriciatest2/Makefile new file mode 100644 index 0000000..cb7ce12 --- /dev/null +++ b/src/examples/patriciatest2/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = patriciatest2${PROG_SUFFIX} +SRCS = patriciatest2.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli diff --git a/src/examples/patriciatest2/patriciatest2.c b/src/examples/patriciatest2/patriciatest2.c new file mode 100644 index 0000000..de70ac2 --- /dev/null +++ b/src/examples/patriciatest2/patriciatest2.c @@ -0,0 +1,153 @@ +/* + * libmowgli: A collection of useful routines for programming. + * patriciatest2.c: More testing of the patricia tree. + * + * Copyright (c) 2008-2010 Jilles Tjoelker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#define TESTSIZE 10000 + +int errors = 0; + +void str_canon(char *key) +{ + return; +} + +void statscb(const char *line, void *data) +{ +} + +/* assumes data is key */ +static void check_all_retrievable(mowgli_patricia_t *dtree) +{ + mowgli_patricia_iteration_state_t state; + void *elem, *elem2; + unsigned int n1 = 0, n2; + + mowgli_patricia_stats(dtree, statscb, NULL); + n2 = mowgli_patricia_size(dtree); + MOWGLI_PATRICIA_FOREACH(elem, &state, dtree) + { + elem2 = mowgli_patricia_retrieve(dtree, (const char *)elem); + if (elem2 == NULL) + { + errors++; + printf("failed to find element %s\n", + (const char *)elem); + } + else if (strcmp(elem2, elem)) + { + printf("element %s != %s\n", + (const char *)elem, + (const char *)elem2); + errors++; + } + n1++; + if (n1 > n2 * 2) + break; + } + if (n1 != n2) + { + errors++; + printf("number of iterated elements %u != size %u\n", n1, n2); + } +} + +void test_patricia(void) +{ + mowgli_patricia_t *dtree; + int i, j; + char buf[100], *strings[TESTSIZE]; + + srandom(12346); + for (i = 0; i < TESTSIZE; i++) + { + for (j = 0; j < 40; j++) + buf[j] = 'a' + random() % 26; + buf[20 + random() % 20] = '\0'; + strings[i] = strdup(buf); + } + + dtree = mowgli_patricia_create(str_canon); + + for (i = 0; i < TESTSIZE; i++) + { + mowgli_patricia_add(dtree, strings[i], strings[i]); + check_all_retrievable(dtree); + } + + check_all_retrievable(dtree); + + for (i = 0; i < TESTSIZE / 2; i++) + { + mowgli_patricia_delete(dtree, strings[i]); + if (mowgli_patricia_retrieve(dtree, strings[i])) + { + printf("still retrievable after delete: %s\n", + strings[i]); + errors++; + } + check_all_retrievable(dtree); + } + + for (i = 0; i < TESTSIZE / 2; i++) + { + mowgli_patricia_add(dtree, strings[i], strings[i]); + check_all_retrievable(dtree); + } + + for (i = 0; i < TESTSIZE; i++) + { + mowgli_patricia_delete(dtree, strings[i]); + if (mowgli_patricia_retrieve(dtree, strings[i])) + { + printf("still retrievable after delete: %s\n", + strings[i]); + errors++; + } + check_all_retrievable(dtree); + } + + mowgli_patricia_destroy(dtree, NULL, NULL); + + for (i = 0; i < TESTSIZE; i++) + free(strings[i]); +} + +int main(int argc, char *argv[]) +{ + mowgli_init(); + + test_patricia(); + + return errors == 0 ? 0 : 1; +} diff --git a/src/examples/randomtest/Makefile b/src/examples/randomtest/Makefile new file mode 100644 index 0000000..b64193e --- /dev/null +++ b/src/examples/randomtest/Makefile @@ -0,0 +1,7 @@ +PROG_NOINST = randomtest${PROG_SUFFIX} +SRCS = randomtest.c + +include ../../../buildsys.mk + +CPPFLAGS += -I../../libmowgli +LIBS += -L../../libmowgli -lmowgli diff --git a/src/examples/randomtest/randomtest.c b/src/examples/randomtest/randomtest.c new file mode 100644 index 0000000..2c4b2d7 --- /dev/null +++ b/src/examples/randomtest/randomtest.c @@ -0,0 +1,51 @@ +/* + * libmowgli: A collection of useful routines for programming. + * randomtest.c: Testsuite for the random number generator. + * + * Copyright (c) 2007 William Pitcock + * Algorithm copyright (c) 1999-2007 Takuji Nishimura and Makoto Matsumoto + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include + +int main(int argc, char *argv[]) +{ + mowgli_random_t *r = mowgli_random_create(); + int i; + + printf("1000 iterations:\n"); + for (i = 0; i < 1000; i++) + { + printf("%10u ", mowgli_random_int(r)); + if (i % 5 == 4) printf("\n"); + } + + mowgli_object_unref(r); + + return 0; +} diff --git a/src/libmowgli/Makefile b/src/libmowgli/Makefile new file mode 100644 index 0000000..d25902e --- /dev/null +++ b/src/libmowgli/Makefile @@ -0,0 +1,77 @@ +include ../../extra.mk + +LIB = ${LIB_PREFIX}mowgli${LIB_SUFFIX} +LIB_MAJOR = 2 +LIB_MINOR = 0 +DISTCLEAN = mowgli_config.h + +SRCS = mowgli_alloc.c \ + mowgli_allocation_policy.c \ + mowgli_allocator.c \ + mowgli_argstack.c \ + mowgli_bitvector.c \ + mowgli_dictionary.c \ + mowgli_error_backtrace.c \ + mowgli_formatter.c \ + mowgli_global_storage.c \ + mowgli_hash.c \ + mowgli_heap.c \ + mowgli_hook.c \ + mowgli_index.c \ + mowgli_init.c \ + mowgli_ioevent.c \ + mowgli_list.c \ + mowgli_logger.c \ + mowgli_mempool.c \ + $(MOWGLI_MODULE) \ + mowgli_object.c \ + mowgli_object_class.c \ + mowgli_object_messaging.c \ + mowgli_object_metadata.c \ + mowgli_patricia.c \ + mowgli_queue.c \ + mowgli_random.c \ + mowgli_signal.c \ + mowgli_spinlock.c \ + mowgli_string.c \ + +INCLUDES = mowgli.h \ + mowgli_alloc.h \ + mowgli_allocation_policy.h \ + mowgli_allocator.h \ + mowgli_argstack.h \ + mowgli_assert.h \ + mowgli_bitvector.h \ + mowgli_config.h \ + mowgli_dictionary.h \ + mowgli_error_backtrace.h \ + mowgli_exception.h \ + mowgli_formatter.h \ + mowgli_global_storage.h \ + mowgli_hash.h \ + mowgli_heap.h \ + mowgli_hook.h \ + mowgli_index.h \ + mowgli_init.h \ + mowgli_ioevent.h \ + mowgli_iterator.h \ + mowgli_list.h \ + mowgli_logger.h \ + mowgli_mempool.h \ + mowgli_module.h \ + mowgli_object.h \ + mowgli_object_class.h \ + mowgli_object_messaging.h \ + mowgli_object_metadata.h \ + mowgli_patricia.h \ + mowgli_queue.h \ + mowgli_random.h \ + mowgli_signal.h \ + mowgli_spinlock.h \ + mowgli_stdinc.h \ + mowgli_string.h + +include ../../buildsys.mk + +CPPFLAGS += ${LIB_CPPFLAGS} -I. -I.. -DMOWGLI_CORE +CFLAGS += ${LIB_CFLAGS} diff --git a/src/libmowgli/mowgli.h b/src/libmowgli/mowgli.h new file mode 100644 index 0000000..fe494b2 --- /dev/null +++ b/src/libmowgli/mowgli.h @@ -0,0 +1,81 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli.h: Base header for libmowgli. Includes everything. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_STAND_H__ +#define __MOWGLI_STAND_H__ + +#ifdef __cplusplus +# define MOWGLI_DECLS_START extern "C" { +# define MOWGLI_DECLS_END } +#else +# define MOWGLI_DECLS_START +# define MOWGLI_DECLS_END +#endif + +#ifdef MOWGLI_CORE +# include "win32_support.h" +# include "mowgli_config.h" +#endif + +#include "mowgli_stdinc.h" + +MOWGLI_DECLS_START + +#include "mowgli_logger.h" +#include "mowgli_assert.h" +#include "mowgli_exception.h" +#include "mowgli_iterator.h" + +#include "mowgli_alloc.h" +#include "mowgli_spinlock.h" +#include "mowgli_list.h" +#include "mowgli_object_class.h" +#include "mowgli_object.h" +#include "mowgli_allocation_policy.h" +#include "mowgli_dictionary.h" +#include "mowgli_patricia.h" +#include "mowgli_mempool.h" +#include "mowgli_module.h" +#include "mowgli_queue.h" +#include "mowgli_hash.h" +#include "mowgli_heap.h" +#include "mowgli_init.h" +#include "mowgli_bitvector.h" +#include "mowgli_hook.h" +#include "mowgli_signal.h" +#include "mowgli_error_backtrace.h" +#include "mowgli_random.h" +#include "mowgli_ioevent.h" +#include "mowgli_argstack.h" +#include "mowgli_object_messaging.h" +#include "mowgli_object_metadata.h" +#include "mowgli_global_storage.h" +#include "mowgli_string.h" +#include "mowgli_allocator.h" +#include "mowgli_formatter.h" +#include "mowgli_index.h" + +MOWGLI_DECLS_END + +#endif + diff --git a/src/libmowgli/mowgli_alloc.c b/src/libmowgli/mowgli_alloc.c new file mode 100644 index 0000000..c7d3c4f --- /dev/null +++ b/src/libmowgli/mowgli_alloc.c @@ -0,0 +1,133 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_alloc.c: Safe, portable implementations of malloc, calloc, and free. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* + * bootstrapped allocators so that we can initialise without blowing up + */ + +static void * +_mowgli_bootstrap_alloc(int size) +{ + return calloc(size, 1); +} + +static void +_mowgli_bootstrap_free(void *ptr) +{ + if (ptr) + free(ptr); +} + +static mowgli_allocation_policy_t _mowgli_allocator_bootstrap = { + { 0 }, + _mowgli_bootstrap_alloc, + _mowgli_bootstrap_free +}; + +static mowgli_allocation_policy_t *_mowgli_allocator = &_mowgli_allocator_bootstrap; + +/* + * \brief Allocates an array of data that contains "count" objects, + * of "size" size. + * + * Usually, this wraps calloc(). + * + * \param size size of objects to allocate. + * \param count amount of objects to allocate. + * + * \return A pointer to a memory buffer. + */ +void * +mowgli_alloc_array(size_t size, size_t count) +{ + return_val_if_fail(_mowgli_allocator != NULL, NULL); + + return _mowgli_allocator->allocate(size * count); +} + +/* + * \brief Allocates an object of "size" size. + * + * This is the equivilant of calling mowgli_alloc_array(size, 1). + * + * \param size size of object to allocate. + * + * \return A pointer to a memory buffer. + */ +void * +mowgli_alloc(size_t size) +{ + return mowgli_alloc_array(size, 1); +} + +/* + * \brief Frees an object back to the system memory pool. + * + * Wraps free protecting against common mistakes (reports an error instead). + * + * \param ptr pointer to object to free. + */ +void +mowgli_free(void *ptr) +{ + return_if_fail(_mowgli_allocator != NULL); + return_if_fail(ptr != NULL); + + _mowgli_allocator->deallocate(ptr); +} + +/* + * \brief Sets the mowgli.allocation_policy used by the allocation primitives. + * + * \param policy The mowgli_allocation_policy_t object to use. + */ +void +mowgli_allocator_set_policy(mowgli_allocation_policy_t *policy) +{ + return_if_fail(policy != NULL); + + _mowgli_allocator = policy; +} + +/* + * \brief Sets the mowgli.allocation_policy used by the allocation primitives, + * when given a name. + * + * \param name The name of the policy to use. + */ +void +mowgli_allocator_set_policy_by_name(const char *name) +{ + mowgli_allocation_policy_t *policy; + + return_if_fail(name != NULL); + + policy = mowgli_allocation_policy_lookup(name); + + if (policy == NULL) + return; + + mowgli_allocator_set_policy(policy); +} diff --git a/src/libmowgli/mowgli_alloc.h b/src/libmowgli/mowgli_alloc.h new file mode 100644 index 0000000..16bd674 --- /dev/null +++ b/src/libmowgli/mowgli_alloc.h @@ -0,0 +1,31 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_alloc.h: Safe, portable implementations of malloc, calloc, and free. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ALLOC_H__ +#define __MOWGLI_ALLOC_H__ + +extern void * mowgli_alloc_array(size_t size, size_t count); +extern void * mowgli_alloc(size_t size); +extern void mowgli_free(void *ptr); + +#endif diff --git a/src/libmowgli/mowgli_allocation_policy.c b/src/libmowgli/mowgli_allocation_policy.c new file mode 100644 index 0000000..8f390d1 --- /dev/null +++ b/src/libmowgli/mowgli_allocation_policy.c @@ -0,0 +1,70 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_allocation_policy.h: Allocation policy management. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_object_class_t klass; +static mowgli_patricia_t *mowgli_allocation_policy_dict = NULL; + +static void _allocation_policy_key_canon(char *str) +{ + +} + +void +mowgli_allocation_policy_init(void) +{ + mowgli_allocation_policy_dict = mowgli_patricia_create(_allocation_policy_key_canon); + + mowgli_object_class_init(&klass, "mowgli.allocation_policy", NULL, FALSE); +} + +mowgli_allocation_policy_t * +mowgli_allocation_policy_create(const char *name, mowgli_allocation_func_t allocator, + mowgli_deallocation_func_t deallocator) +{ + mowgli_allocation_policy_t *policy; + + if (mowgli_allocation_policy_dict == NULL) + mowgli_allocation_policy_dict = mowgli_patricia_create(_allocation_policy_key_canon); + + if ((policy = mowgli_patricia_retrieve(mowgli_allocation_policy_dict, name))) + return policy; + + policy = mowgli_alloc(sizeof(mowgli_allocation_policy_t)); + mowgli_object_init_from_class(mowgli_object(policy), name, &klass); + + policy->allocate = allocator; + policy->deallocate = deallocator; + + return policy; +} + +mowgli_allocation_policy_t * +mowgli_allocation_policy_lookup(const char *name) +{ + if (mowgli_allocation_policy_dict == NULL) + mowgli_allocation_policy_dict = mowgli_patricia_create(_allocation_policy_key_canon); + + return mowgli_patricia_retrieve(mowgli_allocation_policy_dict, name); +} diff --git a/src/libmowgli/mowgli_allocation_policy.h b/src/libmowgli/mowgli_allocation_policy.h new file mode 100644 index 0000000..037b8f9 --- /dev/null +++ b/src/libmowgli/mowgli_allocation_policy.h @@ -0,0 +1,45 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_allocation_policy.h: Allocation policy management. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ALLOCATION_POLICY_H__ +#define __MOWGLI_ALLOCATION_POLICY_H__ + +typedef void *(*mowgli_allocation_func_t)(int size); +typedef void (*mowgli_deallocation_func_t)(void *ptr); + +typedef struct { + mowgli_object_t parent; + mowgli_allocation_func_t allocate; + mowgli_deallocation_func_t deallocate; +} mowgli_allocation_policy_t; + +void mowgli_allocation_policy_init(void); +mowgli_allocation_policy_t *mowgli_allocation_policy_create(const char *name, + mowgli_allocation_func_t allocator, mowgli_deallocation_func_t deallocator); +mowgli_allocation_policy_t *mowgli_allocation_policy_lookup(const char *name); + +/* for mowgli_alloc, et. al */ +void mowgli_allocator_set_policy(mowgli_allocation_policy_t *policy); +void mowgli_allocator_set_policy_by_name(const char *name); + +#endif diff --git a/src/libmowgli/mowgli_allocator.c b/src/libmowgli/mowgli_allocator.c new file mode 100644 index 0000000..8c4bd69 --- /dev/null +++ b/src/libmowgli/mowgli_allocator.c @@ -0,0 +1,46 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_allocator.h: Builtin allocation policies (mmap/malloc). + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +mowgli_allocation_policy_t *mowgli_allocator_malloc = NULL; + +static void * +mowgli_allocator_func_malloc(int size) +{ + return calloc(size, 1); +} + +static void +mowgli_allocator_func_free(void *ptr) +{ + if (ptr) + free(ptr); +} + +void +mowgli_allocator_init(void) +{ + mowgli_allocator_malloc = mowgli_allocation_policy_create("malloc", mowgli_allocator_func_malloc, + mowgli_allocator_func_free); +} diff --git a/src/libmowgli/mowgli_allocator.h b/src/libmowgli/mowgli_allocator.h new file mode 100644 index 0000000..1e2b703 --- /dev/null +++ b/src/libmowgli/mowgli_allocator.h @@ -0,0 +1,31 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_allocator.h: Builtin allocation policies (mmap/malloc). + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ALLOCATOR_H__ +#define __MOWGLI_ALLOCATOR_H__ + +void mowgli_allocator_init(void) MOWGLI_DEPRECATED; +extern mowgli_allocation_policy_t *mowgli_allocator_malloc MOWGLI_DEPRECATED; + +#endif + diff --git a/src/libmowgli/mowgli_argstack.c b/src/libmowgli/mowgli_argstack.c new file mode 100644 index 0000000..0ad5c91 --- /dev/null +++ b/src/libmowgli/mowgli_argstack.c @@ -0,0 +1,247 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_argstack.c: Argument stacks. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_object_class_t klass; + +/* + * \brief Private destructor for the mowgli_argstack_t object. + * + * \param vptr pointer to mowgli_argstack_t to destroy. + */ +static void mowgli_argstack_destroy(void *vptr) +{ + mowgli_argstack_t *self = (mowgli_argstack_t *) vptr; + mowgli_node_t *n, *tn; + + MOWGLI_LIST_FOREACH_SAFE(n, tn, self->stack.head) + { + mowgli_free(n->data); + + mowgli_node_delete(n, &self->stack); + mowgli_node_free(n); + } + + mowgli_free(self); +} + +/* + * \brief Initialization code for the mowgli.argstack library. + * + * Side Effects: + * - the mowgli_argstack_t object class is registered. + */ +void mowgli_argstack_init(void) +{ + mowgli_object_class_init(&klass, "mowgli_argstack_t", mowgli_argstack_destroy, FALSE); +} + +/* + * \brief Creates an argument stack from a va_list and an appropriate + * description schema. + * + * \param descstr a description string which describes the argument stack, where: + * + the character 's' means that the value for that slot is a string + * + the character 'd' means that the value for that slot is a numeric + * + the character 'p' means that the value for that slot is a generic pointer + * + the character 'b' means that the value for that slot is a boolean + * \param va a va_list containing data to populate the argument stack with. + * + * \return a mowgli_argstack_t (mowgli.argstack) object. + */ +mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_list va) +{ + const char *cp = descstr; + mowgli_argstack_t *out = mowgli_alloc(sizeof(mowgli_argstack_t)); + mowgli_object_init(mowgli_object(out), descstr, &klass, NULL); + + if (descstr == NULL) + mowgli_throw_exception_val(mowgli.argstack.invalid_description, NULL); + + while (*cp) + { + mowgli_argstack_element_t *e = mowgli_alloc(sizeof(mowgli_argstack_element_t)); + + switch(*cp) + { + case 's': + e->data.string = va_arg(va, char *); + e->type = MOWGLI_ARG_STRING; + break; + case 'd': + e->data.numeric = va_arg(va, int); + e->type = MOWGLI_ARG_NUMERIC; + break; + case 'p': + e->data.pointer = va_arg(va, void *); + e->type = MOWGLI_ARG_POINTER; + break; + case 'b': + e->data.boolean = va_arg(va, mowgli_boolean_t); + e->type = MOWGLI_ARG_BOOLEAN; + break; + default: + va_end(va); + mowgli_object_unref(out); + mowgli_throw_exception_val(mowgli.argstack.invalid_description, NULL); + break; + } + + mowgli_node_add(e, mowgli_node_create(), &out->stack); + cp++; + } + + return out; +} + +/* + * \brief Creates an argument stack. + * + * \param descstr a description string which describes the argument stack, where: + * + the character 's' means that the value for that slot is a string + * + the character 'd' means that the value for that slot is a numeric + * + the character 'p' means that the value for that slot is a generic pointer + * + the character 'b' means that the value for that slot is a boolean + * \param va a va_list containing data to populate the argument stack with. + * + * \return a mowgli_argstack_t (mowgli.argstack) object. + */ +mowgli_argstack_t *mowgli_argstack_create(const char *descstr, ...) +{ + va_list va; + mowgli_argstack_t *out; + + if (descstr == NULL) + mowgli_throw_exception_val(mowgli.argstack.invalid_description, NULL); + + va_start(va, descstr); + out = mowgli_argstack_create_from_va_list(descstr, va); + va_end(va); + + return out; +} + +/* + * \brief Convenience function to pop a string value off of an argument stack. + * + * \param self A mowgli_argstack_t object to pop a string off of. + * + * \return On success, a string. + * + * Side Effects: + * - the argument is removed from the argstack. + */ +const char *mowgli_argstack_pop_string(mowgli_argstack_t *self) +{ + mowgli_node_t *n; + mowgli_argstack_element_t *e; + + if (self == NULL) + mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL); + + n = self->stack.head; + mowgli_node_delete(n, &self->stack); + e = n->data; + mowgli_node_free(n); + + return e->data.string; +} + +/* + * \brief Convenience function to pop a numeric value off of an argument stack. + * + * \param self A mowgli_argstack_t object to pop a numeric off of. + * + * \return On success, a numeric. + * + * Side Effects: + * - the argument is removed from the argstack. + */ +int mowgli_argstack_pop_numeric(mowgli_argstack_t *self) +{ + mowgli_node_t *n; + mowgli_argstack_element_t *e; + + if (self == NULL) + mowgli_throw_exception_val(mowgli.null_pointer_exception, 0); + + n = self->stack.head; + mowgli_node_delete(n, &self->stack); + e = n->data; + mowgli_node_free(n); + + return e->data.numeric; +} + +/* + * Convenience function to pop a boolean value off of an argument stack. + * + * \param self A mowgli_argstack_t object to pop a boolean off of. + * + * \return On success, a boolean value. + * + * Side Effects: + * - the argument is removed from the argstack. + */ +mowgli_boolean_t mowgli_argstack_pop_boolean(mowgli_argstack_t *self) +{ + mowgli_node_t *n; + mowgli_argstack_element_t *e; + + if (self == NULL) + mowgli_throw_exception_val(mowgli.null_pointer_exception, FALSE); + + n = self->stack.head; + mowgli_node_delete(n, &self->stack); + e = n->data; + mowgli_node_free(n); + + return e->data.boolean; +} + +/* + * \brief Convenience function to pop a pointer value off of an argument stack. + * + * \param self A mowgli_argstack_t object to pop a pointer off of. + * + * \return On success, a pointer. + * + * Side Effects: + * - the argument is removed from the argstack. + */ +void *mowgli_argstack_pop_pointer(mowgli_argstack_t *self) +{ + mowgli_node_t *n; + mowgli_argstack_element_t *e; + + if (self == NULL) + mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL); + + n = self->stack.head; + mowgli_node_delete(n, &self->stack); + e = n->data; + mowgli_node_free(n); + + return e->data.pointer; +} diff --git a/src/libmowgli/mowgli_argstack.h b/src/libmowgli/mowgli_argstack.h new file mode 100644 index 0000000..8e7428c --- /dev/null +++ b/src/libmowgli/mowgli_argstack.h @@ -0,0 +1,57 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_argstack.h: Argument stacks. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ARGSTACK_H__ +#define __MOWGLI_ARGSTACK_H__ + +typedef enum { + MOWGLI_ARG_NUMERIC, + MOWGLI_ARG_POINTER, + MOWGLI_ARG_STRING, + MOWGLI_ARG_BOOLEAN +} mowgli_argstack_element_type_t; + +typedef struct { + union { + int numeric; + void *pointer; + char *string; + mowgli_boolean_t boolean; + } data; + mowgli_argstack_element_type_t type; +} mowgli_argstack_element_t; + +typedef struct { + mowgli_object_t parent; + mowgli_list_t stack; +} mowgli_argstack_t; + +extern mowgli_argstack_t *mowgli_argstack_create(const char *descstr, ...); +extern mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_list va); +extern void mowgli_argstack_init(void); +extern const char *mowgli_argstack_pop_string(mowgli_argstack_t *); +extern int mowgli_argstack_pop_numeric(mowgli_argstack_t *); +extern mowgli_boolean_t mowgli_argstack_pop_boolean(mowgli_argstack_t *); +extern void *mowgli_argstack_pop_pointer(mowgli_argstack_t *); + +#endif diff --git a/src/libmowgli/mowgli_assert.h b/src/libmowgli/mowgli_assert.h new file mode 100644 index 0000000..8ee2c4f --- /dev/null +++ b/src/libmowgli/mowgli_assert.h @@ -0,0 +1,105 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_assert.h: Assertions. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ASSERT_H__ +#define __MOWGLI_ASSERT_H__ + +extern void mowgli_soft_assert_log(const char *asrt, const char *file, int line, const char *function); + +#ifdef __GNUC__ + +/* + * Performs a soft assertion. If the assertion fails, we log it. + */ +#define soft_assert(x) \ + if (!(x)) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } + +/* + * Same as soft_assert, but returns if an assertion fails. + */ +#define return_if_fail(x) \ + if (!(x)) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return; \ + } + +/* + * Same as soft_assert, but returns a given value if an assertion fails. + */ +#define return_val_if_fail(x, y) \ + if (!(x)) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return (y); \ + } + +/* + * Same as soft_assert, but returns NULL if the value is NULL. + */ +#define return_if_null(x) \ + if (x == NULL) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return (NULL); \ + } + +#else + +/* + * Performs a soft assertion. If the assertion fails, we log it. + */ +#define soft_assert(x) \ + if (!(x)) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ + } + +/* + * Same as soft_assert, but returns if an assertion fails. + */ +#define return_if_fail(x) \ + if (!(x)) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ + return; \ + } + +/* + * Same as soft_assert, but returns a given value if an assertion fails. + */ +#define return_val_if_fail(x, y) \ + if (!(x)) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ + return (y); \ + } + +/* + * Same as soft_assert, but returns NULL if the value is NULL. + */ +#define return_if_null(x) \ + if (x == NULL) { \ + mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ + return (NULL); \ + } + +#endif + +#endif diff --git a/src/libmowgli/mowgli_bitvector.c b/src/libmowgli/mowgli_bitvector.c new file mode 100644 index 0000000..8186c16 --- /dev/null +++ b/src/libmowgli/mowgli_bitvector.c @@ -0,0 +1,238 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_bitvector.c: Bitvectors. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_object_class_t klass; + +/* + * mowgli_bitvector_init(void) + * + * Initialization code for the mowgli.bitvector library. + * + * Inputs: + * - none + * + * Outputs: + * - none + * + * Side Effects: + * - the mowgli_bitvector_t object class is registered. + */ +void mowgli_bitvector_init(void) +{ + mowgli_object_class_init(&klass, "mowgli_bitvector_t", mowgli_free, FALSE); +} + +/* + * mowgli_bitvector_create(int bits) + * + * Creates a bitvector. + * + * Inputs: + * - amount of bits that the bitvector should store + * + * Outputs: + * - a mowgli.bitvector object + * + * Side Effects: + * - none + */ +mowgli_bitvector_t *mowgli_bitvector_create(int bits) +{ + mowgli_bitvector_t *bv = (mowgli_bitvector_t *) mowgli_alloc(sizeof(mowgli_bitvector_t)); + mowgli_object_init(mowgli_object(bv), "mowgli_bitvector_t", &klass, NULL); + + bv->bits = bits; + bv->divisor = sizeof(int); + bv->vector = (unsigned int *) mowgli_alloc_array(bv->divisor, bv->bits / bv->divisor); + + return bv; +} + +/* + * mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val) + * + * Sets a bit either ON or OFF in the bitvector. + * + * Inputs: + * - a mowgli bitvector object + * - a slot + * - the value for that slot + * + * Outputs: + * - nothing + * + * Side Effects: + * - a bit is either set ON or OFF in the bitvector. + */ +void mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val) +{ + int value = 1 << slot; + + switch(val) + { + case FALSE: + bv->vector[bv->bits / bv->divisor] &= ~value; + break; + default: + case TRUE: + bv->vector[bv->bits / bv->divisor] |= value; + break; + } +} + +/* + * mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot) + * + * Returns whether the bit in a given slot is ON or OFF. + * + * Inputs: + * - a mowgli.bitvector object + * - a slot to lookup + * + * Outputs: + * - TRUE if the bit is on + * - FALSE otherwise + * + * Side Effects: + * - none + */ +mowgli_boolean_t mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot) +{ + int mask = 1 << slot; + + return ((bv->vector[bv->bits / bv->divisor] & mask) != 0) ? TRUE : FALSE; +} + +/* + * mowgli_bitvector_combine(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) + * + * Combines two bitvectors together. + * + * Inputs: + * - two bitvectors to be combined + * + * Outputs: + * - a new bitvector containing the combined result. + * + * Side Effects: + * - none + */ +mowgli_bitvector_t *mowgli_bitvector_combine(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) +{ + int bits, iter, bs; + mowgli_bitvector_t *out; + + return_val_if_fail(bv1 != NULL, NULL); + return_val_if_fail(bv2 != NULL, NULL); + + /* choose the larger bitwidth */ + bits = bv1->bits > bv2->bits ? bv1->bits : bv2->bits; + + /* create the third bitvector. */ + out = mowgli_bitvector_create(bits); + + /* cache the size of the bitvector in memory. */ + bs = out->bits / out->divisor; + + for (iter = 0; iter < bs; iter++) + { + out->vector[iter] |= bv1->vector[iter]; + out->vector[iter] |= bv2->vector[iter]; + } + + return out; +} + +/* + * mowgli_bitvector_xor(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) + * + * XORs two bitvectors together. + * + * Inputs: + * - two bitvectors to be XORed + * + * Outputs: + * - a new bitvector containing the XORed result. + * + * Side Effects: + * - none + */ +mowgli_bitvector_t *mowgli_bitvector_xor(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) +{ + int bits, iter, bs; + mowgli_bitvector_t *out; + + return_val_if_fail(bv1 != NULL, NULL); + return_val_if_fail(bv2 != NULL, NULL); + + /* choose the larger bitwidth */ + bits = bv1->bits > bv2->bits ? bv1->bits : bv2->bits; + + /* create the third bitvector. */ + out = mowgli_bitvector_create(bits); + + /* cache the size of the bitvector in memory. */ + bs = out->bits / out->divisor; + + for (iter = 0; iter < bs; iter++) + { + out->vector[iter] = bv1->vector[iter]; + out->vector[iter] &= ~bv2->vector[iter]; + } + + return out; +} + +/* + * mowgli_bitvector_compare(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) + * + * Compares two bitvectors to each other. + * + * Inputs: + * - two bitvectors to be compared + * + * Outputs: + * - TRUE if the bitvector is equal + * - FALSE otherwise + * + * Side Effects: + * - none + */ +mowgli_boolean_t mowgli_bitvector_compare(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2) +{ + int iter, bs; + mowgli_boolean_t ret = TRUE; + + /* cache the size of the bitvector in memory. */ + bs = bv1->bits / bv1->divisor; + + for (iter = 0; iter < bs; iter++) + { + if (!(bv1->vector[iter] & bv2->vector[iter])) + ret = FALSE; + } + + return ret; +} diff --git a/src/libmowgli/mowgli_bitvector.h b/src/libmowgli/mowgli_bitvector.h new file mode 100644 index 0000000..195d8d9 --- /dev/null +++ b/src/libmowgli/mowgli_bitvector.h @@ -0,0 +1,41 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_bitvector.h: Bitvectors. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_BITVECTOR_H__ +#define __MOWGLI_BITVECTOR_H__ + +typedef struct { + unsigned int bits; + unsigned int divisor; + unsigned int *vector; +} mowgli_bitvector_t; + +extern void mowgli_bitvector_init(void); +extern mowgli_bitvector_t *mowgli_bitvector_create(int bits); +extern void mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val); +extern mowgli_boolean_t mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot); +extern mowgli_bitvector_t *mowgli_bitvector_combine(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2); +extern mowgli_bitvector_t *mowgli_bitvector_xor(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2); +extern mowgli_boolean_t mowgli_bitvector_compare(mowgli_bitvector_t *bv1, mowgli_bitvector_t *bv2); + +#endif diff --git a/src/libmowgli/mowgli_config.h.in b/src/libmowgli/mowgli_config.h.in new file mode 100644 index 0000000..c43e92c --- /dev/null +++ b/src/libmowgli/mowgli_config.h.in @@ -0,0 +1,147 @@ +/* src/libmowgli/mowgli_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +#undef CLOSEDIR_VOID + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the `epoll_ctl' function. */ +#undef HAVE_EPOLL_CTL + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the `port_create' function. */ +#undef HAVE_PORT_CREATE + +/* Define to 1 if you have the `printf' function. */ +#undef HAVE_PRINTF + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the `sprintf' function. */ +#undef HAVE_SPRINTF + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the `strtod' function. */ +#undef HAVE_STRTOD + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/src/libmowgli/mowgli_dictionary.c b/src/libmowgli/mowgli_dictionary.c new file mode 100644 index 0000000..abcb2f9 --- /dev/null +++ b/src/libmowgli/mowgli_dictionary.c @@ -0,0 +1,914 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_dictionary.c: Dictionary-based information storage. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007 Jilles Tjoelker + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *elem_heap = NULL; + +struct mowgli_dictionary_ +{ + mowgli_dictionary_comparator_func_t compare_cb; + mowgli_dictionary_elem_t *root, *head, *tail; + unsigned int count; + char *id; + mowgli_boolean_t dirty; +}; + +static void warn_deprecated (void) +{ + static char warned = 0; + if (warned) + return; + + printf("mowgli_dictionary is deprecated and pending removal in Mowgli 1.0 " + "series.\nPlease use mowgli_patricia instead.\n"); + warned = 1; +} + +/* + * mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) + * + * Dictionary object factory. + * + * Inputs: + * - function to use for comparing two entries in the dtree + * + * Outputs: + * - on success, a new dictionary object. + * + * Side Effects: + * - if services runs out of memory and cannot allocate the object, + * the program will abort. + */ +mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) +{ + mowgli_dictionary_t *dtree = (mowgli_dictionary_t *) mowgli_alloc(sizeof(mowgli_dictionary_t)); + + dtree->compare_cb = compare_cb; + + if (!elem_heap) + elem_heap = mowgli_heap_create(sizeof(mowgli_dictionary_elem_t), 1024, BH_NOW); + + warn_deprecated(); + return dtree; +} + +/* + * mowgli_dictionary_create_named(const char *name, + * mowgli_dictionary_comparator_func_t compare_cb) + * + * Dictionary object factory. + * + * Inputs: + * - dictionary name + * - function to use for comparing two entries in the dtree + * + * Outputs: + * - on success, a new dictionary object. + * + * Side Effects: + * - if services runs out of memory and cannot allocate the object, + * the program will abort. + */ +mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, + mowgli_dictionary_comparator_func_t compare_cb) +{ + mowgli_dictionary_t *dtree = (mowgli_dictionary_t *) mowgli_alloc(sizeof(mowgli_dictionary_t)); + + dtree->compare_cb = compare_cb; + dtree->id = strdup(name); + + if (!elem_heap) + elem_heap = mowgli_heap_create(sizeof(mowgli_dictionary_elem_t), 1024, BH_NOW); + + warn_deprecated(); + return dtree; +} + +/* + * mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, + * mowgli_dictionary_comparator_func_t compare_cb) + * + * Resets the comparator function used by the dictionary code for + * updating the DTree structure. + * + * Inputs: + * - dictionary object + * - new comparator function (passed as functor) + * + * Outputs: + * - nothing + * + * Side Effects: + * - the dictionary comparator function is reset. + */ +void mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, + mowgli_dictionary_comparator_func_t compare_cb) +{ + return_if_fail(dict != NULL); + return_if_fail(compare_cb != NULL); + + dict->compare_cb = compare_cb; +} + +/* + * mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict) + * + * Returns the current comparator function used by the dictionary. + * + * Inputs: + * - dictionary object + * + * Outputs: + * - comparator function (returned as functor) + * + * Side Effects: + * - none + */ +mowgli_dictionary_comparator_func_t +mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict) +{ + return_val_if_fail(dict != NULL, NULL); + + return dict->compare_cb; +} + +/* + * mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, + * const char *key) + * + * Gets a linear index number for key. + * + * Inputs: + * - dictionary tree object + * - pointer to data + * + * Outputs: + * - position, from zero. + * + * Side Effects: + * - rebuilds the linear index if the tree is marked as dirty. + */ +int +mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const char *key) +{ + mowgli_dictionary_elem_t *elem; + + return_val_if_fail(dict != NULL, 0); + return_val_if_fail(key != NULL, 0); + + elem = mowgli_dictionary_find(dict, key); + if (elem == NULL) + return -1; + + if (!dict->dirty) + return elem->position; + else + { + mowgli_dictionary_elem_t *delem; + int i; + + for (delem = dict->head, i = 0; delem != NULL; delem = delem->next, i++) + delem->position = i; + + dict->dirty = FALSE; + } + + return elem->position; +} + +/* + * mowgli_dictionary_retune(mowgli_dictionary_t *dict, const char *key) + * + * Retunes the tree, self-optimizing for the element which belongs to key. + * + * Tuning the tree structure is a very complex operation. Unlike + * 2-3-4 trees and BTree/BTree+ structures, this structure is a + * constantly evolving algorithm. + * + * Instead of maintaining a balanced tree, we constantly adapt the + * tree by nominating a new root nearby the most recently looked up + * or added data. We are constantly retuning ourselves instead of + * doing massive O(n) rebalance operations as seen in BTrees, + * and the level of data stored in a tree is dynamic, instead of being + * held to a restricted design like other trees. + * + * Moreover, we are different than a radix/patricia tree, because we + * don't statically allocate positions. Radix trees have the advantage + * of not requiring tuning or balancing operations while having the + * disadvantage of requiring a large amount of memory to store + * large trees. Our efficiency as far as speed goes is not as + * fast as a radix tree; but is close to it. + * + * The retuning algorithm uses the comparison callback that is + * passed in the initialization of the tree container. If the + * comparator returns a value which is less than zero, we push the + * losing node out of the way, causing it to later be reparented + * with another node. The winning child of this comparison is always + * the right-most node. + * + * Once we have reached the key which has been targeted, or have reached + * a deadend, we nominate the nearest node as the new root of the tree. + * If an exact match has been found, the new root becomes the node which + * represents key. + * + * This results in a tree which can self-optimize for both critical + * conditions: nodes which are distant and similar and trees which + * have ordered lookups. + * + * Inputs: + * - node to begin search from + * + * Outputs: + * - none + * + * Side Effects: + * - a new root node is nominated. + */ +void +mowgli_dictionary_retune(mowgli_dictionary_t *dict, const char *key) +{ + mowgli_dictionary_elem_t n, *tn, *left, *right, *node; + int ret; + + return_if_fail(dict != NULL); + + if (dict->root == NULL) + return; + + /* + * we initialize n with known values, since it's on stack + * memory. otherwise the dict would become corrupted. + * + * n is used for temporary storage while the tree is retuned. + * -nenolod + */ + n.left = n.right = NULL; + left = right = &n; + + /* this for(;;) loop is the main workhorse of the rebalancing */ + for (node = dict->root; ; ) + { + if ((ret = dict->compare_cb(key, node->key)) == 0) + break; + + if (ret < 0) + { + if (node->left == NULL) + break; + + if ((ret = dict->compare_cb(key, node->left->key)) < 0) + { + tn = node->left; + node->left = tn->right; + tn->right = node; + node = tn; + + if (node->left == NULL) + break; + } + + right->left = node; + right = node; + node = node->left; + } + else + { + if (node->right == NULL) + break; + + if ((ret = dict->compare_cb(key, node->right->key)) > 0) + { + tn = node->right; + node->right = tn->left; + tn->left = node; + node = tn; + + if (node->right == NULL) + break; + } + + left->right = node; + left = node; + node = node->right; + } + } + + left->right = node->left; + right->left = node->right; + + node->left = n.right; + node->right = n.left; + + dict->root = node; +} + +/* + * mowgli_dictionary_link(mowgli_dictionary_t *dict, + * mowgli_dictionary_elem_t *delem) + * + * Links a dictionary tree element to the dictionary. + * + * When we add new nodes to the tree, it becomes the + * next nominated root. This is perhaps not a wise + * optimization because of automatic retuning, but + * it keeps the code simple. + * + * Inputs: + * - dictionary tree + * - dictionary tree element + * + * Outputs: + * - nothing + * + * Side Effects: + * - a node is linked to the dictionary tree + */ +void +mowgli_dictionary_link(mowgli_dictionary_t *dict, + mowgli_dictionary_elem_t *delem) +{ + return_if_fail(dict != NULL); + return_if_fail(delem != NULL); + + dict->dirty = TRUE; + + dict->count++; + + if (dict->root == NULL) + { + delem->left = delem->right = NULL; + delem->next = delem->prev = NULL; + dict->head = dict->tail = dict->root = delem; + } + else + { + int ret; + + mowgli_dictionary_retune(dict, delem->key); + + if ((ret = dict->compare_cb(delem->key, dict->root->key)) < 0) + { + delem->left = dict->root->left; + delem->right = dict->root; + dict->root->left = NULL; + + if (dict->root->prev) + dict->root->prev->next = delem; + else + dict->head = delem; + + delem->prev = dict->root->prev; + delem->next = dict->root; + dict->root->prev = delem; + dict->root = delem; + } + else if (ret > 0) + { + delem->right = dict->root->right; + delem->left = dict->root; + dict->root->right = NULL; + + if (dict->root->next) + dict->root->next->prev = delem; + else + dict->tail = delem; + + delem->next = dict->root->next; + delem->prev = dict->root; + dict->root->next = delem; + dict->root = delem; + } + else + { + dict->root->key = delem->key; + dict->root->data = delem->data; + dict->count--; + + mowgli_heap_free(elem_heap, delem); + } + } +} + +/* + * mowgli_dictionary_unlink_root(mowgli_dictionary_t *dict) + * + * Unlinks the root dictionary tree element from the dictionary. + * + * Inputs: + * - dictionary tree + * + * Outputs: + * - nothing + * + * Side Effects: + * - the root node is unlinked from the dictionary tree + */ +void +mowgli_dictionary_unlink_root(mowgli_dictionary_t *dict) +{ + mowgli_dictionary_elem_t *delem, *nextnode, *parentofnext; + + dict->dirty = TRUE; + + delem = dict->root; + if (delem == NULL) + return; + + if (dict->root->left == NULL) + dict->root = dict->root->right; + else if (dict->root->right == NULL) + dict->root = dict->root->left; + else + { + /* Make the node with the next highest key the new root. + * This node has a NULL left pointer. */ + nextnode = delem->next; + soft_assert(nextnode->left == NULL); + if (nextnode == delem->right) + { + dict->root = nextnode; + dict->root->left = delem->left; + } + else + { + parentofnext = delem->right; + while (parentofnext->left != NULL && parentofnext->left != nextnode) + parentofnext = parentofnext->left; + soft_assert(parentofnext->left == nextnode); + parentofnext->left = nextnode->right; + dict->root = nextnode; + dict->root->left = delem->left; + dict->root->right = delem->right; + } + } + + /* linked list */ + if (delem->prev != NULL) + delem->prev->next = delem->next; + + if (dict->head == delem) + dict->head = delem->next; + + if (delem->next) + delem->next->prev = delem->prev; + + if (dict->tail == delem) + dict->tail = delem->prev; + + dict->count--; +} + +/* + * mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, + * void (*destroy_cb)(dictionary_elem_t *delem, void *privdata), + * void *privdata); + * + * Recursively destroys all nodes in a dictionary tree. + * + * Inputs: + * - dictionary tree object + * - optional iteration callback + * - optional opaque/private data to pass to callback + * + * Outputs: + * - nothing + * + * Side Effects: + * - on success, a dtree and optionally it's children are destroyed. + * + * Notes: + * - if this is called without a callback, the objects bound to the + * DTree will not be destroyed. + */ +void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, + void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + void *privdata) +{ + mowgli_dictionary_elem_t *n, *tn; + + return_if_fail(dtree != NULL); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, dtree->head) + { + if (destroy_cb != NULL) + (*destroy_cb)(n, privdata); + + mowgli_free(n->key); + mowgli_heap_free(elem_heap, n); + } + + mowgli_free(dtree); +} + +/* + * mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, + * void (*destroy_cb)(dictionary_elem_t *delem, void *privdata), + * void *privdata); + * + * Iterates over all entries in a DTree. + * + * Inputs: + * - dictionary tree object + * - optional iteration callback + * - optional opaque/private data to pass to callback + * + * Outputs: + * - nothing + * + * Side Effects: + * - on success, a dtree is iterated + */ +void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, + int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + void *privdata) +{ + mowgli_dictionary_elem_t *n, *tn; + + return_if_fail(dtree != NULL); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, dtree->head) + { + /* delem_t is a subclass of node_t. */ + mowgli_dictionary_elem_t *delem = (mowgli_dictionary_elem_t *) n; + + if (foreach_cb != NULL) + (*foreach_cb)(delem, privdata); + } +} + +/* + * mowgli_dictionary_search(mowgli_dictionary_t *dtree, + * void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + * void *privdata); + * + * Searches all entries in a DTree using a custom callback. + * + * Inputs: + * - dictionary tree object + * - optional iteration callback + * - optional opaque/private data to pass to callback + * + * Outputs: + * - on success, the requested object + * - on failure, NULL. + * + * Side Effects: + * - a dtree is iterated until the requested conditions are met + */ +void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, + void *(*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + void *privdata) +{ + mowgli_dictionary_elem_t *n, *tn; + void *ret = NULL; + + return_val_if_fail(dtree != NULL, NULL); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, dtree->head) + { + /* delem_t is a subclass of node_t. */ + mowgli_dictionary_elem_t *delem = (mowgli_dictionary_elem_t *) n; + + if (foreach_cb != NULL) + ret = (*foreach_cb)(delem, privdata); + + if (ret) + break; + } + + return ret; +} + +/* + * mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, + * mowgli_dictionary_iteration_state_t *state); + * + * Initializes a static DTree iterator. + * + * Inputs: + * - dictionary tree object + * - static DTree iterator + * + * Outputs: + * - nothing + * + * Side Effects: + * - the static iterator, &state, is initialized. + */ +void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, + mowgli_dictionary_iteration_state_t *state) +{ + return_if_fail(dtree != NULL); + return_if_fail(state != NULL); + + state->cur = NULL; + state->next = NULL; + + /* find first item */ + state->cur = dtree->head; + + if (state->cur == NULL) + return; + + /* make state->cur point to first item and state->next point to + * second item */ + state->next = state->cur; + mowgli_dictionary_foreach_next(dtree, state); +} + +/* + * mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, + * mowgli_dictionary_iteration_state_t *state); + * + * Returns the data from the current node being iterated by the + * static iterator. + * + * Inputs: + * - dictionary tree object + * - static DTree iterator + * + * Outputs: + * - reference to data in the current dtree node being iterated + * + * Side Effects: + * - none + */ +void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, + mowgli_dictionary_iteration_state_t *state) +{ + return_val_if_fail(dtree != NULL, NULL); + return_val_if_fail(state != NULL, NULL); + + return state->cur != NULL ? state->cur->data : NULL; +} + +/* + * mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, + * mowgli_dictionary_iteration_state_t *state); + * + * Advances a static DTree iterator. + * + * Inputs: + * - dictionary tree object + * - static DTree iterator + * + * Outputs: + * - nothing + * + * Side Effects: + * - the static iterator, &state, is advanced to a new DTree node. + */ +void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, + mowgli_dictionary_iteration_state_t *state) +{ + return_if_fail(dtree != NULL); + return_if_fail(state != NULL); + + if (state->cur == NULL) + { + mowgli_log("mowgli_dictionary_foreach_next(): called again after iteration finished on dtree<%p>", dtree); + return; + } + + state->cur = state->next; + + if (state->next == NULL) + return; + + state->next = state->next->next; +} + +/* + * mowgli_dictionary_find(mowgli_dictionary_t *dtree, const char *key) + * + * Looks up a DTree node by name. + * + * Inputs: + * - dictionary tree object + * - name of node to lookup + * + * Outputs: + * - on success, the dtree node requested + * - on failure, NULL + * + * Side Effects: + * - none + */ +mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, const char *key) +{ + return_val_if_fail(dict != NULL, NULL); + return_val_if_fail(key != NULL, NULL); + + /* retune for key, key will be the tree's root if it's available */ + mowgli_dictionary_retune(dict, key); + + if (dict->root && !dict->compare_cb(key, dict->root->key)) + return dict->root; + + return NULL; +} + +/* + * mowgli_dictionary_add(mowgli_dictionary_t *dtree, const char *key, void *data) + * + * Creates a new DTree node and binds data to it. + * + * Inputs: + * - dictionary tree object + * - name for new DTree node + * - data to bind to the new DTree node + * + * Outputs: + * - on success, a new DTree node + * - on failure, NULL + * + * Side Effects: + * - data is inserted into the DTree. + */ +mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const char *key, void *data) +{ + mowgli_dictionary_elem_t *delem; + + return_val_if_fail(dict != NULL, NULL); + return_val_if_fail(key != NULL, NULL); + return_val_if_fail(data != NULL, NULL); + return_val_if_fail(mowgli_dictionary_find(dict, key) == NULL, NULL); + + delem = mowgli_heap_alloc(elem_heap); + delem->key = strdup(key); + delem->data = data; + + if (delem->key == NULL) + { + mowgli_log("major WTF: delem->key is NULL, not adding node.", key); + mowgli_heap_free(elem_heap, delem); + return NULL; + } + + mowgli_dictionary_link(dict, delem); + + return delem; +} + +/* + * mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) + * + * Deletes data from a dictionary tree. + * + * Inputs: + * - dictionary tree object + * - name of DTree node to delete + * + * Outputs: + * - on success, the remaining data that needs to be mowgli_freed + * - on failure, NULL + * + * Side Effects: + * - data is removed from the DTree. + * + * Notes: + * - the returned data needs to be mowgli_freed/released manually! + */ +void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) +{ + mowgli_dictionary_elem_t *delem = mowgli_dictionary_find(dtree, key); + void *data; + + if (delem == NULL) + return NULL; + + data = delem->data; + + mowgli_free(delem->key); + mowgli_dictionary_unlink_root(dtree); + mowgli_heap_free(elem_heap, delem); + + return data; +} + +/* + * mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const char *key) + * + * Retrieves data from a dictionary. + * + * Inputs: + * - dictionary tree object + * - name of node to lookup + * + * Outputs: + * - on success, the data bound to the DTree node. + * - on failure, NULL + * + * Side Effects: + * - none + */ +void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const char *key) +{ + mowgli_dictionary_elem_t *delem = mowgli_dictionary_find(dtree, key); + + if (delem != NULL) + return delem->data; + + return NULL; +} + +/* + * mowgli_dictionary_size(mowgli_dictionary_t *dict) + * + * Returns the size of a dictionary. + * + * Inputs: + * - dictionary tree object + * + * Outputs: + * - size of dictionary + * + * Side Effects: + * - none + */ +unsigned int mowgli_dictionary_size(mowgli_dictionary_t *dict) +{ + return_val_if_fail(dict != NULL, 0); + + return dict->count; +} + +/* returns the sum of the depths of the subtree rooted in delem at depth depth */ +static int +stats_recurse(mowgli_dictionary_elem_t *delem, int depth, int *pmaxdepth) +{ + int result; + + if (depth > *pmaxdepth) + *pmaxdepth = depth; + result = depth; + if (delem->left) + result += stats_recurse(delem->left, depth + 1, pmaxdepth); + if (delem->right) + result += stats_recurse(delem->right, depth + 1, pmaxdepth); + return result; +} + +/* + * mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) + * + * Returns the size of a dictionary. + * + * Inputs: + * - dictionary tree object + * - callback + * - data for callback + * + * Outputs: + * - none + * + * Side Effects: + * - callback called with stats text + */ +void mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) +{ + char str[256]; + int sum, maxdepth; + + return_if_fail(dict != NULL); + + if (dict->id != NULL) + snprintf(str, sizeof str, "Dictionary stats for %s (%d)", + dict->id, dict->count); + else + snprintf(str, sizeof str, "Dictionary stats for <%p> (%d)", + dict, dict->count); + cb(str, privdata); + maxdepth = 0; + if (dict->root != NULL) + { + sum = stats_recurse(dict->root, 0, &maxdepth); + snprintf(str, sizeof str, "Depth sum %d Avg depth %d Max depth %d", sum, sum / dict->count, maxdepth); + } + else + snprintf(str, sizeof str, "Depth sum 0 Avg depth 0 Max depth 0"); + cb(str, privdata); + return; +} diff --git a/src/libmowgli/mowgli_dictionary.h b/src/libmowgli/mowgli_dictionary.h new file mode 100644 index 0000000..884cde4 --- /dev/null +++ b/src/libmowgli/mowgli_dictionary.h @@ -0,0 +1,166 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_dictionary.h: Dictionary-based storage. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007 Jilles Tjoelker + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_DICTIONARY_H__ +#define __MOWGLI_DICTIONARY_H__ + +struct mowgli_dictionary_; /* defined in src/dictionary.c */ + +typedef struct mowgli_dictionary_ mowgli_dictionary_t; + +typedef struct mowgli_dictionary_elem_ mowgli_dictionary_elem_t; + +typedef int (*mowgli_dictionary_comparator_func_t)(const char *a, const char *b); + +struct mowgli_dictionary_elem_ +{ + mowgli_dictionary_elem_t *left, *right, *prev, *next; + void *data; + char *key; + int position; +}; + +/* + * mowgli_dictionary_iteration_state_t, private. + */ +struct mowgli_dictionary_iteration_state_ +{ + mowgli_dictionary_elem_t *cur, *next; + void *pspare[4]; + int ispare[4]; +}; + +typedef struct mowgli_dictionary_iteration_state_ mowgli_dictionary_iteration_state_t; + +/* + * this is a convenience macro for inlining iteration of dictionaries. + */ +#define MOWGLI_DICTIONARY_FOREACH(element, state, dict) for (mowgli_dictionary_foreach_start((dict), (state)); (element = mowgli_dictionary_foreach_cur((dict), (state))); mowgli_dictionary_foreach_next((dict), (state))) + +/* + * mowgli_dictionary_create() creates a new dictionary tree. + * compare_cb is the comparison function, typically strcmp, strcasecmp or + * irccasecmp. + */ +extern mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_create_named() creates a new dictionary tree which has a name. + * name is the name, compare_cb is the comparator. + */ +extern mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, mowgli_dictionary_comparator_func_t compare_cb) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_set_comparator_func() resets the comparator used for lookups and + * insertions in the DTree structure. + */ +extern void mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, + mowgli_dictionary_comparator_func_t compare_cb) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_get_comparator_func() returns the comparator used for lookups and + * insertions in the DTree structure. + */ +extern mowgli_dictionary_comparator_func_t mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_get_linear_index() returns the linear index of an object in the + * DTree structure. + */ +extern int mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const char *key) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_destroy() destroys all entries in a dtree, and also optionally calls + * a defined callback function to destroy any data attached to it. + */ +extern void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, + void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + void *privdata) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_foreach() iterates all entries in a dtree, and also optionally calls + * a defined callback function to use any data attached to it. + * + * To shortcircuit iteration, return non-zero from the callback function. + */ +extern void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, + int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + void *privdata) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_search() iterates all entries in a dtree, and also optionally calls + * a defined callback function to use any data attached to it. + * + * When the object is found, a non-NULL is returned from the callback, which results + * in that object being returned to the user. + */ +extern void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, + void *(*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), + void *privdata) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_foreach_start() begins an iteration over all items + * keeping state in the given struct. If there is only one iteration + * in progress at a time, it is permitted to remove the current element + * of the iteration (but not any other element). + */ +extern void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, + mowgli_dictionary_iteration_state_t *state) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_foreach_cur() returns the current element of the iteration, + * or NULL if there are no more elements. + */ +extern void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, + mowgli_dictionary_iteration_state_t *state) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_foreach_next() moves to the next element. + */ +extern void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, + mowgli_dictionary_iteration_state_t *state) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_add() adds a key->value entry to the dictionary tree. + */ +extern mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dtree, const char *key, void *data) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_find() returns a mowgli_dictionary_elem_t container from a dtree for key 'key'. + */ +extern mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dtree, const char *key) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_find() returns data from a dtree for key 'key'. + */ +extern void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const char *key) MOWGLI_DEPRECATED; + +/* + * mowgli_dictionary_delete() deletes a key->value entry from the dictionary tree. + */ +extern void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) MOWGLI_DEPRECATED; + +void mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) MOWGLI_DEPRECATED; + +#endif diff --git a/src/libmowgli/mowgli_error_backtrace.c b/src/libmowgli/mowgli_error_backtrace.c new file mode 100644 index 0000000..02b7b4e --- /dev/null +++ b/src/libmowgli/mowgli_error_backtrace.c @@ -0,0 +1,109 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_error_backtrace.c: Print errors and explain how they were reached. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void +mowgli_error_context_display(mowgli_error_context_t *e, const char *delim) +{ + mowgli_node_t *n; + char *bt_msg; + + return_if_fail(e != NULL); + return_if_fail(delim != NULL); + + if (MOWGLI_LIST_LENGTH(&e->bt) == 0) + mowgli_throw_exception(mowgli.error_backtrace.no_backtrace); + + MOWGLI_LIST_FOREACH(n, e->bt.head) + { + bt_msg = (char *) n->data; + + printf("%s%s", bt_msg, n->next != NULL ? delim : "\n"); + } +} + +void +mowgli_error_context_destroy(mowgli_error_context_t *e) +{ + mowgli_node_t *n, *tn; + + return_if_fail(e != NULL); + + if (MOWGLI_LIST_LENGTH(&e->bt) == 0) + { + mowgli_free(e); + return; + } + + MOWGLI_LIST_FOREACH_SAFE(n, tn, e->bt.head) + { + mowgli_free(n->data); + + mowgli_node_delete(n, &e->bt); + mowgli_node_free(n); + } + + mowgli_free(e); +} + +void +mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error) +{ + mowgli_error_context_display(e, delim); + printf("Error: %s\n", error); + + exit(EXIT_FAILURE); +} + +void +mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...) +{ + char buf[65535]; + va_list va; + + return_if_fail(e != NULL); + return_if_fail(msg != NULL); + + va_start(va, msg); + vsnprintf(buf, 65535, msg, va); + va_end(va); + + mowgli_node_add(strdup(buf), mowgli_node_create(), &e->bt); +} + +void +mowgli_error_context_pop(mowgli_error_context_t *e) +{ + return_if_fail(e != NULL); + + mowgli_node_delete(e->bt.tail, &e->bt); +} + +mowgli_error_context_t * +mowgli_error_context_create(void) +{ + mowgli_error_context_t *out = (mowgli_error_context_t *) mowgli_alloc(sizeof(mowgli_error_context_t)); + + return out; +} diff --git a/src/libmowgli/mowgli_error_backtrace.h b/src/libmowgli/mowgli_error_backtrace.h new file mode 100644 index 0000000..57970b0 --- /dev/null +++ b/src/libmowgli/mowgli_error_backtrace.h @@ -0,0 +1,38 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_error_backtrace.h: Print errors and explain how they were reached. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ERROR_BACKTRACE_H__ +#define __MOWGLI_ERROR_BACKTRACE_H__ + +typedef struct mowgli_error_context_ { + mowgli_list_t bt; +} mowgli_error_context_t; + +extern void mowgli_error_context_display(mowgli_error_context_t *e, const char *delim); +extern void mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error); +extern void mowgli_error_context_destroy(mowgli_error_context_t *e); +extern void mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...); +extern void mowgli_error_context_pop(mowgli_error_context_t *e); +extern mowgli_error_context_t *mowgli_error_context_create(void); + +#endif diff --git a/src/libmowgli/mowgli_exception.h b/src/libmowgli/mowgli_exception.h new file mode 100644 index 0000000..c919bcb --- /dev/null +++ b/src/libmowgli/mowgli_exception.h @@ -0,0 +1,37 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_exception.h: Exceptions. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_EXCEPTION_H__ +#define __MOWGLI_EXCEPTION_H__ + +#define mowgli_throw_exception(x) do { mowgli_log("exception %s thrown", #x); return; } while(0) + +#define mowgli_throw_exception_val(x, y) do { mowgli_log("exception %s thrown", #x); return (y); } while(0) + +#define mowgli_throw_exception_fatal(x) \ + do { \ + mowgli_log("exception %s thrown", #x); \ + exit(EXIT_FAILURE); \ + } while (0) + +#endif diff --git a/src/libmowgli/mowgli_formatter.c b/src/libmowgli/mowgli_formatter.c new file mode 100644 index 0000000..b6aa1cc --- /dev/null +++ b/src/libmowgli/mowgli_formatter.c @@ -0,0 +1,119 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_formatter.c: Reusable formatting. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, mowgli_argstack_t *stack) +{ + size_t pos = 0; + char *i = buf; + const char *fiter = fmtstr; + + return_if_fail(buf != NULL); + return_if_fail(fmtstr != NULL); + return_if_fail(descstr != NULL); + + *i = '\0'; + + while (*fiter && pos <= bufstr) + { + int arg; + mowgli_argstack_element_t *e; + + pos = strlen(buf); + + switch(*fiter) + { + case '%': + fiter++; + arg = atoi(fiter); + e = mowgli_node_nth_data(&stack->stack, arg - 1); + + while (isdigit(*fiter)) fiter++; + + if (e == NULL) + { + arg = snprintf(i, bufstr - (i - buf), "(unknown)"); + i += arg; + continue; + } + + switch(e->type) + { + case MOWGLI_ARG_STRING: + arg = snprintf(i, bufstr - (i - buf), "%s", e->data.string); + i += arg; + break; + case MOWGLI_ARG_NUMERIC: + arg = snprintf(i, bufstr - (i - buf), "%d", e->data.numeric); + i += arg; + break; + case MOWGLI_ARG_POINTER: + arg = snprintf(i, bufstr - (i - buf), "%p", e->data.pointer); + i += arg; + break; + case MOWGLI_ARG_BOOLEAN: + arg = snprintf(i, bufstr - (i - buf), "%s", e->data.boolean ? "TRUE" : "FALSE"); + i += arg; + break; + default: + mowgli_throw_exception(mowgli.formatter.unhandled_type_exception); + break; + } + + continue; + break; + default: + *i = *fiter; + } + + i++; + fiter++; + } +} + +void mowgli_formatter_format(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, ...) +{ + va_list va; + mowgli_argstack_t *stack; + + va_start(va, descstr); + stack = mowgli_argstack_create_from_va_list(descstr, va); + va_end(va); + + mowgli_formatter_format_from_argstack(buf, bufstr, fmtstr, descstr, stack); +} + +void mowgli_formatter_print(const char *fmtstr, const char *descstr, ...) +{ + va_list va; + char buf[65535]; + mowgli_argstack_t *stack; + + va_start(va, descstr); + stack = mowgli_argstack_create_from_va_list(descstr, va); + va_end(va); + + mowgli_formatter_format_from_argstack(buf, 65535, fmtstr, descstr, stack); + printf("%s", buf); +} diff --git a/src/libmowgli/mowgli_formatter.h b/src/libmowgli/mowgli_formatter.h new file mode 100644 index 0000000..2631ad6 --- /dev/null +++ b/src/libmowgli/mowgli_formatter.h @@ -0,0 +1,31 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_formatter.h: Reusable formatting. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_FORMATTER_H__ +#define __MOWGLI_FORMATTER_H__ + +extern void mowgli_formatter_format(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, ...); +extern void mowgli_formatter_print(const char *fmtstr, const char *descstr, ...); +extern void mowgli_formatter_format_from_argstack(char *buf, size_t bufstr, const char *fmtstr, const char *descstr, mowgli_argstack_t *stack); + +#endif diff --git a/src/libmowgli/mowgli_global_storage.c b/src/libmowgli/mowgli_global_storage.c new file mode 100644 index 0000000..c74c6cb --- /dev/null +++ b/src/libmowgli/mowgli_global_storage.c @@ -0,0 +1,68 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_global_storage.c: Simple key->value global storage tool. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_patricia_t *mowgli_global_storage_dict = NULL; +static mowgli_spinlock_t *mowgli_global_storage_lock = NULL; + +static void _storage_key_canon(char *key) +{ + +} + +void +mowgli_global_storage_init(void) +{ + mowgli_global_storage_dict = mowgli_patricia_create(_storage_key_canon); + mowgli_global_storage_lock = mowgli_spinlock_create(); +} + +void * +mowgli_global_storage_get(char *name) +{ + void *ret; + + /* name serves as lock token */ + mowgli_spinlock_lock(mowgli_global_storage_lock, name, NULL); + ret = mowgli_patricia_retrieve(mowgli_global_storage_dict, name); + mowgli_spinlock_unlock(mowgli_global_storage_lock, name, NULL); + + return ret; +} + +void +mowgli_global_storage_put(char *name, void *value) +{ + mowgli_spinlock_lock(mowgli_global_storage_lock, NULL, name); + mowgli_patricia_add(mowgli_global_storage_dict, name, value); + mowgli_spinlock_unlock(mowgli_global_storage_lock, NULL, name); +} + +void +mowgli_global_storage_free(char *name) +{ + mowgli_spinlock_lock(mowgli_global_storage_lock, name, name); + mowgli_patricia_delete(mowgli_global_storage_dict, name); + mowgli_spinlock_unlock(mowgli_global_storage_lock, name, name); +} diff --git a/src/libmowgli/mowgli_global_storage.h b/src/libmowgli/mowgli_global_storage.h new file mode 100644 index 0000000..aa60c03 --- /dev/null +++ b/src/libmowgli/mowgli_global_storage.h @@ -0,0 +1,32 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_global_storage.h: Simple key->value global storage tool. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MOWGLI_GLOBAL_STORAGE_H +#define MOWGLI_GLOBAL_STORAGE_H + +extern void mowgli_global_storage_init(void); +extern void *mowgli_global_storage_get(char *name); +extern void mowgli_global_storage_put(char *name, void *value); +extern void mowgli_global_storage_free(char *name); + +#endif diff --git a/src/libmowgli/mowgli_hash.c b/src/libmowgli/mowgli_hash.c new file mode 100644 index 0000000..3f331e4 --- /dev/null +++ b/src/libmowgli/mowgli_hash.c @@ -0,0 +1,66 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_hash.c: FNV-1 hashing implementation. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#define HASHINIT 0x811c9dc5 +#define HASHBITS 16 +#define HASHSIZE (1 << HASHBITS) /* 2^16 = 65536 */ + +int mowgli_fnv_hash_string(const char *p) +{ + static int htoast = 0; + unsigned int hval = HASHINIT; + + if (htoast == 0) + htoast = rand(); + + if (!p) + return (0); + for (; *p != '\0'; ++p) + { + hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); + hval ^= (tolower(*p) ^ htoast); + } + + return ((hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE); +} + +int mowgli_fnv_hash(unsigned int *p) +{ + static int htoast = 0; + unsigned int hval = HASHINIT; + + if (htoast == 0) + htoast = rand(); + + if (!p) + return (0); + for (; *p != '\0'; ++p) + { + hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); + hval ^= (tolower(*p) ^ htoast); + } + + return ((hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE); +} diff --git a/src/libmowgli/mowgli_hash.h b/src/libmowgli/mowgli_hash.h new file mode 100644 index 0000000..e8e04cd --- /dev/null +++ b/src/libmowgli/mowgli_hash.h @@ -0,0 +1,30 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_hash.h: FNV-1 hashing implementation. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_HASH_H__ +#define __MOWGLI_HASH_H__ + +extern int mowgli_fnv_hash_string(const char *data); +extern int mowgli_fnv_hash(unsigned int *data); + +#endif diff --git a/src/libmowgli/mowgli_heap.c b/src/libmowgli/mowgli_heap.c new file mode 100644 index 0000000..532517a --- /dev/null +++ b/src/libmowgli/mowgli_heap.c @@ -0,0 +1,323 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_heap.c: Heap allocation. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2005-2006 Theo Julienne + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Legal note: code devised from claro.base.block module r288 (Pre MPL) + */ + +#include "mowgli.h" + +#ifdef HAVE_MMAP +# include +# if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +# endif +#endif + +/* A block of memory allocated to the allocator */ +struct mowgli_block_ +{ + mowgli_node_t node; + + /* link back to our heap */ + mowgli_heap_t *heap; + + /* pointer to the first item */ + void *data; + + /* singly linked list of free items */ + void *first_free; + + int num_allocated; +}; + +/* A pile of blocks */ +struct mowgli_heap_ +{ + mowgli_node_t node; + + unsigned int elem_size; + unsigned int mowgli_heap_elems; + unsigned int free_elems; + + unsigned int alloc_size; + + unsigned int flags; + + mowgli_list_t blocks; /* list of non-empty blocks */ + + mowgli_allocation_policy_t *allocator; + mowgli_boolean_t use_mmap; + + mowgli_block_t *empty_block; /* a single entirely free block, or NULL */ +}; + +typedef struct mowgli_heap_elem_header_ mowgli_heap_elem_header_t; + +struct mowgli_heap_elem_header_ +{ + union + { + mowgli_block_t *block; /* for allocated elems: block ptr */ + mowgli_heap_elem_header_t *next; /* for free elems: next free */ + } un; +}; + +/* expands a mowgli_heap_t by 1 block */ +static void +mowgli_heap_expand(mowgli_heap_t *bh) +{ + mowgli_block_t *block = NULL; + void *blp = NULL; + mowgli_heap_elem_header_t *node, *prev; + char *offset; + unsigned int a; + + size_t blp_size = sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems); + + return_if_fail(bh->empty_block == NULL); + +#if defined(HAVE_MMAP) && defined(MAP_ANON) + if (bh->use_mmap) + blp = mmap(NULL, sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + else +#endif + { + if (bh->allocator) + blp = bh->allocator->allocate(blp_size); + else + blp = mowgli_alloc(blp_size); + } + + block = (mowgli_block_t *)blp; + + offset = (char*)blp + sizeof(mowgli_block_t); + block->data = offset; + block->heap = bh; + + prev = NULL; + + for (a = 0; a < bh->mowgli_heap_elems; a++) + { + node = (mowgli_heap_elem_header_t *)offset; + node->un.next = prev; + offset += bh->alloc_size; + prev = node; + } + + block->first_free = prev; + + bh->empty_block = block; + bh->free_elems += bh->mowgli_heap_elems; +} + +/* shrinks a mowgli_heap_t by 1 block. */ +static void +mowgli_heap_shrink(mowgli_heap_t *heap, mowgli_block_t *b) +{ + return_if_fail(b != NULL); + + if (b == heap->empty_block) + heap->empty_block = NULL; + else + mowgli_node_delete(&b->node, &heap->blocks); + +#ifdef HAVE_MMAP + if (heap->use_mmap) + munmap(b, sizeof(mowgli_block_t) + (heap->alloc_size * heap->mowgli_heap_elems)); + else +#endif + if (heap->allocator) + heap->allocator->deallocate(b); + else + mowgli_free(b); + + heap->free_elems -= heap->mowgli_heap_elems; +} + +/* creates a new mowgli_heap_t */ +mowgli_heap_t * +mowgli_heap_create_full(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags, + mowgli_allocation_policy_t *allocator) +{ + mowgli_heap_t *bh = mowgli_alloc(sizeof(mowgli_heap_t)); + int numpages, pagesize; + + bh->elem_size = elem_size; + bh->mowgli_heap_elems = mowgli_heap_elems; + /* at least 2, this avoids some silly special cases */ + if (bh->mowgli_heap_elems < 2) + bh->mowgli_heap_elems = 2; + bh->free_elems = 0; + + bh->alloc_size = bh->elem_size + sizeof(mowgli_heap_elem_header_t); + + /* don't waste part of a page */ + if (allocator == NULL) + { +#ifdef HAVE_MMAP + pagesize = getpagesize(); +#else + pagesize = 4096; +#endif + numpages = (sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems) + pagesize - 1) / pagesize; + bh->mowgli_heap_elems = (numpages * pagesize - sizeof(mowgli_block_t)) / bh->alloc_size; + } + + bh->flags = flags; + + bh->allocator = allocator ? allocator : mowgli_allocator_malloc; + +#ifdef HAVE_MMAP + bh->use_mmap = allocator != NULL ? FALSE : TRUE; +#endif + + if (flags & BH_NOW) + mowgli_heap_expand(bh); + + return bh; +} + +mowgli_heap_t * +mowgli_heap_create(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags) +{ + return mowgli_heap_create_full(elem_size, mowgli_heap_elems, flags, NULL); +} + +/* completely frees a mowgli_heap_t and all blocks */ +void +mowgli_heap_destroy(mowgli_heap_t *heap) +{ + mowgli_node_t *n, *tn; + + MOWGLI_LIST_FOREACH_SAFE(n, tn, heap->blocks.head) + { + mowgli_heap_shrink(heap, n->data); + } + if (heap->empty_block) + mowgli_heap_shrink(heap, heap->empty_block); + + /* everything related to heap has gone, time for itself */ + mowgli_free(heap); +} + +/* allocates a new item from a mowgli_heap_t */ +void * +mowgli_heap_alloc(mowgli_heap_t *heap) +{ + mowgli_node_t *n; + mowgli_block_t *b; + mowgli_heap_elem_header_t *h; + + /* no free space? */ + if (heap->free_elems == 0) + { + mowgli_heap_expand(heap); + + return_val_if_fail(heap->free_elems != 0, NULL); + } + + /* try a partially used block before using a fully free block */ + n = heap->blocks.head; + b = n != NULL ? n->data : NULL; + if (b == NULL || b->first_free == NULL) + b = heap->empty_block; + /* due to above check */ + return_val_if_fail(b != NULL, NULL); + + /* pull the first free node from the list */ + h = b->first_free; + return_val_if_fail(h != NULL, NULL); + + /* mark it as used */ + b->first_free = h->un.next; + h->un.block = b; + + /* keep count */ + heap->free_elems--; + b->num_allocated++; + + /* move it between the lists if needed */ + /* note that a block has at least two items in it, so these cases + * cannot both occur in the same allocation */ + if (b->num_allocated == 1) + { + heap->empty_block = NULL; + mowgli_node_add_head(b, &b->node, &heap->blocks); + } + else if (b->first_free == NULL) + { + /* move full blocks to the end of the list */ + mowgli_node_delete(&b->node, &heap->blocks); + mowgli_node_add(b, &b->node, &heap->blocks); + } + +#ifdef HEAP_DEBUG + /* debug */ + mowgli_log("mowgli_heap_alloc(heap = @%p) -> %p", heap, fn->data); +#endif + /* return pointer to it */ + return (char *)h + sizeof(mowgli_heap_elem_header_t); +} + +/* frees an item back to the mowgli_heap_t */ +void +mowgli_heap_free(mowgli_heap_t *heap, void *data) +{ + mowgli_block_t *b; + mowgli_heap_elem_header_t *h; + + h = (mowgli_heap_elem_header_t *)((char *)data - sizeof(mowgli_heap_elem_header_t)); + b = h->un.block; + + return_if_fail(b->heap == heap); + return_if_fail(b->num_allocated > 0); + + /* memset the element before returning it to the heap. */ + memset(data, 0, b->heap->elem_size); + + /* mark it as free */ + h->un.next = b->first_free; + b->first_free = h; + + /* keep count */ + heap->free_elems++; + b->num_allocated--; +#ifdef HEAP_DEBUG + /* debug */ + mowgli_log("mowgli_heap_free(heap = @%p, data = %p)", heap, data); +#endif + /* move it between the lists if needed */ + if (b->num_allocated == 0) + { + if (heap->empty_block != NULL) + mowgli_heap_shrink(heap, heap->empty_block); + mowgli_node_delete(&b->node, &heap->blocks); + heap->empty_block = b; + } + else if (b->num_allocated == heap->mowgli_heap_elems - 1) + { + mowgli_node_delete(&b->node, &heap->blocks); + mowgli_node_add_head(b, &b->node, &heap->blocks); + } +} diff --git a/src/libmowgli/mowgli_heap.h b/src/libmowgli/mowgli_heap.h new file mode 100644 index 0000000..8a38f55 --- /dev/null +++ b/src/libmowgli/mowgli_heap.h @@ -0,0 +1,50 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_heap.h: Heap allocation. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2005-2006 Theo Julienne + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Legal note: code devised from claro.base.block module r288 (Pre MPL) + */ + +#ifndef __MOWGLI_HEAP_H__ +#define __MOWGLI_HEAP_H__ + +typedef struct mowgli_heap_ mowgli_heap_t; +typedef struct mowgli_block_ mowgli_block_t; + +/* Flag for mowgli_heap_create */ +#define BH_DONTCARE 0 + +#define BH_NOW 1 +#define BH_LAZY 0 + +/* Functions for heaps */ +extern mowgli_heap_t *mowgli_heap_create(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags); +extern mowgli_heap_t *mowgli_heap_create_full(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags, + mowgli_allocation_policy_t *allocator); +extern void mowgli_heap_destroy(mowgli_heap_t *heap); + +/* Functions for blocks */ +extern void *mowgli_heap_alloc(mowgli_heap_t *heap); +extern void mowgli_heap_free(mowgli_heap_t *heap, void *data); + +#endif + diff --git a/src/libmowgli/mowgli_hook.c b/src/libmowgli/mowgli_hook.c new file mode 100644 index 0000000..8527a6b --- /dev/null +++ b/src/libmowgli/mowgli_hook.c @@ -0,0 +1,146 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_hook.c: Hooks. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007 Giacomo Lozito + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_patricia_t *mowgli_hooks = NULL; +static mowgli_heap_t *mowgli_hook_item_heap; + +static void _hook_key_canon(char *str) +{ + while (*str) + { + *str = toupper(*str); + str++; + } +} + +void +mowgli_hook_init(void) +{ + mowgli_hooks = mowgli_patricia_create(_hook_key_canon); + mowgli_hook_item_heap = mowgli_heap_create(sizeof(mowgli_hook_item_t), 64, BH_NOW); +} + +static mowgli_hook_t * +mowgli_hook_find(const char *name) +{ + return mowgli_patricia_retrieve(mowgli_hooks, name); +} + +void +mowgli_hook_register(const char *name) +{ + mowgli_hook_t *hook; + + return_if_fail(name != NULL); + return_if_fail((hook = mowgli_hook_find(name)) == NULL); + + hook = mowgli_alloc(sizeof(mowgli_hook_t)); + hook->name = strdup(name); + + mowgli_patricia_add(mowgli_hooks, hook->name, hook); +} + +int +mowgli_hook_associate(const char *name, mowgli_hook_function_t func, void *user_data) +{ + mowgli_hook_t *hook; + mowgli_hook_item_t *hookitem; + + return_val_if_fail(name != NULL, -1); + return_val_if_fail(func != NULL, -1); + + hook = mowgli_hook_find(name); + + if (hook == NULL) + { + mowgli_hook_register(name); + hook = mowgli_hook_find(name); + } + + /* this *cant* happen */ + return_val_if_fail(hook != NULL, -1); + + hookitem = mowgli_heap_alloc(mowgli_hook_item_heap); + hookitem->func = func; + hookitem->user_data = user_data; + + mowgli_node_add(hookitem, &hookitem->node, &hook->items); + + return 0; +} + +int +mowgli_hook_dissociate(const char *name, mowgli_hook_function_t func) +{ + mowgli_hook_t *hook; + mowgli_node_t *n, *tn; + + return_val_if_fail(name != NULL, -1); + return_val_if_fail(func != NULL, -1); + + hook = mowgli_hook_find(name); + + if (hook == NULL) + return -1; + + MOWGLI_LIST_FOREACH_SAFE(n, tn, hook->items.head) + { + mowgli_hook_item_t *hookitem = n->data; + + if (hookitem->func == func) + { + mowgli_node_delete(&hookitem->node, &hook->items); + mowgli_heap_free(mowgli_hook_item_heap, hookitem); + + return 0; + } + } + + return -1; +} + +void +mowgli_hook_call(const char *name, void *hook_data) +{ + mowgli_hook_t *hook; + mowgli_node_t *n; + + return_if_fail(name != NULL); + + hook = mowgli_hook_find(name); + + if (hook == NULL) + return; + + MOWGLI_LIST_FOREACH(n, hook->items.head) + { + mowgli_hook_item_t *hookitem = n->data; + + return_if_fail(hookitem->func != NULL); + + hookitem->func(hook_data, hookitem->user_data); + } +} diff --git a/src/libmowgli/mowgli_hook.h b/src/libmowgli/mowgli_hook.h new file mode 100644 index 0000000..2e79086 --- /dev/null +++ b/src/libmowgli/mowgli_hook.h @@ -0,0 +1,47 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_hook.h: Hooks. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007 Giacomo Lozito + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_HOOK_H__ +#define __MOWGLI_HOOK_H__ + +typedef void (*mowgli_hook_function_t)(void *hook_data, void *user_data); + +typedef struct { + mowgli_hook_function_t func; + void *user_data; + mowgli_node_t node; +} mowgli_hook_item_t; + +typedef struct { + const char *name; + mowgli_list_t items; +} mowgli_hook_t; + +extern void mowgli_hook_init(void); +extern void mowgli_hook_register(const char *name); +extern int mowgli_hook_associate(const char *name, mowgli_hook_function_t func, void * user_data); +extern int mowgli_hook_dissociate(const char *name, mowgli_hook_function_t func); +extern void mowgli_hook_call(const char *name, void * hook_data); + +#endif diff --git a/src/libmowgli/mowgli_index.c b/src/libmowgli/mowgli_index.c new file mode 100644 index 0000000..b96b45e --- /dev/null +++ b/src/libmowgli/mowgli_index.c @@ -0,0 +1,175 @@ +/* + * Copyright 2009-2011 John Lindgren + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +struct mowgli_index_ +{ + void * * data; + int count, size; + int (* compare) (const void * a, const void * b, void * data); + void * compare_data; +}; + +static mowgli_heap_t *index_heap = NULL; + +void mowgli_index_init (void) +{ + index_heap = mowgli_heap_create(sizeof(mowgli_index_t), 32, BH_NOW); +} + +mowgli_index_t * mowgli_index_create (void) +{ + mowgli_index_t * index = mowgli_heap_alloc(index_heap); + + index->data = NULL; + index->count = 0; + index->size = 0; + index->compare = NULL; + index->compare_data = NULL; + + return index; +} + +void mowgli_index_destroy (mowgli_index_t * index) +{ + mowgli_free (index->data); + mowgli_heap_free (index_heap, index); +} + +int mowgli_index_count (mowgli_index_t * index) +{ + return index->count; +} + +void mowgli_index_allocate (mowgli_index_t * index, int size) +{ + if (size <= index->size) + return; + + if (! index->size) + index->size = 64; + + while (size > index->size) + index->size <<= 1; + + index->data = realloc (index->data, sizeof (void *) * index->size); +} + +void mowgli_index_set (mowgli_index_t * index, int at, void * value) +{ + index->data[at] = value; +} + +void * mowgli_index_get (mowgli_index_t * index, int at) +{ + return index->data[at]; +} + +static void make_room (mowgli_index_t * index, int at, int count) +{ + mowgli_index_allocate (index, index->count + count); + + if (at < index->count) + memmove (index->data + at + count, index->data + at, sizeof (void *) * + (index->count - at)); + + index->count += count; +} + +void mowgli_index_insert (mowgli_index_t * index, int at, void * value) +{ + make_room (index, at, 1); + index->data[at] = value; +} + +void mowgli_index_append (mowgli_index_t * index, void * value) +{ + mowgli_index_insert (index, index->count, value); +} + +void mowgli_index_copy_set (mowgli_index_t * source, int from, mowgli_index_t * target, + int to, int count) +{ + memcpy (target->data + to, source->data + from, sizeof (void *) * count); +} + +void mowgli_index_copy_insert (mowgli_index_t * source, int from, mowgli_index_t * target, + int to, int count) +{ + make_room (target, to, count); + memcpy (target->data + to, source->data + from, sizeof (void *) * count); +} + +void mowgli_index_copy_append (mowgli_index_t * source, int from, mowgli_index_t * target, + int count) +{ + mowgli_index_copy_insert (source, from, target, target->count, count); +} + +void mowgli_index_merge_insert (mowgli_index_t * first, int at, mowgli_index_t * second) +{ + mowgli_index_copy_insert (second, 0, first, at, second->count); +} + +void mowgli_index_merge_append (mowgli_index_t * first, mowgli_index_t * second) +{ + mowgli_index_copy_insert (second, 0, first, first->count, second->count); +} + +void mowgli_index_move (mowgli_index_t * index, int from, int to, int count) +{ + memmove (index->data + to, index->data + from, sizeof (void *) * count); +} + +void mowgli_index_delete (mowgli_index_t * index, int at, int count) +{ + index->count -= count; + memmove (index->data + at, index->data + at + count, sizeof (void *) * + (index->count - at)); +} + +void mowgli_index_sort (mowgli_index_t * index, int (* compare) (const void *, const void *)) +{ + qsort(index->data, index->count, sizeof (void *), compare); +} + +#ifdef NOTYET +static int mowgli_index_compare_with_data (const void * a, const void * b, void * _index) +{ + mowgli_index_t * index = _index; + + return index->compare (* (const void * *) a, * (const void * *) b, + index->compare_data); +} + +void mowgli_index_sort_with_data (mowgli_index_t * index, int (* compare) + (const void * a, const void * b, void * data), void * data) +{ + index->compare = compare; + index->compare_data = data; + g_qsort_with_data (index->data, index->count, sizeof (void *), + mowgli_index_compare_with_data, index); + index->compare = NULL; + index->compare_data = NULL; +} +#endif diff --git a/src/libmowgli/mowgli_index.h b/src/libmowgli/mowgli_index.h new file mode 100644 index 0000000..85e9e72 --- /dev/null +++ b/src/libmowgli/mowgli_index.h @@ -0,0 +1,51 @@ +/* + * Copyright 2009-2011 John Lindgren + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_INDEX_H__ +#define __MOWGLI_INDEX_H__ + +struct mowgli_index_; + +typedef struct mowgli_index_ mowgli_index_t; + +mowgli_index_t * mowgli_index_create (void); +void mowgli_index_destroy (mowgli_index_t * index); +int mowgli_index_count (mowgli_index_t * index); +void mowgli_index_allocate (mowgli_index_t * index, int size); +void mowgli_index_set (mowgli_index_t * index, int at, void * value); +void * mowgli_index_get (mowgli_index_t * index, int at); +void mowgli_index_insert (mowgli_index_t * index, int at, void * value); +void mowgli_index_append (mowgli_index_t * index, void * value); +void mowgli_index_copy_set (mowgli_index_t * source, int from, mowgli_index_t * target, + int to, int count); +void mowgli_index_copy_insert (mowgli_index_t * source, int from, mowgli_index_t * target, + int to, int count); +void mowgli_index_copy_append (mowgli_index_t * source, int from, mowgli_index_t * target, + int count); +void mowgli_index_merge_insert (mowgli_index_t * first, int at, mowgli_index_t * second); +void mowgli_index_merge_append (mowgli_index_t * first, mowgli_index_t * second); +void mowgli_index_move (mowgli_index_t * index, int from, int to, int count); +void mowgli_index_delete (mowgli_index_t * index, int at, int count); +void mowgli_index_sort (mowgli_index_t * index, int (* compare) (const void * a, + const void * b)); +void mowgli_index_sort_with_data (mowgli_index_t * index, int (* compare) + (const void * a, const void * b, void * data), void * data); + +#endif diff --git a/src/libmowgli/mowgli_init.c b/src/libmowgli/mowgli_init.c new file mode 100644 index 0000000..5b15aa0 --- /dev/null +++ b/src/libmowgli/mowgli_init.c @@ -0,0 +1,49 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_init.c: Initialization of libmowgli. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void mowgli_init(void) +{ + static int mowgli_initted_ = 0; + + if (mowgli_initted_) + return; + + /* initial bootstrap */ + mowgli_node_init(); + mowgli_queue_init(); + mowgli_argstack_init(); + mowgli_bitvector_init(); + mowgli_global_storage_init(); + mowgli_hook_init(); + mowgli_random_init(); + mowgli_allocation_policy_init(); + mowgli_allocator_init(); + + /* now that we're bootstrapped, we can use a more optimised allocator + if one is available. */ + mowgli_allocator_set_policy(mowgli_allocator_malloc); + + mowgli_initted_++; +} diff --git a/src/libmowgli/mowgli_init.h b/src/libmowgli/mowgli_init.h new file mode 100644 index 0000000..3ebc7e3 --- /dev/null +++ b/src/libmowgli/mowgli_init.h @@ -0,0 +1,29 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_init.c: Initialization of libmowgli. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_INIT_H__ +#define __MOWGLI_INIT_H__ + +extern void mowgli_init(void); + +#endif diff --git a/src/libmowgli/mowgli_ioevent.c b/src/libmowgli/mowgli_ioevent.c new file mode 100644 index 0000000..ed08cb9 --- /dev/null +++ b/src/libmowgli/mowgli_ioevent.c @@ -0,0 +1,195 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_ioevent.c: Portable I/O event layer. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_EPOLL_CTL +# include +#endif + +#ifdef HAVE_PORT_CREATE +# include +#endif + +mowgli_ioevent_handle_t *mowgli_ioevent_create(void) +{ + mowgli_ioevent_handle_t *self = mowgli_alloc(sizeof(mowgli_ioevent_handle_t)); + +#ifdef HAVE_EPOLL_CTL + self->impldata = epoll_create(FD_SETSIZE); +#endif + +#ifdef HAVE_PORT_CREATE + self->impldata = port_create(); +#endif + + return self; +} + +void mowgli_ioevent_destroy(mowgli_ioevent_handle_t *self) +{ + return_if_fail(self != NULL); + +#if defined(HAVE_EPOLL_CTL) || defined(HAVE_PORT_CREATE) + close(self->impldata); +#endif + + mowgli_free(self); +} + +int mowgli_ioevent_get(mowgli_ioevent_handle_t *self, mowgli_ioevent_t *buf, size_t bufsize, unsigned int delay) +{ +#if defined HAVE_EPOLL_CTL || defined HAVE_PORT_CREATE + int ret, iter; +#else + int ret = -1; +#endif + +#ifdef HAVE_EPOLL_CTL + struct epoll_event events[bufsize]; + + ret = epoll_wait(self->impldata, events, bufsize, delay); + + if (ret == -1) + return ret; + + for (iter = 0; iter < ret; iter++) + { + buf[iter].ev_status = 0; + buf[iter].ev_object = events[iter].data.fd; + buf[iter].ev_opaque = events[iter].data.ptr; + buf[iter].ev_source = MOWGLI_SOURCE_FD; + + if (events[iter].events & EPOLLIN) + buf[iter].ev_status |= MOWGLI_POLLRDNORM; + + if (events[iter].events & EPOLLOUT) + buf[iter].ev_status |= MOWGLI_POLLWRNORM; + + if (events[iter].events & EPOLLHUP) + buf[iter].ev_status = MOWGLI_POLLHUP; + + if (events[iter].events & EPOLLERR) + buf[iter].ev_status = MOWGLI_POLLERR; + } +#endif + +#ifdef HAVE_PORT_CREATE + port_event_t events[bufsize]; + unsigned int nget = 1; + struct timespec poll_time; + + poll_time.tv_sec = delay / 1000; + poll_time.tv_nsec = (delay % 1000) * 1000000; + + ret = port_getn(self->impldata, events, bufsize, &nget, &poll_time); + + if (ret == -1) + return ret; + + for (iter = 0; iter < nget; iter++) + { + buf[iter].ev_status = 0; + buf[iter].ev_object = events[iter].portev_object; + buf[iter].ev_opaque = events[iter].portev_user; + buf[iter].ev_source = MOWGLI_SOURCE_FD; + + if (events[iter].portev_events & POLLRDNORM) + buf[iter].ev_status |= MOWGLI_POLLRDNORM; + + if (events[iter].portev_events & POLLWRNORM) + buf[iter].ev_status |= MOWGLI_POLLWRNORM; + + if (events[iter].portev_events & POLLHUP) + buf[iter].ev_status = MOWGLI_POLLHUP; + + if (events[iter].portev_events & POLLERR) + buf[iter].ev_status = MOWGLI_POLLERR; + } + + ret = nget; +#endif + + return ret; +} + +void mowgli_ioevent_associate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object, unsigned int flags, void *opaque) +{ +#if defined HAVE_EPOLL_CTL || defined HAVE_PORT_CREATE + int events = 0; +#endif + + if (source != MOWGLI_SOURCE_FD) + return; + +#ifdef HAVE_EPOLL_CTL + { + struct epoll_event ep_event = {}; + events = EPOLLONESHOT; + + if (flags & MOWGLI_POLLRDNORM) + events |= EPOLLIN; + + if (flags & MOWGLI_POLLWRNORM) + events |= EPOLLOUT; + + ep_event.events = events; + ep_event.data.ptr = opaque; + + epoll_ctl(self->impldata, EPOLL_CTL_ADD, object, &ep_event); + } +#endif + +#ifdef HAVE_PORT_CREATE +#ifdef POLLRDNORM + if (flags & MOWGLI_POLLRDNORM) + events |= POLLRDNORM; +#endif + +#ifdef EPOLLWRNORM + if (flags & MOWGLI_POLLWRNORM) + events |= EPOLLWRNORM; +#endif + + port_associate(self->impldata, PORT_SOURCE_FD, object, events, opaque); +#endif +} + +void mowgli_ioevent_dissociate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object) +{ + if (source != MOWGLI_SOURCE_FD) + return; + +#ifdef HAVE_EPOLL_CTL + { + struct epoll_event ep_event = {}; + + epoll_ctl(self->impldata, EPOLL_CTL_DEL, object, &ep_event); + } +#endif + +#ifdef HAVE_PORT_CREATE + port_dissociate(self->impldata, PORT_SOURCE_FD, object); +#endif +} + diff --git a/src/libmowgli/mowgli_ioevent.h b/src/libmowgli/mowgli_ioevent.h new file mode 100644 index 0000000..17007b6 --- /dev/null +++ b/src/libmowgli/mowgli_ioevent.h @@ -0,0 +1,55 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_ioevent.h: Portable I/O event layer. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_IOEVENT_H__ +#define __MOWGLI_IOEVENT_H__ + +typedef struct { + int impldata; /* implementation-specific data: this is almost always an FD */ +} mowgli_ioevent_handle_t; + +typedef enum { + MOWGLI_SOURCE_FD = 1 +} mowgli_ioevent_source_t; + +typedef struct { + mowgli_ioevent_source_t ev_source; + unsigned int ev_status; + int ev_object; + void *ev_opaque; +} mowgli_ioevent_t; + +#define MOWGLI_POLLRDNORM 0x01 +#define MOWGLI_POLLWRNORM 0x02 +#define MOWGLI_POLLHUP 0x04 +#define MOWGLI_POLLERR 0x08 + +extern mowgli_ioevent_handle_t *mowgli_ioevent_create(void) MOWGLI_DEPRECATED; +extern void mowgli_ioevent_destroy(mowgli_ioevent_handle_t *self) MOWGLI_DEPRECATED; + +extern int mowgli_ioevent_get(mowgli_ioevent_handle_t *self, mowgli_ioevent_t *buf, size_t bufsize, unsigned int delay) MOWGLI_DEPRECATED; + +extern void mowgli_ioevent_associate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object, unsigned int flags, void *opaque) MOWGLI_DEPRECATED; +extern void mowgli_ioevent_dissociate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object) MOWGLI_DEPRECATED; + +#endif diff --git a/src/libmowgli/mowgli_iterator.h b/src/libmowgli/mowgli_iterator.h new file mode 100644 index 0000000..f99412b --- /dev/null +++ b/src/libmowgli/mowgli_iterator.h @@ -0,0 +1,38 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_iterator.h: Iterators. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ITERATOR_H__ +#define __MOWGLI_ITERATOR_H__ + +typedef struct _mowgli_iterator { + struct _mowgli_iterator *prev, *next; + void *data; +} mowgli_iterator_t; + +/* The following are macros which can be used with iterators. */ +#define MOWGLI_ITER_FOREACH(n, head) for (n = (head); n; n = n->next) +#define MOWGLI_ITER_FOREACH_NEXT(n, head) for (n = (head); n->next; n = n->next) +#define MOWGLI_ITER_FOREACH_PREV(n, tail) for (n = (tail); n; n = n->prev) +#define MOWGLI_ITER_FOREACH_SAFE(n, tn, head) for (n = (head), tn = n ? n->next : NULL; n != NULL; n = tn, tn = n ? n->next : NULL) + +#endif diff --git a/src/libmowgli/mowgli_list.c b/src/libmowgli/mowgli_list.c new file mode 100644 index 0000000..0e33103 --- /dev/null +++ b/src/libmowgli/mowgli_list.c @@ -0,0 +1,386 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_list.c: Linked lists. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *mowgli_node_heap; +static mowgli_heap_t *mowgli_list_heap; + +void mowgli_node_init(void) +{ + mowgli_node_heap = mowgli_heap_create(sizeof(mowgli_node_t), 1024, BH_NOW); + mowgli_list_heap = mowgli_heap_create(sizeof(mowgli_list_t), 64, BH_NOW); + + if (mowgli_node_heap == NULL || mowgli_list_heap == NULL) + { + mowgli_log("heap allocator failure."); + abort(); + } +} + +/* creates a new node */ +mowgli_node_t *mowgli_node_create(void) +{ + mowgli_node_t *n; + + /* allocate it */ + n = mowgli_heap_alloc(mowgli_node_heap); + + /* initialize */ + n->next = n->prev = n->data = NULL; + + /* return a pointer to the new node */ + return n; +} + +/* frees a node */ +void mowgli_node_free(mowgli_node_t *n) +{ + return_if_fail(n != NULL); + + /* free it */ + mowgli_heap_free(mowgli_node_heap, n); +} + +/* adds a node to the end of a list */ +void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l) +{ + mowgli_node_t *tn; + + return_if_fail(n != NULL); + return_if_fail(l != NULL); + + n->next = n->prev = NULL; + n->data = data; + + /* first node? */ + if (l->head == NULL) + { + l->head = n; + l->tail = n; + l->count++; + return; + } + + /* use the cached tail. */ + tn = l->tail; + + /* set the our `prev' to the last node */ + n->prev = tn; + + /* set the last node's `next' to us */ + n->prev->next = n; + + /* set the list's `tail' to us */ + l->tail = n; + + /* up the count */ + l->count++; +} + +/* adds a node to the head of a list */ +void mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l) +{ + mowgli_node_t *tn; + + return_if_fail(n != NULL); + return_if_fail(l != NULL); + + n->next = n->prev = NULL; + n->data = data; + + /* first node? */ + if (!l->head) + { + l->head = n; + l->tail = n; + l->count++; + return; + } + + tn = l->head; + n->next = tn; + tn->prev = n; + l->head = n; + l->count++; +} + +/* adds a node to a list before another node, or to the end */ +void mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before) +{ + return_if_fail(n != NULL); + return_if_fail(l != NULL); + + if (before == NULL) + mowgli_node_add(data, n, l); + else if (before == l->head) + mowgli_node_add_head(data, n, l); + else + { + n->data = data; + n->prev = before->prev; + n->next = before; + before->prev = n; + n->prev->next = n; + l->count++; + } +} + +/* adds a node to a list after another node, or to the end */ +void mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before) +{ + return_if_fail(n != NULL); + return_if_fail(l != NULL); + + if (before == NULL || before->next == NULL) + mowgli_node_add(data, n, l); + else + { + n->data = data; + n->prev = before; + n->next = before->next; + before->next = n; + n->next->prev = n; + l->count++; + } +} + +/* retrieves a node at `position` position. */ +mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, int pos) +{ + int iter; + mowgli_node_t *n; + + return_val_if_fail(l != NULL, NULL); + + if (pos < 0) + return NULL; + + /* locate the proper position. */ + if (pos < MOWGLI_LIST_LENGTH(l) / 2) + for (iter = 0, n = l->head; iter != pos && n != NULL; iter++, n = n->next); + else + for (iter = MOWGLI_LIST_LENGTH(l) - 1, n = l->tail; + iter != pos && n != NULL; iter--, n = n->prev); + + return n; +} + +/* returns the data from node at `position` position, or NULL. */ +void *mowgli_node_nth_data(mowgli_list_t *l, int pos) +{ + mowgli_node_t *n; + + return_val_if_fail(l != NULL, NULL); + + n = mowgli_node_nth(l, pos); + + if (n == NULL) + return NULL; + + return n->data; +} + +/* inserts a node at `position` position. */ +void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, int pos) +{ + mowgli_node_t *tn; + + return_if_fail(n != NULL); + return_if_fail(l != NULL); + + /* locate the proper position. */ + tn = mowgli_node_nth(l, pos); + + mowgli_node_add_before(data, n, l, tn); +} + +/* retrieves the index position of a node in a list. */ +int mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) +{ + int iter; + mowgli_node_t *tn; + + return_val_if_fail(n != NULL, -1); + return_val_if_fail(l != NULL, -1); + + /* locate the proper position. */ + for (iter = 0, tn = l->head; tn != n && tn != NULL; iter++, tn = tn->next); + + return iter < MOWGLI_LIST_LENGTH(l) ? iter : -1; +} + +/* deletes a link between a node and a list. */ +void mowgli_node_delete(mowgli_node_t *n, mowgli_list_t *l) +{ + return_if_fail(n != NULL); + return_if_fail(l != NULL); + + /* are we the head? */ + if (!n->prev) + l->head = n->next; + else + n->prev->next = n->next; + + /* are we the tail? */ + if (!n->next) + l->tail = n->prev; + else + n->next->prev = n->prev; + + /* down the count */ + l->count--; +} + +/* finds a node by `data' */ +mowgli_node_t *mowgli_node_find(void *data, mowgli_list_t *l) +{ + mowgli_node_t *n; + + return_val_if_fail(l != NULL, NULL); + + MOWGLI_LIST_FOREACH(n, l->head) if (n->data == data) + return n; + + return NULL; +} + +/* moves a node from one list to another. */ +void mowgli_node_move(mowgli_node_t *m, mowgli_list_t *oldlist, mowgli_list_t *newlist) +{ + return_if_fail(m != NULL); + return_if_fail(oldlist != NULL); + return_if_fail(newlist != NULL); + + /* Assumption: If m->next == NULL, then list->tail == m + * and: If m->prev == NULL, then list->head == m + */ + if (m->next != NULL) + m->next->prev = m->prev; + else + oldlist->tail = m->prev; + + if (m->prev != NULL) + m->prev->next = m->next; + else + oldlist->head = m->next; + + m->prev = NULL; + m->next = newlist->head; + + if (newlist->head != NULL) + newlist->head->prev = m; + else if (newlist->tail == NULL) + newlist->tail = m; + + newlist->head = m; + + oldlist->count--; + newlist->count++; +} + +/* creates a new list. */ +mowgli_list_t *mowgli_list_create(void) +{ + mowgli_list_t *out = mowgli_heap_alloc(mowgli_list_heap); + + return out; +} + +/* frees a created list. */ +void mowgli_list_free(mowgli_list_t *l) +{ + mowgli_heap_free(mowgli_list_heap, l); +} + +/* concatenates two lists together. */ +void mowgli_list_concat(mowgli_list_t *l, mowgli_list_t *l2) +{ + return_if_fail(l != NULL); + return_if_fail(l2 != NULL); + + l->tail->next = l2->head; + l->tail->next->prev = l->tail; + l->tail = l2->tail; + l->count += l2->count; + + /* clear out l2 as it is no longer needed. */ + l2->head = l2->tail = NULL; + l2->count = 0; +} + +/* reverse a list -- O(n)! */ +void mowgli_list_reverse(mowgli_list_t *l) +{ + mowgli_node_t *n, *tn; + + return_if_fail(l != NULL); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, l->head) + { + mowgli_node_t *tn2 = n->next; + n->next = n->prev; + n->prev = tn2; + } + + tn = l->head; + l->head = l->tail; + l->tail = tn; +} + +/* sorts a list -- O(n ^ 2) most likely, i don't want to think about it. --nenolod */ +void mowgli_list_sort(mowgli_list_t *l, mowgli_list_comparator_t comp, void *opaque) +{ + mowgli_node_t *n, *tn, *n2, *tn2; + + return_if_fail(l != NULL); + return_if_fail(comp != NULL); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, l->head) + { + MOWGLI_LIST_FOREACH_SAFE(n2, tn2, l->head) + { + int result; + int i, i2; + + if (n == n2) + continue; + + i = mowgli_node_index(n, l); + i2 = mowgli_node_index(n2, l); + + if ((result = comp(n, n2, opaque)) == 0) + continue; + else if (result < 0 && i > i2) + { + mowgli_node_delete(n, l); + mowgli_node_add_before(n->data, n, l, n2); + } + else if (result > 0 && i < i2) + { + mowgli_node_delete(n, l); + mowgli_node_add_after(n->data, n, l, n2); + } + } + } +} diff --git a/src/libmowgli/mowgli_list.h b/src/libmowgli/mowgli_list.h new file mode 100644 index 0000000..2699686 --- /dev/null +++ b/src/libmowgli/mowgli_list.h @@ -0,0 +1,76 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_list.c: Linked lists. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_LIST_H__ +#define __MOWGLI_LIST_H__ + +/* macros for linked lists */ +#define MOWGLI_LIST_FOREACH(n, head) for (n = (head); n; n = n->next) +#define MOWGLI_LIST_FOREACH_NEXT(n, head) for (n = (head); n->next; n = n->next) +#define MOWGLI_LIST_FOREACH_PREV(n, tail) for (n = (tail); n; n = n->prev) + +#define MOWGLI_LIST_LENGTH(list) (list)->count + +#define MOWGLI_LIST_FOREACH_SAFE(n, tn, head) for (n = (head), tn = n ? n->next : NULL; n != NULL; n = tn, tn = n ? n->next : NULL) + +/* list node struct */ +typedef struct mowgli_node_ mowgli_node_t; +typedef struct mowgli_list_ mowgli_list_t; + +struct mowgli_node_ +{ + struct mowgli_node_ *next, *prev; + void *data; /* pointer to real structure */ +}; + +/* node list struct */ +struct mowgli_list_ +{ + mowgli_node_t *head, *tail; + size_t count; /* how many entries in the list */ +}; + +extern void mowgli_node_init(void); +extern mowgli_node_t *mowgli_node_create(void); +extern void mowgli_node_free(mowgli_node_t *n); +extern void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l); +extern void mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l); +extern void mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before); +extern void mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before); +extern void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, int position); +extern int mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l); +extern void mowgli_node_delete(mowgli_node_t *n, mowgli_list_t *l); +extern mowgli_node_t *mowgli_node_find(void *data, mowgli_list_t *l); +extern void mowgli_node_move(mowgli_node_t *m, mowgli_list_t *oldlist, mowgli_list_t *newlist); +extern mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, int pos); +extern void *mowgli_node_nth_data(mowgli_list_t *l, int pos); + +typedef int (*mowgli_list_comparator_t)(mowgli_node_t *n, mowgli_node_t *n2, void *opaque); + +extern mowgli_list_t *mowgli_list_create(void); +extern void mowgli_list_free(mowgli_list_t *l); +extern void mowgli_list_concat(mowgli_list_t *l, mowgli_list_t *l2); +extern void mowgli_list_reverse(mowgli_list_t *l); +extern void mowgli_list_sort(mowgli_list_t *l, mowgli_list_comparator_t comp, void *opaque); + +#endif diff --git a/src/libmowgli/mowgli_logger.c b/src/libmowgli/mowgli_logger.c new file mode 100644 index 0000000..e3c13ea --- /dev/null +++ b/src/libmowgli/mowgli_logger.c @@ -0,0 +1,62 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_logger.c: Event and debugging message logging. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void mowgli_log_cb_default(const char *buf) +{ + fprintf(stderr, "%s\n", buf); +} + +static mowgli_log_cb_t mowgli_log_cb = mowgli_log_cb_default; + +void mowgli_log_real(const char *file, int line, const char *func, const char *fmt, ...) +{ + char buf[65535]; + char snbuf[65535]; + va_list va; + + va_start(va, fmt); + vsnprintf(snbuf, 65535, fmt, va); + va_end(va); + + snprintf(buf, 65535, "(%s:%d) [%s]: %s", file, line, func, snbuf); + + mowgli_log_cb(buf); +} + +void mowgli_log_set_cb(mowgli_log_cb_t callback) +{ + return_if_fail(callback != NULL); + + mowgli_log_cb = callback; +} + +void mowgli_soft_assert_log(const char *asrt, const char *file, int line, const char *function) +{ + char buf[65535]; + + snprintf(buf, sizeof buf, "(%s:%d) [%s]: critical: Assertion '%s' failed.", file, line, function, asrt); + + mowgli_log_cb(buf); +} diff --git a/src/libmowgli/mowgli_logger.h b/src/libmowgli/mowgli_logger.h new file mode 100644 index 0000000..730383a --- /dev/null +++ b/src/libmowgli/mowgli_logger.h @@ -0,0 +1,45 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_logger.h: Event and debugging message logging. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_LOGGER_H__ +#define __MOWGLI_LOGGER_H__ + +typedef void (*mowgli_log_cb_t)(const char *); + +#ifdef __GNUC__ +# define mowgli_log(...) mowgli_log_real(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__) +#elif defined _MSC_VER +# if _MSC_VER <= 1200 + static __inline void mowgli_log(char *fmt, ...) { /* TODO/UNSUPPORTED */ } +# else +# define mowgli_log(...) mowgli_log_real(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +# endif +#else +# define mowgli_log(...) mowgli_log_real(__FILE__, __LINE__, __func__, __VA_ARGS__) +#endif + +extern void mowgli_log_real(const char *file, int line, const char *func, const char *buf, ...); + +extern void mowgli_log_set_cb(mowgli_log_cb_t callback); + +#endif diff --git a/src/libmowgli/mowgli_mempool.c b/src/libmowgli/mowgli_mempool.c new file mode 100644 index 0000000..c41436c --- /dev/null +++ b/src/libmowgli/mowgli_mempool.c @@ -0,0 +1,199 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_mempool.c: Memory pooling. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* visibility of this object is not available to the outside */ +struct mowgli_mempool_t_ { + mowgli_list_t stack; + mowgli_destructor_t destructor; +#ifdef NOTYET + mowgli_mutex_t *mutex; +#endif +}; + +typedef struct { + void *addr; + int refcount; + mowgli_node_t node; +} mowgli_mempool_elem_t; + +mowgli_mempool_t *mowgli_mempool_with_custom_destructor(mowgli_destructor_t destructor) +{ + mowgli_mempool_t *pool; + + pool = mowgli_alloc(sizeof(mowgli_mempool_t)); + pool->destructor = destructor; +#ifdef NOTYET + pool->mutex = mowgli_mutex_create(); +#endif + return pool; +} + +mowgli_mempool_t *mowgli_mempool_create(void) +{ + return mowgli_mempool_with_custom_destructor(mowgli_free); +} + +void *mowgli_mempool_add(mowgli_mempool_t * pool, void * ptr) +{ + mowgli_mempool_elem_t *e = mowgli_alloc(sizeof(mowgli_mempool_elem_t)); + + e->addr = ptr; + e->refcount = 1; + +#ifdef NOTYET + mowgli_mutex_lock(pool->mutex); +#endif + mowgli_node_add(e, &e->node, &pool->stack); +#ifdef NOTYET + mowgli_mutex_unlock(pool->mutex); +#endif + return ptr; +} + +void * +mowgli_mempool_allocate(mowgli_mempool_t * pool, size_t sz) +{ + void * addr; + +#ifdef NOTYET + mowgli_mutex_lock(pool->mutex); +#endif + addr = mowgli_alloc(sz); + mowgli_node_add(addr, mowgli_node_create(), &pool->stack); +#ifdef NOTYET + mowgli_mutex_unlock(pool->mutex); +#endif + return addr; +} + +void +mowgli_mempool_sustain(mowgli_mempool_t * pool, void * addr) +{ + mowgli_node_t *n, *tn; + mowgli_mempool_elem_t *e; + +#ifdef NOTYET + mowgli_mutex_lock(pool->mutex); +#endif + + MOWGLI_LIST_FOREACH_SAFE(n, tn, pool->stack.head) + { + e = (mowgli_mempool_elem_t *) n->data; + + if (e->addr == addr) + ++e->refcount; + } + +#ifdef NOTYET + mowgli_mutex_unlock(pool->mutex); +#endif +} + +void +mowgli_mempool_release(mowgli_mempool_t * pool, void * addr) +{ + mowgli_node_t *n, *tn; + mowgli_mempool_elem_t *e; + +#ifdef NOTYET + mowgli_mutex_lock(pool->mutex); +#endif + + MOWGLI_LIST_FOREACH_SAFE(n, tn, pool->stack.head) + { + e = (mowgli_mempool_elem_t *) n->data; + + if (e->addr == addr && --e->refcount == 0) + { + mowgli_node_delete(n, &pool->stack); + pool->destructor(addr); + mowgli_free(e); + } + } + +#ifdef NOTYET + mowgli_mutex_unlock(pool->mutex); +#endif +} + +static void +mowgli_mempool_cleanup_nolock(mowgli_mempool_t * pool) +{ + mowgli_node_t *n, *tn; + + MOWGLI_LIST_FOREACH_SAFE(n, tn, pool->stack.head) + { + mowgli_mempool_elem_t *e = (mowgli_mempool_elem_t *) n->data; + + /* don't care about refcounting here. we're killing the entire pool. */ + mowgli_log("mowgli_mempool_t<%p> element at %p was not released until cleanup (refcount: %d)", pool, e->addr, e->refcount); + pool->destructor(e->addr); + mowgli_free(e); + + mowgli_node_delete(n, &pool->stack); + } +} + +void +mowgli_mempool_cleanup(mowgli_mempool_t * pool) +{ +#ifdef NOTYET + mowgli_mutex_lock(pool->mutex); +#endif + mowgli_mempool_cleanup_nolock(pool); +#ifdef NOTYET + mowgli_mutex_unlock(pool->mutex); +#endif +} + +void +mowgli_mempool_destroy(mowgli_mempool_t * pool) +{ +#ifdef NOTYET + mowgli_mutex_lock(pool->mutex); +#endif + + mowgli_mempool_cleanup_nolock(pool); + +#ifdef NOTYET + mowgli_mutex_unlock(pool->mutex); + + mowgli_mutex_free(pool->mutex); +#endif + + mowgli_free(pool); +} + +char * +mowgli_mempool_strdup(mowgli_mempool_t * pool, char * src) +{ + char *out; + size_t sz = strlen(src) + 1; + + out = mowgli_mempool_allocate(pool, sz); + mowgli_strlcpy(out, src, sz); + + return out; +} diff --git a/src/libmowgli/mowgli_mempool.h b/src/libmowgli/mowgli_mempool.h new file mode 100644 index 0000000..14d5911 --- /dev/null +++ b/src/libmowgli/mowgli_mempool.h @@ -0,0 +1,45 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_mempool.h: Memory pooling. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_MEMPOOL_H__ +#define __MOWGLI_MEMPOOL_H__ + +typedef struct mowgli_mempool_t_ mowgli_mempool_t; + +mowgli_mempool_t * mowgli_mempool_create(void); +mowgli_mempool_t * mowgli_mempool_with_custom_destructor(mowgli_destructor_t destructor); + +void * mowgli_mempool_add(mowgli_mempool_t * pool, void * ptr); +void * mowgli_mempool_allocate(mowgli_mempool_t * pool, size_t sz); +void mowgli_mempool_release(mowgli_mempool_t * pool, void * addr); + +void mowgli_mempool_cleanup(mowgli_mempool_t * pool); + +void mowgli_mempool_destroy(mowgli_mempool_t * pool); + +char * mowgli_mempool_strdup(mowgli_mempool_t * pool, char * src); + +#define mowgli_mempool_alloc_object(pool, obj) \ + mowgli_mempool_allocate(pool, sizeof(obj)) + +#endif diff --git a/src/libmowgli/mowgli_module.h b/src/libmowgli/mowgli_module.h new file mode 100644 index 0000000..1ef89b4 --- /dev/null +++ b/src/libmowgli/mowgli_module.h @@ -0,0 +1,33 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_module.h: Loadable modules. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_MODULE_H__ +#define __MOWGLI_MODULE_H__ + +typedef void * mowgli_module_t; + +extern mowgli_module_t mowgli_module_open(const char *path); +extern void * mowgli_module_symbol(mowgli_module_t module, const char *symbol); +extern void mowgli_module_close(mowgli_module_t module); + +#endif diff --git a/src/libmowgli/mowgli_module_posix.c b/src/libmowgli/mowgli_module_posix.c new file mode 100644 index 0000000..dd4a25c --- /dev/null +++ b/src/libmowgli/mowgli_module_posix.c @@ -0,0 +1,69 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_module.c: Loadable modules for POSIX systems. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#include + +#ifdef __OpenBSD__ +# define RTLD_NOW RTLD_LAZY +#endif + +#ifndef RTLD_LOCAL +#define RTLD_LOCAL 0 +#endif + +mowgli_module_t mowgli_module_open(const char *path) +{ + void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); + + /* make sure we have something. make this an assertion so that + * there is feedback if something happens. (poor programming practice). + */ + return_val_if_fail(handle != NULL, NULL); + + return handle; +} + +void * mowgli_module_symbol(mowgli_module_t module, const char *symbol) +{ + void *handle; + + return_val_if_fail(module != NULL, NULL); + + handle = dlsym(module, symbol); + + /* make sure we have something. make this an assertion so that + * there is feedback if something happens. (poor programming practice). + */ + return_val_if_fail(handle != NULL, NULL); + + return handle; +} + +void mowgli_module_close(mowgli_module_t module) +{ + return_if_fail(module != NULL); + + dlclose(module); +} diff --git a/src/libmowgli/mowgli_module_win32.c b/src/libmowgli/mowgli_module_win32.c new file mode 100644 index 0000000..e4b7428 --- /dev/null +++ b/src/libmowgli/mowgli_module_win32.c @@ -0,0 +1,62 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_module_win32.c: Loadable modules under Microsoft Windows. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#define WIN32_LEAN_AND_MEAN +#include + +mowgli_module_t mowgli_module_open(const char *path) +{ + HANDLE handle = LoadLibraryA(path); + + /* make sure we have something. make this an assertion so that + * there is feedback if something happens. (poor programming practice). + */ + return_val_if_fail(handle != NULL, NULL); + + return (mowgli_module_t)handle; +} + +void * mowgli_module_symbol(mowgli_module_t module, const char *symbol) +{ + void *handle; + + return_val_if_fail(module != NULL, NULL); + + handle = GetProcAddress((HANDLE)module, symbol); + + /* make sure we have something. make this an assertion so that + * there is feedback if something happens. (poor programming practice). + */ + return_val_if_fail(handle != NULL, NULL); + + return handle; +} + +void mowgli_module_close(mowgli_module_t module) +{ + return_if_fail(module != NULL); + + FreeLibrary((HANDLE)module); +} diff --git a/src/libmowgli/mowgli_object.c b/src/libmowgli/mowgli_object.c new file mode 100644 index 0000000..731f1c5 --- /dev/null +++ b/src/libmowgli/mowgli_object.c @@ -0,0 +1,164 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object.c: Object management. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* + * mowgli_object_init + * + * Populates the object manager part of an object. + * + * Inputs: + * - pointer to object manager area + * - (optional) name of object + * - (optional) class of object + * - (optional) custom destructor + * + * Outputs: + * - none + * + * Side Effects: + * - none + */ +void mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_class_t *klass, mowgli_destructor_t des) +{ + return_if_fail(obj != NULL); + + if (name != NULL) + obj->name = strdup(name); + + if (klass != NULL) + obj->klass = klass; + else + { + mowgli_object_class_t *tmp = mowgli_alloc(sizeof(mowgli_object_class_t)); + mowgli_object_class_init(tmp, name, des, TRUE); + obj->klass = tmp; + } + + obj->refcount = 1; + + obj->message_handlers.head = NULL; + obj->message_handlers.tail = NULL; + obj->message_handlers.count = 0; + + obj->metadata.head = NULL; + obj->metadata.tail = NULL; + obj->metadata.count = 0; + + mowgli_object_message_broadcast(obj, "create"); +} + +/* + * mowgli_object_init_from_class + * + * Populates the object manager part of an object from an object class. + * + * Inputs: + * - pointer to object manager area + * - class of object + * + * Outputs: + * - none + * + * Side Effects: + * - none + */ +void +mowgli_object_init_from_class(mowgli_object_t *obj, const char *name, + mowgli_object_class_t *klass) +{ + return_if_fail(obj != NULL); + return_if_fail(klass != NULL); + + mowgli_object_init(obj, name, klass, NULL); +} + +/* + * mowgli_object_ref + * + * Increment the reference counter on an object. + * + * Inputs: + * - the object to refcount + * + * Outputs: + * - none + * + * Side Effects: + * - none + */ +void * mowgli_object_ref(void *object) +{ + return_val_if_fail(object != NULL, NULL); + + mowgli_object(object)->refcount++; + + return object; +} + +/* + * mowgli_object_unref + * + * Decrement the reference counter on an object. + * + * Inputs: + * - the object to refcount + * + * Outputs: + * - none + * + * Side Effects: + * - if the refcount is 0, the object is destroyed. + */ +void mowgli_object_unref(void *object) +{ + mowgli_object_t *obj = mowgli_object(object); + + return_if_fail(object != NULL); + + obj->refcount--; + + if (obj->refcount <= 0) + { + mowgli_object_message_broadcast(obj, "destroy"); + + if (obj->name != NULL) + free(obj->name); + + if (obj->klass != NULL) + { + mowgli_destructor_t destructor = obj->klass->destructor; + + if (obj->klass->dynamic == TRUE) + mowgli_object_class_destroy(obj->klass); + + if (destructor != NULL) + destructor(obj); + else + free(obj); + } + else + mowgli_throw_exception(mowgli.object.invalid_object_class_exception); + } +} diff --git a/src/libmowgli/mowgli_object.h b/src/libmowgli/mowgli_object.h new file mode 100644 index 0000000..5bcee2a --- /dev/null +++ b/src/libmowgli/mowgli_object.h @@ -0,0 +1,42 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object.h: Object management. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_OBJECT_H__ +#define __MOWGLI_OBJECT_H__ + +typedef struct { + char *name; + int refcount; + mowgli_object_class_t *klass; + mowgli_list_t message_handlers; + mowgli_list_t metadata; +} mowgli_object_t; + +extern void mowgli_object_init(mowgli_object_t *, const char *name, mowgli_object_class_t *klass, mowgli_destructor_t destructor); +extern void mowgli_object_init_from_class(mowgli_object_t *, const char *, mowgli_object_class_t *klass); +extern void *mowgli_object_ref(void *); +extern void mowgli_object_unref(void *); + +#define mowgli_object(x) ((mowgli_object_t *) x) + +#endif diff --git a/src/libmowgli/mowgli_object_class.c b/src/libmowgli/mowgli_object_class.c new file mode 100644 index 0000000..8dc2b83 --- /dev/null +++ b/src/libmowgli/mowgli_object_class.c @@ -0,0 +1,132 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object_class.c: Object class and type management, + * cast checking. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_patricia_t *mowgli_object_class_dict = NULL; + +static void _object_key_canon(char *str) +{ + while (*str) + { + *str = toupper(*str); + str++; + } +} + +void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic) +{ + /* if the object_class dictionary has not yet been initialized, we will want to do that. */ + if (mowgli_object_class_dict == NULL) + mowgli_object_class_dict = mowgli_patricia_create(_object_key_canon); + + if (klass == NULL) + mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception); + + if (mowgli_object_class_find_by_name(name) != NULL) + mowgli_throw_exception_fatal(mowgli.object_class.duplicate_object_class_exception); + + /* initialize object_class::name */ + klass->name = strdup(name); + + /* initialize object_class::derivitives */ + klass->derivitives.head = NULL; + klass->derivitives.tail = NULL; + klass->derivitives.count = 0; + + /* initialize object_class::destructor */ + klass->destructor = des != NULL ? des : mowgli_free; + + /* initialize object_class::dynamic */ + klass->dynamic = dynamic; + + /* add to the object_class index */ + mowgli_patricia_add(mowgli_object_class_dict, klass->name, klass); +} + +int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2) +{ + mowgli_node_t *n; + + if (klass1 == NULL || klass2 == NULL) + mowgli_throw_exception_val(mowgli.object_class.invalid_object_class_exception, 0); + + MOWGLI_LIST_FOREACH(n, klass1->derivitives.head) + { + mowgli_object_class_t *tklass = (mowgli_object_class_t *) n->data; + + if (tklass == klass2) + return 1; + } + + return 0; +} + +void mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent) +{ + if (klass == NULL || parent == NULL) + mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception); + + mowgli_node_add(klass, mowgli_node_create(), &parent->derivitives); +} + +void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *opdata, mowgli_object_class_t *klass) +{ + mowgli_object_t *object = mowgli_object(opdata); + + /* this can possibly happen at runtime .. lets not make it a fatal exception. */ + return_val_if_fail(object != NULL, NULL); + return_val_if_fail(klass != NULL, NULL); + + if (mowgli_object_class_check_cast(object->klass, klass)) + return object; + + mowgli_log("Invalid reinterpreted cast from %s<%p> to %s", object->klass->name, klass->name); + return NULL; +} + +mowgli_object_class_t *mowgli_object_class_find_by_name(const char *name) +{ + return mowgli_patricia_retrieve(mowgli_object_class_dict, name); +} + +void mowgli_object_class_destroy(mowgli_object_class_t *klass) +{ + mowgli_node_t *n, *tn; + + if (klass == NULL) + mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception); + + if (klass->dynamic != TRUE) + mowgli_throw_exception_fatal(mowgli.object_class.nondynamic_object_class_exception); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, klass->derivitives.head) + { + mowgli_node_delete(n, &klass->derivitives); + mowgli_node_free(n); + } + + mowgli_free(klass->name); + mowgli_free(klass); +} diff --git a/src/libmowgli/mowgli_object_class.h b/src/libmowgli/mowgli_object_class.h new file mode 100644 index 0000000..03cfd4b --- /dev/null +++ b/src/libmowgli/mowgli_object_class.h @@ -0,0 +1,61 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object_class.h: Object class and type management, + * cast checking. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_OBJECT_CLASS_H__ +#define __MOWGLI_OBJECT_CLASS_H__ + +typedef void (*mowgli_destructor_t)(void *); + +typedef struct { + char *name; + mowgli_list_t derivitives; + mowgli_destructor_t destructor; + mowgli_boolean_t dynamic; + mowgli_list_t message_handlers; +} mowgli_object_class_t; + +extern void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic); +extern int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2); +extern void mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent); +extern void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *object, mowgli_object_class_t *klass); +extern mowgli_object_class_t *mowgli_object_class_find_by_name(const char *name); +extern void mowgli_object_class_destroy(mowgli_object_class_t *klass); + +#define MOWGLI_REINTERPRET_CAST(object, klass) (klass *) mowgli_object_class_reinterpret_impl(object, mowgli_object_class_find_by_name( # klass )); + +#define mowgli_forced_cast(from_type, to_type, from, to)\ +do { \ + union cast_union \ + { \ + to_type out; \ + from_type in; \ + } u; \ + typedef int cant_use_union_cast[ \ + sizeof (from_type) == sizeof (u) \ + && sizeof (from_type) == sizeof (to_type) ? 1 : -1];\ + u.in = from; \ + to = u.out; \ +} while (0) + +#endif diff --git a/src/libmowgli/mowgli_object_messaging.c b/src/libmowgli/mowgli_object_messaging.c new file mode 100644 index 0000000..b61a16d --- /dev/null +++ b/src/libmowgli/mowgli_object_messaging.c @@ -0,0 +1,142 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object_messaging.c: Object event notification and message passing. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void mowgli_object_class_message_handler_attach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig) +{ + if (klass == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_object_class_exception); + + if (sig == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + + mowgli_node_add(sig, mowgli_node_create(), &klass->message_handlers); +} + +void mowgli_object_class_message_handler_detach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig) +{ + mowgli_node_t *n; + + if (klass == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_object_class_exception); + + if (sig == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + + n = mowgli_node_find(sig, &klass->message_handlers); + mowgli_node_delete(n, &klass->message_handlers); + mowgli_node_free(n); +} + +void mowgli_object_message_handler_attach(mowgli_object_t *self, mowgli_object_message_handler_t *sig) +{ + if (self == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception); + + if (sig == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + + mowgli_node_add(sig, mowgli_node_create(), &self->message_handlers); +} + +void mowgli_object_message_handler_detach(mowgli_object_t *self, mowgli_object_message_handler_t *sig) +{ + mowgli_node_t *n; + + if (self == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception); + + if (sig == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception); + + n = mowgli_node_find(sig, &self->message_handlers); + mowgli_node_delete(n, &self->message_handlers); + mowgli_node_free(n); +} + +void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, ...) +{ + mowgli_argstack_t *stack; + mowgli_object_message_handler_t *sig = NULL; + mowgli_node_t *n; + va_list va; + + if (self == NULL) + mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception); + + if (name == NULL) + mowgli_throw_exception(mowgli.null_pointer_exception); + + /* try to find a signal to compile the argument stack from, we start with self::klass first. */ + MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head) + { + mowgli_object_message_handler_t *sig2 = (mowgli_object_message_handler_t *) n->data; + + if (!strcasecmp(sig2->name, name)) + { + sig = sig2; + break; + } + } + + if (sig == NULL) + { + MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head) + { + mowgli_object_message_handler_t *sig2 = (mowgli_object_message_handler_t *) n->data; + + if (!strcasecmp(sig2->name, name)) + { + sig = sig2; + break; + } + } + } + + /* return if no signals found, else compile the argstack */ + if (sig == NULL) + return; + + va_start(va, name); + stack = mowgli_argstack_create_from_va_list(sig->descstr, va); + va_end(va); + + MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head) + { + sig = (mowgli_object_message_handler_t *) n->data; + + if (!strcasecmp(sig->name, name) && sig->handler != NULL) + sig->handler(self, sig, stack); + } + + MOWGLI_LIST_FOREACH(n, self->message_handlers.head) + { + sig = (mowgli_object_message_handler_t *) n->data; + + if (!strcasecmp(sig->name, name) && sig->handler != NULL) + sig->handler(self, sig, stack); + } + + mowgli_object_unref(stack); +} diff --git a/src/libmowgli/mowgli_object_messaging.h b/src/libmowgli/mowgli_object_messaging.h new file mode 100644 index 0000000..8fc1f95 --- /dev/null +++ b/src/libmowgli/mowgli_object_messaging.h @@ -0,0 +1,42 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object_messaging.h: Object event notification and message passing. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_OBJECT_MESSAGING_H__ +#define __MOWGLI_OBJECT_MESSAGING_H__ + +typedef struct mowgli_object_message_handler_ mowgli_object_message_handler_t; +typedef void (*mowgli_object_messaging_func_t)(mowgli_object_t *self, mowgli_object_message_handler_t *sig, mowgli_argstack_t *argstack); + +struct mowgli_object_message_handler_ { + char *name; + char *descstr; + mowgli_object_messaging_func_t handler; +}; + +extern void mowgli_object_class_message_handler_attach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig); +extern void mowgli_object_class_message_handler_detach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig); +extern void mowgli_object_message_handler_attach(mowgli_object_t *self, mowgli_object_message_handler_t *sig); +extern void mowgli_object_message_handler_detach(mowgli_object_t *self, mowgli_object_message_handler_t *sig); +extern void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, ...); + +#endif diff --git a/src/libmowgli/mowgli_object_metadata.c b/src/libmowgli/mowgli_object_metadata.c new file mode 100644 index 0000000..9cfece5 --- /dev/null +++ b/src/libmowgli/mowgli_object_metadata.c @@ -0,0 +1,104 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object_metadata.c: Object metadata. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, void *value) +{ + mowgli_object_metadata_entry_t *e = NULL; + mowgli_node_t *n; + + if (self == NULL) + mowgli_throw_exception(mowgli.object_metadata.invalid_object_exception); + + if (key == NULL) + mowgli_throw_exception(mowgli.null_pointer_exception); + + MOWGLI_LIST_FOREACH(n, self->metadata.head) + { + e = (mowgli_object_metadata_entry_t *) n->data; + + if (!strcasecmp(e->name, key)) + break; + } + + if (e != NULL) + { + e->data = value; + return; + } + + e = mowgli_alloc(sizeof(mowgli_object_metadata_entry_t)); + e->name = strdup(key); + e->data = value; + + mowgli_node_add(e, mowgli_node_create(), &self->metadata); +} + +void mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key) +{ + mowgli_object_metadata_entry_t *e; + mowgli_node_t *n, *tn; + + if (self == NULL) + mowgli_throw_exception(mowgli.object_metadata.invalid_object_exception); + + if (key == NULL) + mowgli_throw_exception(mowgli.null_pointer_exception); + + MOWGLI_LIST_FOREACH_SAFE(n, tn, self->metadata.head) + { + e = (mowgli_object_metadata_entry_t *) n->data; + + if (!strcasecmp(e->name, key)) + { + mowgli_node_delete(n, &self->metadata); + mowgli_node_free(n); + + mowgli_free(e->name); + mowgli_free(e); + } + } +} + +void *mowgli_object_metadata_retrieve(mowgli_object_t *self, const char *key) +{ + mowgli_object_metadata_entry_t *e; + mowgli_node_t *n; + + if (self == NULL) + mowgli_throw_exception_val(mowgli.object_metadata.invalid_object_exception, NULL); + + if (key == NULL) + mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL); + + MOWGLI_LIST_FOREACH(n, self->metadata.head) + { + e = (mowgli_object_metadata_entry_t *) n->data; + + if (!strcasecmp(e->name, key)) + return e->data; + } + + return NULL; +} diff --git a/src/libmowgli/mowgli_object_metadata.h b/src/libmowgli/mowgli_object_metadata.h new file mode 100644 index 0000000..5f93b8e --- /dev/null +++ b/src/libmowgli/mowgli_object_metadata.h @@ -0,0 +1,36 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_object_metadata.h: Object metadata. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_OBJECT_METADATA_H__ +#define __MOWGLI_OBJECT_METADATA_H__ + +typedef struct { + char *name; + void *data; +} mowgli_object_metadata_entry_t; + +extern void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, void *value); +extern void mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key); +extern void *mowgli_object_metadata_retrieve(mowgli_object_t *self, const char *key); + +#endif diff --git a/src/libmowgli/mowgli_patricia.c b/src/libmowgli/mowgli_patricia.c new file mode 100644 index 0000000..cf9af5c --- /dev/null +++ b/src/libmowgli/mowgli_patricia.c @@ -0,0 +1,1000 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_patricia.c: Dictionary-based information storage. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007-2010 Jilles Tjoelker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *leaf_heap = NULL; +static mowgli_heap_t *node_heap = NULL; + +/* + * Patricia tree. + * + * A radix trie that avoids one-way branching and redundant nodes. + * + * To find a node, the tree is traversed starting from the root. The + * nibnum in each node indicates which nibble of the key needs to be + * tested, and the appropriate branch is taken. + * + * The nibnum values are strictly increasing while going down the tree. + * + * -- jilles + */ + +union patricia_elem; + +struct mowgli_patricia_ +{ + void (*canonize_cb)(char *key); + union patricia_elem *root; + unsigned int count; + char *id; +}; + +#define POINTERS_PER_NODE 16 +#define NIBBLE_VAL(key, nibnum) (((key)[(nibnum) / 2] >> ((nibnum) & 1 ? 0 : 4)) & 0xF) + +struct patricia_node +{ + /* nibble to test (nibble NUM%2 of byte NUM/2) */ + int nibnum; + /* branches of the tree */ + union patricia_elem *down[POINTERS_PER_NODE]; + union patricia_elem *parent; + char parent_val; +}; + +/* mowgli_patricia_elem_ is the name used in mowgli_patricia.h. + * patricia_leaf is the name historically used here. */ +#define patricia_leaf mowgli_patricia_elem_ + +struct patricia_leaf +{ + /* -1 to indicate this is a leaf, not a node */ + int nibnum; + /* data associated with the key */ + void *data; + /* key (canonized copy) */ + char *key; + union patricia_elem *parent; + char parent_val; +}; + +union patricia_elem +{ + int nibnum; + struct patricia_node node; + struct patricia_leaf leaf; +}; + +#define IS_LEAF(elem) ((elem)->nibnum == -1) + +/* Preserve compatibility with the old mowgli_patricia.h */ +#define STATE_CUR(state) ((state)->pspare[0]) +#define STATE_NEXT(state) ((state)->pspare[1]) + +/* + * first_leaf() + * + * Find the smallest leaf hanging off a subtree. + * + * Inputs: + * - element (may be leaf or node) heading subtree + * + * Outputs: + * - lowest leaf in subtree + * + * Side Effects: + * - none + */ +static union patricia_elem *first_leaf(union patricia_elem *delem) +{ + int val; + + while (!IS_LEAF(delem)) + { + for (val = 0; val < POINTERS_PER_NODE; val++) + { + if (delem->node.down[val] != NULL) + { + delem = delem->node.down[val]; + break; + } + } + } + return delem; +} + +/* + * mowgli_patricia_create(void (*canonize_cb)(char *key)) + * + * Dictionary object factory. + * + * Inputs: + * - function to use for canonizing keys (for example, use + * a function that makes the string upper case to create + * a patricia with case-insensitive matching) + * + * Outputs: + * - on success, a new patricia object. + * + * Side Effects: + * - if services runs out of memory and cannot allocate the object, + * the program will abort. + */ +mowgli_patricia_t *mowgli_patricia_create(void (*canonize_cb)(char *key)) +{ + mowgli_patricia_t *dtree = (mowgli_patricia_t *) mowgli_alloc(sizeof(mowgli_patricia_t)); + + dtree->canonize_cb = canonize_cb; + + if (!leaf_heap) + leaf_heap = mowgli_heap_create(sizeof(struct patricia_leaf), 1024, BH_NOW); + if (!node_heap) + node_heap = mowgli_heap_create(sizeof(struct patricia_node), 128, BH_NOW); + + dtree->root = NULL; + + return dtree; +} + +/* + * mowgli_patricia_create_named(const char *name, + * void (*canonize_cb)(char *key)) + * + * Dictionary object factory. + * + * Inputs: + * - patricia name + * - function to use for canonizing keys (for example, use + * a function that makes the string upper case to create + * a patricia with case-insensitive matching) + * + * Outputs: + * - on success, a new patricia object. + * + * Side Effects: + * - if services runs out of memory and cannot allocate the object, + * the program will abort. + */ +mowgli_patricia_t *mowgli_patricia_create_named(const char *name, + void (*canonize_cb)(char *key)) +{ + mowgli_patricia_t *dtree = (mowgli_patricia_t *) mowgli_alloc(sizeof(mowgli_patricia_t)); + + dtree->canonize_cb = canonize_cb; + dtree->id = strdup(name); + + if (!leaf_heap) + leaf_heap = mowgli_heap_create(sizeof(struct patricia_leaf), 1024, BH_NOW); + if (!node_heap) + node_heap = mowgli_heap_create(sizeof(struct patricia_node), 128, BH_NOW); + + dtree->root = NULL; + + return dtree; +} + +/* + * mowgli_patricia_destroy(mowgli_patricia_t *dtree, + * void (*destroy_cb)(const char *key, void *data, void *privdata), + * void *privdata); + * + * Recursively destroys all nodes in a patricia tree. + * + * Inputs: + * - patricia tree object + * - optional iteration callback + * - optional opaque/private data to pass to callback + * + * Outputs: + * - nothing + * + * Side Effects: + * - on success, a dtree and optionally it's children are destroyed. + * + * Notes: + * - if this is called without a callback, the objects bound to the + * DTree will not be destroyed. + */ +void mowgli_patricia_destroy(mowgli_patricia_t *dtree, + void (*destroy_cb)(const char *key, void *data, void *privdata), + void *privdata) +{ + mowgli_patricia_iteration_state_t state; + union patricia_elem *delem; + void *entry; + + return_if_fail(dtree != NULL); + + MOWGLI_PATRICIA_FOREACH(entry, &state, dtree) + { + delem = STATE_CUR(&state); + if (destroy_cb != NULL) + (*destroy_cb)(delem->leaf.key, delem->leaf.data, + privdata); + mowgli_patricia_delete(dtree, delem->leaf.key); + } + + mowgli_free(dtree); +} + +/* + * mowgli_patricia_foreach(mowgli_patricia_t *dtree, + * int (*foreach_cb)(const char *key, void *data, void *privdata), + * void *privdata); + * + * Iterates over all entries in a DTree. + * + * Inputs: + * - patricia tree object + * - optional iteration callback + * - optional opaque/private data to pass to callback + * + * Outputs: + * - nothing + * + * Side Effects: + * - on success, a dtree is iterated + */ +void mowgli_patricia_foreach(mowgli_patricia_t *dtree, + int (*foreach_cb)(const char *key, void *data, void *privdata), + void *privdata) +{ + union patricia_elem *delem, *next; + int val; + + return_if_fail(dtree != NULL); + + delem = dtree->root; + if (delem == NULL) + return; + /* Only one element in the tree */ + if (IS_LEAF(delem)) + { + if (foreach_cb != NULL) + (*foreach_cb)(delem->leaf.key, delem->leaf.data, privdata); + return; + } + val = 0; + do + { + do + next = delem->node.down[val++]; + while (next == NULL && val < POINTERS_PER_NODE); + if (next != NULL) + { + if (IS_LEAF(next)) + { + if (foreach_cb != NULL) + (*foreach_cb)(next->leaf.key, next->leaf.data, privdata); + } + else + { + delem = next; + val = 0; + } + } + while (val >= POINTERS_PER_NODE) + { + val = delem->node.parent_val; + delem = delem->node.parent; + if (delem == NULL) + break; + val++; + } + } while (delem != NULL); +} + +/* + * mowgli_patricia_search(mowgli_patricia_t *dtree, + * void *(*foreach_cb)(const char *key, void *data, void *privdata), + * void *privdata); + * + * Searches all entries in a DTree using a custom callback. + * + * Inputs: + * - patricia tree object + * - optional iteration callback + * - optional opaque/private data to pass to callback + * + * Outputs: + * - on success, the requested object + * - on failure, NULL. + * + * Side Effects: + * - a dtree is iterated until the requested conditions are met + */ +void *mowgli_patricia_search(mowgli_patricia_t *dtree, + void *(*foreach_cb)(const char *key, void *data, void *privdata), + void *privdata) +{ + union patricia_elem *delem, *next; + int val; + void *ret = NULL; + + return_val_if_fail(dtree != NULL, NULL); + + delem = dtree->root; + if (delem == NULL) + return NULL; + /* Only one element in the tree */ + if (IS_LEAF(delem)) + { + if (foreach_cb != NULL) + return (*foreach_cb)(delem->leaf.key, delem->leaf.data, privdata); + return NULL; + } + val = 0; + for (;;) + { + do + next = delem->node.down[val++]; + while (next == NULL && val < POINTERS_PER_NODE); + if (next != NULL) + { + if (IS_LEAF(next)) + { + if (foreach_cb != NULL) + ret = (*foreach_cb)(next->leaf.key, next->leaf.data, privdata); + if (ret != NULL) + break; + } + else + { + delem = next; + val = 0; + } + } + while (val >= POINTERS_PER_NODE) + { + val = delem->node.parent_val; + delem = delem->node.parent; + if (delem == NULL) + break; + val++; + } + } + return ret; +} + +/* + * mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, + * mowgli_patricia_iteration_state_t *state); + * + * Initializes a static DTree iterator. + * + * Inputs: + * - patricia tree object + * - static DTree iterator + * + * Outputs: + * - nothing + * + * Side Effects: + * - the static iterator, &state, is initialized. + */ +void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, + mowgli_patricia_iteration_state_t *state) +{ + if (dtree == NULL) + return; + + return_if_fail(state != NULL); + + if (dtree->root != NULL) + STATE_NEXT(state) = first_leaf(dtree->root); + else + STATE_NEXT(state) = NULL; + STATE_CUR(state) = STATE_NEXT(state); + + if (STATE_NEXT(state) == NULL) + return; + + /* make STATE_CUR point to first item and STATE_NEXT point to + * second item */ + mowgli_patricia_foreach_next(dtree, state); +} + +/* + * mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, + * mowgli_patricia_iteration_state_t *state); + * + * Returns the data from the current node being iterated by the + * static iterator. + * + * Inputs: + * - patricia tree object + * - static DTree iterator + * + * Outputs: + * - reference to data in the current dtree node being iterated + * + * Side Effects: + * - none + */ +void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, + mowgli_patricia_iteration_state_t *state) +{ + if (dtree == NULL) + return NULL; + + return_val_if_fail(state != NULL, NULL); + + return STATE_CUR(state) != NULL ? + ((struct patricia_leaf *)STATE_CUR(state))->data : NULL; +} + +/* + * mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, + * mowgli_patricia_iteration_state_t *state); + * + * Advances a static DTree iterator. + * + * Inputs: + * - patricia tree object + * - static DTree iterator + * + * Outputs: + * - nothing + * + * Side Effects: + * - the static iterator, &state, is advanced to a new DTree node. + */ +void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, + mowgli_patricia_iteration_state_t *state) +{ + struct patricia_leaf *leaf; + union patricia_elem *delem, *next; + int val; + + if (dtree == NULL) + return; + + return_if_fail(state != NULL); + + if (STATE_CUR(state) == NULL) + { + mowgli_log("mowgli_patricia_foreach_next(): called again after iteration finished on dtree<%p>", dtree); + return; + } + + STATE_CUR(state) = STATE_NEXT(state); + + if (STATE_NEXT(state) == NULL) + return; + + leaf = STATE_NEXT(state); + delem = leaf->parent; + val = leaf->parent_val; + + while (delem != NULL) + { + do + next = delem->node.down[val++]; + while (next == NULL && val < POINTERS_PER_NODE); + if (next != NULL) + { + if (IS_LEAF(next)) + { + /* We will find the original leaf first. */ + if (&next->leaf != leaf) + { + if (strcmp(next->leaf.key, leaf->key) < 0) + { + mowgli_log("mowgli_patricia_foreach_next(): iteration went backwards (libmowgli bug) on dtree<%p>", dtree); + STATE_NEXT(state) = NULL; + return; + } + STATE_NEXT(state) = next; + return; + } + } + else + { + delem = next; + val = 0; + } + } + while (val >= POINTERS_PER_NODE) + { + val = delem->node.parent_val; + delem = delem->node.parent; + if (delem == NULL) + break; + val++; + } + } + STATE_NEXT(state) = NULL; +} + +/* + * mowgli_patricia_elem_find(mowgli_patricia_t *dtree, const char *key) + * + * Looks up a DTree node by name. + * + * Inputs: + * - patricia tree object + * - name of node to lookup + * + * Outputs: + * - on success, the dtree node requested + * - on failure, NULL + * + * Side Effects: + * - none + */ +struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const char *key) +{ + char ckey_store[256]; + char *ckey_buf = NULL; + const char *ckey; + union patricia_elem *delem; + int val, keylen; + + return_val_if_fail(dict != NULL, NULL); + return_val_if_fail(key != NULL, NULL); + + keylen = strlen(key); + + if (dict->canonize_cb == NULL) + ckey = key; + else + { + if (keylen >= sizeof ckey_store) + { + ckey_buf = strdup(key); + dict->canonize_cb(ckey_buf); + ckey = ckey_buf; + } + else + { + mowgli_strlcpy(ckey_store, key, sizeof ckey_store); + dict->canonize_cb(ckey_store); + ckey = ckey_store; + } + } + + delem = dict->root; + while (delem != NULL && !IS_LEAF(delem)) + { + if (delem->nibnum / 2 < keylen) + val = NIBBLE_VAL(ckey, delem->nibnum); + else + val = 0; + delem = delem->node.down[val]; + } + /* Now, if the key is in the tree, delem contains it. */ + if (delem != NULL && strcmp(delem->leaf.key, ckey)) + delem = NULL; + + if (ckey_buf != NULL) + free(ckey_buf); + + return &delem->leaf; +} + +/* + * mowgli_patricia_add(mowgli_patricia_t *dtree, const char *key, void *data) + * + * Creates a new DTree node and binds data to it. + * + * Inputs: + * - patricia tree object + * - name for new DTree node + * - data to bind to the new DTree node + * + * Outputs: + * - on success, TRUE + * - on failure, FALSE + * + * Side Effects: + * - data is inserted into the DTree. + */ +struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const char *key, void *data) +{ + char *ckey; + union patricia_elem *delem, *prev, *newnode; + union patricia_elem **place1; + int val, keylen; + int i, j; + + return_val_if_fail(dict != NULL, FALSE); + return_val_if_fail(key != NULL, FALSE); + return_val_if_fail(data != NULL, FALSE); + + keylen = strlen(key); + ckey = strdup(key); + if (ckey == NULL) + { + mowgli_log("major WTF: ckey is NULL, not adding node."); + return NULL; + } + if (dict->canonize_cb != NULL) + dict->canonize_cb(ckey); + + prev = NULL; + val = POINTERS_PER_NODE + 2; /* trap value */ + delem = dict->root; + while (delem != NULL && !IS_LEAF(delem)) + { + prev = delem; + if (delem->nibnum / 2 < keylen) + val = NIBBLE_VAL(ckey, delem->nibnum); + else + val = 0; + delem = delem->node.down[val]; + } + /* Now, if the key is in the tree, delem contains it. */ + if (delem != NULL && !strcmp(delem->leaf.key, ckey)) + { + mowgli_log("Key is already in dict, ignoring duplicate"); + free(ckey); + return NULL; + } + + if (delem == NULL && prev != NULL) + { + /* Get a leaf to compare with. */ + delem = first_leaf(prev); + } + + if (delem == NULL) + { + soft_assert(prev == NULL); + soft_assert(dict->count == 0); + place1 = &dict->root; + *place1 = mowgli_heap_alloc(leaf_heap); + (*place1)->nibnum = -1; + (*place1)->leaf.data = data; + (*place1)->leaf.key = ckey; + (*place1)->leaf.parent = prev; + (*place1)->leaf.parent_val = val; + dict->count++; + return &(*place1)->leaf; + } + + /* Find the first nibble where they differ. */ + for (i = 0; NIBBLE_VAL(ckey, i) == NIBBLE_VAL(delem->leaf.key, i); i++) + ; + /* Find where to insert the new node. */ + while (prev != NULL && prev->nibnum > i) + { + val = prev->node.parent_val; + prev = prev->node.parent; + } + if (prev == NULL || prev->nibnum < i) + { + /* Insert new node below prev */ + newnode = mowgli_heap_alloc(node_heap); + newnode->nibnum = i; + newnode->node.parent = prev; + newnode->node.parent_val = val; + for (j = 0; j < POINTERS_PER_NODE; j++) + newnode->node.down[j] = NULL; + if (prev == NULL) + { + newnode->node.down[NIBBLE_VAL(delem->leaf.key, i)] = dict->root; + if (IS_LEAF(dict->root)) + { + dict->root->leaf.parent = newnode; + dict->root->leaf.parent_val = NIBBLE_VAL(delem->leaf.key, i); + } + else + { + soft_assert(dict->root->nibnum > i); + dict->root->node.parent = newnode; + dict->root->node.parent_val = NIBBLE_VAL(delem->leaf.key, i); + } + dict->root = newnode; + } + else + { + newnode->node.down[NIBBLE_VAL(delem->leaf.key, i)] = prev->node.down[val]; + if (IS_LEAF(prev->node.down[val])) + { + prev->node.down[val]->leaf.parent = newnode; + prev->node.down[val]->leaf.parent_val = NIBBLE_VAL(delem->leaf.key, i); + } + else + { + prev->node.down[val]->node.parent = newnode; + prev->node.down[val]->node.parent_val = NIBBLE_VAL(delem->leaf.key, i); + } + prev->node.down[val] = newnode; + } + } + else + { + /* This nibble is already checked. */ + soft_assert(prev->nibnum == i); + newnode = prev; + } + val = NIBBLE_VAL(ckey, i); + place1 = &newnode->node.down[val]; + soft_assert(*place1 == NULL); + *place1 = mowgli_heap_alloc(leaf_heap); + (*place1)->nibnum = -1; + (*place1)->leaf.data = data; + (*place1)->leaf.key = ckey; + (*place1)->leaf.parent = newnode; + (*place1)->leaf.parent_val = val; + dict->count++; + return &(*place1)->leaf; +} + +mowgli_boolean_t mowgli_patricia_add(mowgli_patricia_t *dict, const char *key, void *data) +{ + return (mowgli_patricia_elem_add(dict, key, data) != NULL) ? TRUE : FALSE; +} + +/* + * mowgli_patricia_delete(mowgli_patricia_t *dtree, const char *key) + * + * Deletes data from a patricia tree. + * + * Inputs: + * - patricia tree object + * - name of DTree node to delete + * + * Outputs: + * - on success, the remaining data that needs to be mowgli_freed + * - on failure, NULL + * + * Side Effects: + * - data is removed from the DTree. + * + * Notes: + * - the returned data needs to be mowgli_freed/released manually! + */ +void *mowgli_patricia_delete(mowgli_patricia_t *dict, const char *key) +{ + void *data; + struct patricia_leaf *leaf; + + leaf = mowgli_patricia_elem_find(dict, key); + if (leaf == NULL) + return NULL; + + data = leaf->data; + mowgli_patricia_elem_delete(dict, leaf); + return data; +} + +void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf *leaf) +{ + union patricia_elem *delem, *prev, *next; + int val, i, used; + + delem = (union patricia_elem *)leaf; + + val = delem->leaf.parent_val; + prev = delem->leaf.parent; + + mowgli_free(delem->leaf.key); + mowgli_heap_free(leaf_heap, delem); + + if (prev != NULL) + { + prev->node.down[val] = NULL; + + /* Leaf is gone, now consider the node it was in. */ + delem = prev; + + used = -1; + for (i = 0; i < POINTERS_PER_NODE; i++) + if (delem->node.down[i] != NULL) + used = used == -1 ? i : -2; + soft_assert(used == -2 || used >= 0); + if (used >= 0) + { + /* Only one pointer in this node, remove it. + * Replace the pointer that pointed to it by + * the sole pointer in it. + */ + next = delem->node.down[used]; + val = delem->node.parent_val; + prev = delem->node.parent; + if (prev != NULL) + prev->node.down[val] = next; + else + dict->root = next; + if (IS_LEAF(next)) + next->leaf.parent = prev, next->leaf.parent_val = val; + else + next->node.parent = prev, next->node.parent_val = val; + mowgli_heap_free(node_heap, delem); + } + } + else + { + /* This was the last leaf. */ + dict->root = NULL; + } + + dict->count--; + if (dict->count == 0) + { + soft_assert(dict->root == NULL); + dict->root = NULL; + } +} + +/* + * mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key) + * + * Retrieves data from a patricia. + * + * Inputs: + * - patricia tree object + * - name of node to lookup + * + * Outputs: + * - on success, the data bound to the DTree node. + * - on failure, NULL + * + * Side Effects: + * - none + */ +void *mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key) +{ + struct patricia_leaf *delem = mowgli_patricia_elem_find(dtree, key); + + if (delem != NULL) + return delem->data; + + return NULL; +} + +const char *mowgli_patricia_elem_get_key(struct patricia_leaf *leaf) +{ + return leaf->key; +} + +void mowgli_patricia_elem_set_data(struct patricia_leaf *leaf, void *data) +{ + leaf->data = data; +} + +void *mowgli_patricia_elem_get_data(struct patricia_leaf *leaf) +{ + return leaf->data; +} + +/* + * mowgli_patricia_size(mowgli_patricia_t *dict) + * + * Returns the size of a patricia. + * + * Inputs: + * - patricia tree object + * + * Outputs: + * - size of patricia + * + * Side Effects: + * - none + */ +unsigned int mowgli_patricia_size(mowgli_patricia_t *dict) +{ + return_val_if_fail(dict != NULL, 0); + + return dict->count; +} + +/* returns the sum of the depths of the subtree rooted in delem at depth depth */ +/* there is no need for this to be recursive, but it is easier... */ +static int +stats_recurse(union patricia_elem *delem, int depth, int *pmaxdepth) +{ + int result = 0; + int val; + union patricia_elem *next; + + if (depth > *pmaxdepth) + *pmaxdepth = depth; + if (depth == 0) + { + if (IS_LEAF(delem)) + { + soft_assert(delem->leaf.parent == NULL); + } + else + { + soft_assert(delem->node.parent == NULL); + } + } + if (IS_LEAF(delem)) + return depth; + for (val = 0; val < POINTERS_PER_NODE; val++) + { + next = delem->node.down[val]; + if (next == NULL) + continue; + result += stats_recurse(next, depth + 1, pmaxdepth); + if (IS_LEAF(next)) + { + soft_assert(next->leaf.parent == delem); + soft_assert(next->leaf.parent_val == val); + } + else + { + soft_assert(next->node.parent == delem); + soft_assert(next->node.parent_val == val); + soft_assert(next->node.nibnum > delem->node.nibnum); + } + } + return result; +} + +/* + * mowgli_patricia_stats(mowgli_patricia_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) + * + * Returns the size of a patricia. + * + * Inputs: + * - patricia tree object + * - callback + * - data for callback + * + * Outputs: + * - none + * + * Side Effects: + * - callback called with stats text + */ +void mowgli_patricia_stats(mowgli_patricia_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) +{ + char str[256]; + int sum, maxdepth; + + return_if_fail(dict != NULL); + + if (dict->id != NULL) + snprintf(str, sizeof str, "Dictionary stats for %s (%d)", + dict->id, dict->count); + else + snprintf(str, sizeof str, "Dictionary stats for <%p> (%d)", + dict, dict->count); + cb(str, privdata); + maxdepth = 0; + if (dict->count > 0) + { + sum = stats_recurse(dict->root, 0, &maxdepth); + snprintf(str, sizeof str, "Depth sum %d Avg depth %d Max depth %d", sum, sum / dict->count, maxdepth); + } + else + snprintf(str, sizeof str, "Depth sum 0 Avg depth 0 Max depth 0"); + cb(str, privdata); + return; +} diff --git a/src/libmowgli/mowgli_patricia.h b/src/libmowgli/mowgli_patricia.h new file mode 100644 index 0000000..6c2c669 --- /dev/null +++ b/src/libmowgli/mowgli_patricia.h @@ -0,0 +1,148 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_patricia.h: Dictionary-based storage. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007-2008 Jilles Tjoelker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_PATRICIA_H__ +#define __MOWGLI_PATRICIA_H__ + +struct mowgli_patricia_; /* defined in src/patricia.c */ +struct mowgli_patricia_elem_; /* defined in src/patricia.c */ + +typedef struct mowgli_patricia_ mowgli_patricia_t; +typedef struct mowgli_patricia_elem_ mowgli_patricia_elem_t; + +/* + * mowgli_patricia_iteration_state_t, private. + */ +struct mowgli_patricia_iteration_state_ +{ + mowgli_patricia_elem_t *cur, *next; + void *pspare[4]; + int ispare[4]; +}; + +typedef struct mowgli_patricia_iteration_state_ mowgli_patricia_iteration_state_t; + +/* + * this is a convenience macro for inlining iteration of dictionaries. + */ +#define MOWGLI_PATRICIA_FOREACH(element, state, dict) for (mowgli_patricia_foreach_start((dict), (state)); (element = mowgli_patricia_foreach_cur((dict), (state))); mowgli_patricia_foreach_next((dict), (state))) + +/* + * mowgli_patricia_create() creates a new patricia tree of the defined resolution. + * compare_cb is the canonizing function. + */ + +/* defined if this version of Mowgli allows canonize_cb to be NULL */ +#define MOWGLI_PATRICIA_ALLOWS_NULL_CANONIZE + +extern mowgli_patricia_t *mowgli_patricia_create(void (*canonize_cb)(char *key)); + +/* + * mowgli_patricia_destroy() destroys all entries in a dtree, and also optionally calls + * a defined callback function to destroy any data attached to it. + */ +extern void mowgli_patricia_destroy(mowgli_patricia_t *dtree, + void (*destroy_cb)(const char *key, void *data, void *privdata), + void *privdata); + +/* + * mowgli_patricia_foreach() iterates all entries in a dtree, and also optionally calls + * a defined callback function to use any data attached to it. + * + * To shortcircuit iteration, return non-zero from the callback function. + */ +extern void mowgli_patricia_foreach(mowgli_patricia_t *dtree, + int (*foreach_cb)(const char *key, void *data, void *privdata), + void *privdata); + +/* + * mowgli_patricia_search() iterates all entries in a dtree, and also optionally calls + * a defined callback function to use any data attached to it. + * + * When the object is found, a non-NULL is returned from the callback, which results + * in that object being returned to the user. + */ +extern void *mowgli_patricia_search(mowgli_patricia_t *dtree, + void *(*foreach_cb)(const char *key, void *data, void *privdata), + void *privdata); + +/* + * mowgli_patricia_foreach_start() begins an iteration over all items + * keeping state in the given struct. If there is only one iteration + * in progress at a time, it is permitted to remove the current element + * of the iteration (but not any other element). + */ +extern void mowgli_patricia_foreach_start(mowgli_patricia_t *dtree, + mowgli_patricia_iteration_state_t *state); + +/* + * mowgli_patricia_foreach_cur() returns the current element of the iteration, + * or NULL if there are no more elements. + */ +extern void *mowgli_patricia_foreach_cur(mowgli_patricia_t *dtree, + mowgli_patricia_iteration_state_t *state); + +/* + * mowgli_patricia_foreach_next() moves to the next element. + */ +extern void mowgli_patricia_foreach_next(mowgli_patricia_t *dtree, + mowgli_patricia_iteration_state_t *state); + +/* + * mowgli_patricia_add() adds a key->value entry to the patricia tree. + */ +extern mowgli_boolean_t mowgli_patricia_add(mowgli_patricia_t *dtree, const char *key, void *data); + +/* + * mowgli_patricia_find() returns data from a dtree for key 'key'. + */ +extern void *mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key); + +/* + * mowgli_patricia_delete() deletes a key->value entry from the patricia tree. + */ +extern void *mowgli_patricia_delete(mowgli_patricia_t *dtree, const char *key); + +/* Low-level functions */ +mowgli_patricia_elem_t *mowgli_patricia_elem_add(mowgli_patricia_t *dtree, const char *key, void *data); +mowgli_patricia_elem_t *mowgli_patricia_elem_find(mowgli_patricia_t *dtree, const char *key); +void mowgli_patricia_elem_delete(mowgli_patricia_t *dtree, mowgli_patricia_elem_t *elem); +const char *mowgli_patricia_elem_get_key(mowgli_patricia_elem_t *elem); +void mowgli_patricia_elem_set_data(mowgli_patricia_elem_t *elem, void *data); +void *mowgli_patricia_elem_get_data(mowgli_patricia_elem_t *elem); + +unsigned int mowgli_patricia_size(mowgli_patricia_t *dict); +void mowgli_patricia_stats(mowgli_patricia_t *dict, void (*cb)(const char *line, void *privdata), void *privdata); + +#endif diff --git a/src/libmowgli/mowgli_queue.c b/src/libmowgli/mowgli_queue.c new file mode 100644 index 0000000..f27ff50 --- /dev/null +++ b/src/libmowgli/mowgli_queue.c @@ -0,0 +1,209 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_queue.c: Double-ended queues, also known as deque. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *mowgli_queue_heap = NULL; + +void +mowgli_queue_init(void) +{ + mowgli_queue_heap = mowgli_heap_create(sizeof(mowgli_queue_t), 256, BH_NOW); + + if (mowgli_queue_heap == NULL) + mowgli_log("mowgli_queue_heap was not created, expect problems."); +} + +mowgli_queue_t * +mowgli_queue_shift(mowgli_queue_t *head, void *data) +{ + mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap); + + out->next = head; + out->data = data; + + if (head != NULL) + { + out->prev = head->prev; + + if (out->prev != NULL) + out->prev->next = out; + + head->prev = out; + } + + return out; +} + +mowgli_queue_t * +mowgli_queue_push(mowgli_queue_t *head, void *data) +{ + mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap); + + out->prev = head; + out->data = data; + + if (head != NULL) + head->next = out; + + return out; +} + +mowgli_queue_t * +mowgli_queue_remove(mowgli_queue_t *head) +{ + mowgli_queue_t *out; + + if (head->prev != NULL) + head->prev->next = head->next; + + if (head->next != NULL) + head->next->prev = head->prev; + + out = head->prev != NULL ? head->prev : head->next; + + mowgli_heap_free(mowgli_queue_heap, head); + + return out; +} + +mowgli_queue_t * +mowgli_queue_find(mowgli_queue_t *head, void *data) +{ + mowgli_queue_t *n; + + for (n = head; n != NULL; n = n->next) + if (n->data == data) + return n; + + return NULL; +} + +mowgli_queue_t * +mowgli_queue_remove_data(mowgli_queue_t *head, void *data) +{ + mowgli_queue_t *n = mowgli_queue_find(head, data); + + if (n != NULL) + return mowgli_queue_remove(n); + + return NULL; +} + +void +mowgli_queue_destroy(mowgli_queue_t *head) +{ + mowgli_queue_t *n, *n2; + + for (n = head, n2 = n ? n->next : NULL; n != NULL; n = n2, n2 = n ? n->next : NULL) + mowgli_queue_remove(n); +} + +mowgli_queue_t * +mowgli_queue_skip(mowgli_queue_t *head, int nodes) +{ + mowgli_queue_t *n; + int iter; + + for (iter = 0, n = head; n != NULL && iter < nodes; n = n->next, iter++); + + return n; +} + +mowgli_queue_t * +mowgli_queue_rewind(mowgli_queue_t *head, int nodes) +{ + mowgli_queue_t *n; + int iter; + + for (iter = 0, n = head; n != NULL && iter < nodes; n = n->prev, iter++); + + return n; +} + +mowgli_queue_t * +mowgli_queue_head(mowgli_queue_t *n) +{ + mowgli_queue_t *tn; + + for (tn = n; tn != NULL && tn->prev != NULL; tn = tn->prev); + + return tn; +} + +mowgli_queue_t * +mowgli_queue_tail(mowgli_queue_t *n) +{ + mowgli_queue_t *tn; + + for (tn = n; tn != NULL && tn->next != NULL; tn = tn->next); + + return tn; +} + +void * +mowgli_queue_pop_head(mowgli_queue_t **n) +{ + mowgli_queue_t *tn; + void *out; + + return_val_if_fail(n != NULL, NULL); + return_val_if_fail(*n != NULL, NULL); + + tn = *n; + out = tn->data; + *n = tn->next; + + mowgli_queue_remove(tn); + + return out; +} + +void * +mowgli_queue_pop_tail(mowgli_queue_t **n) +{ + mowgli_queue_t *tn; + void *out; + + return_val_if_fail(n != NULL, NULL); + return_val_if_fail(*n != NULL, NULL); + + tn = *n; + out = tn->data; + *n = tn->prev; + + mowgli_queue_remove(tn); + + return out; +} + +int +mowgli_queue_length(mowgli_queue_t *head) +{ + int iter; + mowgli_queue_t *n; + + for (n = head, iter = 0; n != NULL; n = n->next, iter++); + + return iter; +} diff --git a/src/libmowgli/mowgli_queue.h b/src/libmowgli/mowgli_queue.h new file mode 100644 index 0000000..2d3b16b --- /dev/null +++ b/src/libmowgli/mowgli_queue.h @@ -0,0 +1,44 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_queue.h: Double-ended queues, also known as deque. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_QUEUE_H__ +#define __MOWGLI_QUEUE_H__ + +typedef mowgli_iterator_t mowgli_queue_t; + +extern void mowgli_queue_init(void); +extern mowgli_queue_t *mowgli_queue_push(mowgli_queue_t *head, void *data); +extern mowgli_queue_t *mowgli_queue_shift(mowgli_queue_t *head, void *data); +extern mowgli_queue_t *mowgli_queue_remove(mowgli_queue_t *head); +extern mowgli_queue_t *mowgli_queue_find(mowgli_queue_t *head, void *data); +extern mowgli_queue_t *mowgli_queue_remove_data(mowgli_queue_t *head, void *data); +extern void mowgli_queue_destroy(mowgli_queue_t *head); +extern mowgli_queue_t *mowgli_queue_skip(mowgli_queue_t *head, int amt); +extern mowgli_queue_t *mowgli_queue_rewind(mowgli_queue_t *head, int amt); +extern mowgli_queue_t *mowgli_queue_head(mowgli_queue_t *n); +extern mowgli_queue_t *mowgli_queue_tail(mowgli_queue_t *n); +extern void *mowgli_queue_pop_head(mowgli_queue_t **n); +extern void *mowgli_queue_pop_tail(mowgli_queue_t **n); +extern int mowgli_queue_length(mowgli_queue_t *head); + +#endif diff --git a/src/libmowgli/mowgli_random.c b/src/libmowgli/mowgli_random.c new file mode 100644 index 0000000..cd6d03e --- /dev/null +++ b/src/libmowgli/mowgli_random.c @@ -0,0 +1,143 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_random.c: Portable mersinne-twister based psuedo-random number generator. + * + * Copyright (c) 2007 William Pitcock + * Algorithm copyright (c) 1999-2007 Takuji Nishimura and Makoto Matsumoto + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +/* mowgli_random_t contains state data which is private */ +struct mowgli_random_ +{ + mowgli_object_t object; + unsigned int mt[N]; + size_t mti; +}; + +static mowgli_object_class_t klass; + +/* initialization */ +void mowgli_random_init(void) +{ + mowgli_object_class_init(&klass, "mowgli_random_t", NULL, FALSE); +} + +/* construction and destruction. */ +mowgli_random_t *mowgli_random_create(void) +{ + return mowgli_random_create_with_seed(time(NULL)); +} + +mowgli_random_t *mowgli_random_create_with_seed(unsigned int seed) +{ + mowgli_random_t *out = mowgli_alloc(sizeof(mowgli_random_t)); + mowgli_object_init(mowgli_object(out), NULL, &klass, NULL); + + mowgli_random_reseed(out, seed); + + return out; +} + +/* reset seed */ +void mowgli_random_reseed(mowgli_random_t *self, unsigned int seed) +{ + return_if_fail(self != NULL); + + self->mt[0] = seed & 0xffffffffUL; + for (self->mti = 1; self->mti < N; self->mti++) + { + self->mt[self->mti] = (1812433253UL * (self->mt[self->mti - 1] ^ (self->mt[self->mti - 1] >> 30)) + self->mti); + self->mt[self->mti] &= 0xffffffffUL; + } +} + +/* number retrieval */ +unsigned int mowgli_random_int(mowgli_random_t *self) +{ + unsigned int y; + static unsigned int mag01[2] = { 0x0UL, MATRIX_A }; + + return_val_if_fail(self != NULL, 0); + + if (self->mti >= N) + { + int t; + + for (t = 0; t < N - M; t++) + { + y = (self->mt[t] & UPPER_MASK) | (self->mt[t + 1] & LOWER_MASK); + self->mt[t] = self->mt[t + M] ^ (y >> 1) ^ mag01[y & 0x1U]; + } + + for (; t < N - 1; t++) + { + y = (self->mt[t] & UPPER_MASK) | (self->mt[t + 1] & LOWER_MASK); + self->mt[t] = self->mt[t + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U]; + } + + y = (self->mt[N - 1] & UPPER_MASK) | (self->mt[0] & LOWER_MASK); + self->mt[N - 1] = self->mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1U]; + self->mti = 0; + } + + y = self->mt[self->mti++]; + + /* tempering */ + y ^= (y >> 11); + y ^= (y >> 7) & 0x9d2c5680U; + y ^= (y >> 15) & 0xefc60000U; + y ^= (y >> 18); + + return y; +} + +int mowgli_random_int_ranged(mowgli_random_t *self, int begin, int end) +{ + int dist = end - begin; + unsigned int max, ret; + + if (dist <= 0x80000000U) + { + unsigned int remain = (0x80000000U % dist) * 2; + + if (remain >= dist) + remain -= dist; + + max = 0xFFFFFFFFU - remain; + } else + max = dist - 1; + + do + { + ret = mowgli_random_int(self); + } while (ret > max); + + ret %= dist; + + return begin + ret; +} diff --git a/src/libmowgli/mowgli_random.h b/src/libmowgli/mowgli_random.h new file mode 100644 index 0000000..6fb0e61 --- /dev/null +++ b/src/libmowgli/mowgli_random.h @@ -0,0 +1,45 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_random.h: Portable mersinne-twister based psuedo-random number generator. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_RANDOM_H__ +#define __MOWGLI_RANDOM_H__ + +/* mowgli_random_t contains state data which is private */ +struct mowgli_random_; +typedef struct mowgli_random_ mowgli_random_t; + +/* object class initialization. */ +extern void mowgli_random_init(void); + +/* construction and destruction. */ +extern mowgli_random_t *mowgli_random_create(void); +extern mowgli_random_t *mowgli_random_create_with_seed(unsigned int seed); + +/* reset seed */ +extern void mowgli_random_reseed(mowgli_random_t *self, unsigned int seed); + +/* number retrieval */ +extern unsigned int mowgli_random_int(mowgli_random_t *self); +extern int mowgli_random_int_ranged(mowgli_random_t *self, int begin, int end); + +#endif diff --git a/src/libmowgli/mowgli_signal.c b/src/libmowgli/mowgli_signal.c new file mode 100644 index 0000000..3fdd708 --- /dev/null +++ b/src/libmowgli/mowgli_signal.c @@ -0,0 +1,65 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_signal.c: Safe signal handling. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _WIN32 + +#include "mowgli.h" + +static mowgli_signal_handler_t +mowgli_signal_install_handler_full(int signum, mowgli_signal_handler_t handler, + int *sigtoblock, size_t sigtoblocksize) +{ + struct sigaction action, old_action; + size_t i; + + action.sa_handler = handler; + action.sa_flags = SA_RESTART; + + sigemptyset(&action.sa_mask); + + for (i = 0; i < sigtoblocksize; i++) + sigaddset(&action.sa_mask, sigtoblock[i]); + + if (sigaction(signum, &action, &old_action) == -1) + { + mowgli_log("Failed to install signal handler for signal %d", signum); + return NULL; + } + + return old_action.sa_handler; +} + +/* + * A version of signal(2) that works more reliably across different + * platforms. + * + * It restarts interrupted system calls, does not reset the handler, + * and blocks the same signal from within the handler. + */ +mowgli_signal_handler_t +mowgli_signal_install_handler(int signum, mowgli_signal_handler_t handler) +{ + return mowgli_signal_install_handler_full(signum, handler, NULL, 0); +} + +#endif diff --git a/src/libmowgli/mowgli_signal.h b/src/libmowgli/mowgli_signal.h new file mode 100644 index 0000000..cc3db11 --- /dev/null +++ b/src/libmowgli/mowgli_signal.h @@ -0,0 +1,31 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_signal.c: Safe signal handling. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_SIGNAL_H__ +#define __MOWGLI_SIGNAL_H__ + +typedef void (*mowgli_signal_handler_t) (int); + +extern mowgli_signal_handler_t mowgli_signal_install_handler(int signum, mowgli_signal_handler_t handler); + +#endif diff --git a/src/libmowgli/mowgli_spinlock.c b/src/libmowgli/mowgli_spinlock.c new file mode 100644 index 0000000..47c1166 --- /dev/null +++ b/src/libmowgli/mowgli_spinlock.c @@ -0,0 +1,105 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_spinlock.c: Spinlocks. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +mowgli_spinlock_t *mowgli_spinlock_create(void) +{ + mowgli_spinlock_t *out = mowgli_alloc(sizeof(mowgli_spinlock_t)); + + return out; +} + +void mowgli_spinlock_lock(mowgli_spinlock_t *self, void *r, void *w) +{ + return_if_fail(self != NULL); + + if (r) + mowgli_spinlock_wait(self, MOWGLI_SPINLOCK_READ); + + if (w) + mowgli_spinlock_wait(self, MOWGLI_SPINLOCK_WRITE); + + if (r && (self->read_owner == NULL || self->read_owner == r)) + self->read_owner = r; + + if (w && (self->write_owner == NULL || self->write_owner == w)) + self->write_owner = w; +} + +void mowgli_spinlock_unlock(mowgli_spinlock_t *self, void *r, void *w) +{ + return_if_fail(self != NULL); + + if (r && self->read_owner == r) + self->read_owner = NULL; + + if (w && self->write_owner == w) + self->write_owner = NULL; +} + +void mowgli_spinlock_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param) +{ + return_if_fail(self != NULL) + + if (param == MOWGLI_SPINLOCK_READ) + while (self->read_owner != NULL) + usleep(1000); /* XXX: we'll want a more threadsafe function eventually. */ + + if (param == MOWGLI_SPINLOCK_WRITE) + while (self->write_owner != NULL) + usleep(1000); + + if (param == MOWGLI_SPINLOCK_READWRITE) + while (self->write_owner != NULL || self->read_owner != NULL) + usleep(1000); +} + +void mowgli_spinlock_timed_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param, struct timeval *tv) +{ + struct timeval iter = {0}; + + return_if_fail(self != NULL) + return_if_fail(tv != NULL) + + if (param == MOWGLI_SPINLOCK_READ) + while (self->read_owner != NULL && iter.tv_sec < tv->tv_sec && iter.tv_usec < tv->tv_usec) + { + gettimeofday(&iter, NULL); + usleep(1000); /* XXX: we'll want a more threadsafe function eventually. */ + } + + if (param == MOWGLI_SPINLOCK_WRITE) + while (self->write_owner != NULL && iter.tv_sec < tv->tv_sec && iter.tv_usec < tv->tv_usec) + { + gettimeofday(&iter, NULL); + usleep(1000); + } + + if (param == MOWGLI_SPINLOCK_READWRITE) + while ((self->write_owner != NULL || self->read_owner != NULL) && iter.tv_sec < tv->tv_sec && iter.tv_usec < tv->tv_usec) + { + gettimeofday(&iter, NULL); + usleep(1000); + } +} diff --git a/src/libmowgli/mowgli_spinlock.h b/src/libmowgli/mowgli_spinlock.h new file mode 100644 index 0000000..6742e13 --- /dev/null +++ b/src/libmowgli/mowgli_spinlock.h @@ -0,0 +1,44 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_spinlock.h: Spinlocks. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_SPINLOCK_H__ +#define __MOWGLI_SPINLOCK_H__ + +typedef struct { + void *read_owner; /* opaque data representing a spinlock's owner */ + void *write_owner; /* opaque data representing a spinlock's owner */ +} mowgli_spinlock_t; + +typedef enum { + MOWGLI_SPINLOCK_READ, + MOWGLI_SPINLOCK_WRITE, + MOWGLI_SPINLOCK_READWRITE +} mowgli_spinlock_lock_param_t; + +extern mowgli_spinlock_t *mowgli_spinlock_create(void); +extern void mowgli_spinlock_lock(mowgli_spinlock_t *self, void *r, void *w); +extern void mowgli_spinlock_unlock(mowgli_spinlock_t *self, void *r, void *w); +extern void mowgli_spinlock_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param); +extern void mowgli_spinlock_timed_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param, struct timeval *tv); + +#endif diff --git a/src/libmowgli/mowgli_stdinc.h b/src/libmowgli/mowgli_stdinc.h new file mode 100644 index 0000000..ae64a22 --- /dev/null +++ b/src/libmowgli/mowgli_stdinc.h @@ -0,0 +1,96 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_stdinc.h: Pulls in the base system includes for libmowgli. + * + * Copyright (c) 2007 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_STDINC_H__ +#define __MOWGLI_STDINC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* socket stuff */ +#ifndef _WIN32 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +#endif + +#include + +#ifdef _MSC_VER +# pragma warning (disable: 4996) +#endif + +#ifdef FALSE +# undef FALSE +#endif + +#ifdef TRUE +# undef TRUE +#endif + +typedef enum { FALSE, TRUE } mowgli_boolean_t; + +/* Macros for min/max. */ +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#if defined(__GNUC__) || defined(_INTEL_COMPILER) +#define MOWGLI_DEPRECATED \ + __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define MOWGLI_DEPRECATED \ + __declspec(deprecated) +#else +#define MOWGLI_DEPRECATED +#endif + +#endif diff --git a/src/libmowgli/mowgli_string.c b/src/libmowgli/mowgli_string.c new file mode 100644 index 0000000..9c9d5c2 --- /dev/null +++ b/src/libmowgli/mowgli_string.c @@ -0,0 +1,121 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_string.c: Immutable string buffers with cheap manipulation. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007 Pippijn van Steenhoven + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +mowgli_string_t *mowgli_string_create(void) +{ + mowgli_string_t *self = mowgli_alloc(sizeof(mowgli_string_t)); + + self->size = 64; + self->pos = 0; + self->str = mowgli_alloc(self->size); + + self->append = &mowgli_string_append; + self->append_char = &mowgli_string_append_char; + self->reset = &mowgli_string_reset; + self->destroy = &mowgli_string_destroy; + + return self; +} + +void mowgli_string_reset(mowgli_string_t *self) +{ + return_if_fail(self != NULL); + + self->str[0] = self->pos = 0; +} + +void mowgli_string_destroy(mowgli_string_t *self) +{ + return_if_fail(self != NULL); + + mowgli_free(self->str); + mowgli_free(self); +} + +void mowgli_string_append(mowgli_string_t *self, const char *src, size_t n) +{ + if (self->size - self->pos <= n) + { + char *new; + + self->size = MAX(self->size * 2, self->pos + n + 8); + new = realloc(self->str, self->size); + self->str = new; + } + + memcpy(self->str + self->pos, src, n); + self->pos += n; + self->str[self->pos] = 0; +} + +void mowgli_string_append_char(mowgli_string_t *self, const char c) +{ + if (self->size - self->pos <= 1) + { + char *new; + + self->size = MAX(self->size * 2, self->pos + 9); + new = realloc(self->str, self->size); + self->str = new; + } + + self->str[self->pos++] = c; + self->str[self->pos] = 0; +} + +/* These functions are taken from Linux. */ +size_t mowgli_strlcat(char *dest, const char *src, size_t count) +{ + size_t dsize = strlen(dest); + size_t len = strlen(src); + size_t res = dsize + len; + + dest += dsize; + count -= dsize; + + if (len >= count) + len = count - 1; + + memcpy(dest, src, len); + + dest[len] = 0; + + return res; +} + +size_t mowgli_strlcpy(char *dest, const char *src, size_t size) +{ + size_t ret = strlen(src); + + if (size) + { + size_t len = (ret >= size) ? size - 1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + + return ret; +} diff --git a/src/libmowgli/mowgli_string.h b/src/libmowgli/mowgli_string.h new file mode 100644 index 0000000..b815451 --- /dev/null +++ b/src/libmowgli/mowgli_string.h @@ -0,0 +1,48 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mowgli_string.h: Immutable string buffers with cheap manipulation. + * + * Copyright (c) 2007 William Pitcock + * Copyright (c) 2007 Pippijn van Steenhoven + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_STRING_H__ +#define __MOWGLI_STRING_H__ + +typedef struct mowgli_string_ { + char *str; + size_t pos; + size_t size; + + void (*reset)(struct mowgli_string_ *self); + void (*append)(struct mowgli_string_ *self, const char *src, size_t n); + void (*append_char)(struct mowgli_string_ *self, const char c); + void (*destroy)(struct mowgli_string_ *self); +} mowgli_string_t; + +extern mowgli_string_t *mowgli_string_create(void); +extern void mowgli_string_reset(mowgli_string_t *self); +extern void mowgli_string_destroy(mowgli_string_t *self); +extern void mowgli_string_append(mowgli_string_t *self, const char *src, size_t n); +extern void mowgli_string_append_char(mowgli_string_t *self, const char c); + +extern size_t mowgli_strlcat(char *dest, const char *src, size_t count); +extern size_t mowgli_strlcpy(char *dest, const char *src, size_t count); + +#endif diff --git a/src/libmowgli/win32_support.c b/src/libmowgli/win32_support.c new file mode 100644 index 0000000..da6344f --- /dev/null +++ b/src/libmowgli/win32_support.c @@ -0,0 +1,64 @@ +/* + * libmowgli: A collection of useful routines for programming. + * win32_support.c: Support functions and values for Win32 platform. + * + * Copyright (c) 2009 SystemInPlace, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef _MSC_VER +# define EPOCH_TIME_IN_MICROSECS 11644473600000000Ui64 +#else +# define EPOCH_TIME_IN_MICROSECS 11644473600000000ULL +#endif + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + ULARGE_INTEGER tmpres = { 0 }; + static mowgli_boolean_t tz_init_done = FALSE; + + if (tv != NULL) + { + GetSystemTimeAsFileTime(&ft); + + tmpres.u.HighPart = ft.dwHighDateTime; + tmpres.u.LowPart = ft.dwLowDateTime; + + tmpres.QuadPart /= 10; + tmpres.QuadPart -= EPOCH_TIME_IN_MICROSECS; + tv->tv_sec = (long) (tmpres.QuadPart / 1000000UL); + tv->tv_usec = (long) (tmpres.QuadPart % 1000000UL); + } + + if (tz != NULL) + { + if (!tz_init_done) + { + _tzset(); + tz_init_done = TRUE; + } + + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} diff --git a/src/libmowgli/win32_support.h b/src/libmowgli/win32_support.h new file mode 100644 index 0000000..c87c643 --- /dev/null +++ b/src/libmowgli/win32_support.h @@ -0,0 +1,47 @@ +/* + * libmowgli: A collection of useful routines for programming. + * win32_support.h: Support functions and values for Win32 platform. + * + * Copyright (c) 2009 SystemInPlace, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LIBMOWGLI_SRC_LIBMOWGLI_WIN32_SUPPORT_H__GUARD +#define __LIBMOWGLI_SRC_LIBMOWGLI_WIN32_SUPPORT_H__GUARD + +#ifdef _WIN32 + +#include // just for struct timeval declaration +#include + +#define strcasecmp _stricmp +#define strdup _strdup +#define usleep(_usecs) Sleep((_usecs)/1000L) +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +extern int gettimeofday(struct timeval *tv, struct timezone *tz); + +#endif + +#endif -- cgit v1.2.3