diff options
Diffstat (limited to 'src/libmowgli/object/class.c')
-rw-r--r-- | src/libmowgli/object/class.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/libmowgli/object/class.c b/src/libmowgli/object/class.c new file mode 100644 index 0000000..9bddf79 --- /dev/null +++ b/src/libmowgli/object/class.c @@ -0,0 +1,131 @@ +/* + * libmowgli: A collection of useful routines for programming. + * class.c: Object class and type management, cast checking. + * + * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * + * 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 = mowgli_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); +} |