summaryrefslogtreecommitdiffstats
path: root/tinySAK/src/tsk_object.c
blob: 36984bf28428132c1fe108d86f487b10fc6e9bd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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