summaryrefslogtreecommitdiffstats
path: root/tinySAK/src/tsk_object.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinySAK/src/tsk_object.c')
-rw-r--r--tinySAK/src/tsk_object.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/tinySAK/src/tsk_object.c b/tinySAK/src/tsk_object.c
new file mode 100644
index 0000000..36984bf
--- /dev/null
+++ b/tinySAK/src/tsk_object.c
@@ -0,0 +1,224 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tsk_object.c
+ * @brief Base object implementation.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tsk_object.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+#include "tsk_common.h"
+
+/**@defgroup tsk_object_group Base object implementation.
+* @brief Provides utility functions to ease Object Oriented Programming in C.
+*/
+
+#if defined (_DEBUG) || defined (DEBUG)
+# define TSK_DEBUG_OBJECTS 0
+static int tsk_objects_count = 0;
+#else
+# define TSK_DEBUG_OBJECTS 0
+#endif
+
+/** Object meta-data (definition).
+*/
+typedef struct tsk_object_header_s{
+ const void* base; /**< Opaque data holding a pointer to the actual meta-data(size, constructor, destructor and comparator) */
+ int refCount; /**< Reference counter. */
+}
+tsk_object_header_t;
+#define TSK_OBJECT_HEADER(object) ((tsk_object_header_t*)object)
+
+/**@ingroup tsk_object_group
+* Creates new object. The object MUST be declared using @ref TSK_DECLARE_OBJECT macro.
+* @param objdef The object meta-data (definition). For more infomation see @ref tsk_object_def_t.
+* @param ... List of parameters to pass to the constructor(defined in the meta-data).
+* @retval @ref tsk_object_t object with a reference counter equal to 1.
+* @sa @ref tsk_object_new_2.
+*/
+tsk_object_t* tsk_object_new(const tsk_object_def_t *objdef, ...)
+{
+ // Do not check "objdef", let the application die if it's null
+ tsk_object_t *newobj = tsk_calloc(1, objdef->size);
+ if(newobj){
+ (*(const tsk_object_def_t **) newobj) = objdef;
+ TSK_OBJECT_HEADER(newobj)->refCount = 1;
+ if(objdef->constructor){
+ va_list ap;
+ va_start(ap, objdef);
+ newobj = objdef->constructor(newobj, &ap);
+ va_end(ap);
+
+#if TSK_DEBUG_OBJECTS
+ TSK_DEBUG_INFO("N∞ objects:%d", ++tsk_objects_count);
+#endif
+ }
+ else{
+ TSK_DEBUG_WARN("No constructor found.");
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create new tsk_object.");
+ }
+
+ return newobj;
+}
+
+/**@ingroup tsk_object_group
+* Creates new object. The object MUST be declared using @ref TSK_DECLARE_OBJECT macro.
+* @param objdef The object meta-data (definition). For more infomation see @ref tsk_object_def_t.
+* @param ap Variable argument list to pass to the constructor(defined in the meta-data).
+* @retval @ref tsk_object_t object with a reference counter equal to 1.
+* @sa @ref tsk_object_new.
+*/
+tsk_object_t* tsk_object_new_2(const tsk_object_def_t *objdef, va_list* ap)
+{
+ tsk_object_t *newobj = tsk_calloc(1, objdef->size);
+ if(newobj){
+ (*(const tsk_object_def_t **) newobj) = objdef;
+ TSK_OBJECT_HEADER(newobj)->refCount = 1;
+ if(objdef->constructor){
+ newobj = objdef->constructor(newobj, ap);
+
+#if TSK_DEBUG_OBJECTS
+ TSK_DEBUG_INFO("N∞ objects:%d", ++tsk_objects_count);
+#endif
+ }
+ else{
+ TSK_DEBUG_WARN("No constructor found.");
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create new tsk_object.");
+ }
+
+ return newobj;
+}
+
+/**@ingroup tsk_object_group
+* Gets the size of an opaque object.
+* @param self The object for which we want to get the size.
+* The object MUST be declared using @ref TSK_DECLARE_OBJECT macro and created using @ref tsk_object_new or @ref tsk_object_new_2.
+* @retval The size of the object.
+*/
+tsk_size_t tsk_object_sizeof(const tsk_object_t *self)
+{
+ const tsk_object_def_t **objdef = (const tsk_object_def_t **)self;
+ if(objdef && *objdef){
+ return (*objdef)->size;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL object definition.");
+ return 0;
+ }
+}
+
+/**@ingroup tsk_object_group
+* Compares two well-defined objects.
+* If the meta-data (definition) of the first object (@a object1) do not include a function comparator then this method will amlways return -1.
+* @param object1 The first object to compare.
+* @param object2 The second object to compare.
+* @retval Zero if the two object are equal.
+* Positive value if @a object1 is greater than @a object2 and a negative value otherwise.
+*/
+int tsk_object_cmp(const tsk_object_t *object1, const tsk_object_t *object2)
+{
+ const tsk_object_def_t **objdef = (const tsk_object_def_t **)object1;
+
+ if(objdef && *objdef && (*objdef)->comparator){
+ return (*objdef)->comparator(object1, object2);
+ }
+ return -1;
+}
+
+/**@ingroup tsk_object_group
+* Increment the refrence counting of the object.<br>
+* Refernce counting: http://en.wikipedia.org/wiki/Reference_counting.<br>
+* The object MUST be declared using @ref TSK_DECLARE_OBJECT macro and created using @ref tsk_object_new or @ref tsk_object_new_2.
+* @param self The object holding the counter to increment.
+* @retval The new object (incremented).
+* @sa tsk_object_unref.
+*/
+tsk_object_t* tsk_object_ref(tsk_object_t *self)
+{
+ tsk_object_header_t* objhdr = TSK_OBJECT_HEADER(self);
+ if(objhdr && objhdr->refCount){
+ objhdr->refCount++;
+ return self;
+ }
+ return tsk_null;
+}
+
+/**@ingroup tsk_object_group
+* Decrement the refrence counting of the object.<br>
+* Refernce counting: http://en.wikipedia.org/wiki/Reference_counting.<br>
+* The object MUST be declared using @ref TSK_DECLARE_OBJECT macro and created using @ref tsk_object_new or @ref tsk_object_new_2.
+* @param self The object holding the counter to decrement.
+* @retval If the refernce counter is equal to zero then NULL is returned otherwise a new object (decremented) is returned.
+* @sa ref tsk_object_ref.
+* @sa ref TSK_OBJECT_SAFE_FREE.
+*/
+tsk_object_t* tsk_object_unref(tsk_object_t *self)
+{
+ if(self){
+ tsk_object_header_t* objhdr = TSK_OBJECT_HEADER(self);
+ if(objhdr->refCount){ // If refCount is == 0 then, nothing should happen.
+ if(!--objhdr->refCount){
+ tsk_object_delete(self);
+ return tsk_null;
+ }
+ }
+ else{
+ return tsk_null;
+ }
+ }
+ return self;
+}
+
+/**@ingroup tsk_object_group
+* Delete an object. This function will delete the object even if it's reference counter is greater than 1.
+* This mean that this function is not safe. You should use @ref TSK_OBJECT_SAFE_FREE to safely delete an object.
+* The object MUST be declared using @ref TSK_DECLARE_OBJECT macro and created using @ref tsk_object_new or @ref tsk_object_new_2.
+* @param self The object to delete.
+* @sa @ref TSK_OBJECT_SAFE_FREE.
+*/
+void tsk_object_delete(tsk_object_t *self)
+{
+ const tsk_object_def_t ** objdef = self;
+ if(self && *objdef){
+ if((*objdef)->destructor){
+ self = (*objdef)->destructor(self);
+#if TSK_DEBUG_OBJECTS
+ TSK_DEBUG_INFO("N∞ objects:%d", --tsk_objects_count);
+#endif
+ }
+ else{
+ TSK_DEBUG_WARN("No destructor found.");
+ }
+ free(self);
+ }
+}
+
OpenPOWER on IntegriCloud