summaryrefslogtreecommitdiffstats
path: root/tinySAK/src/tsk_object.h
blob: 51f892a793183398d7a136bc95135feae6100a34 (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
/* Copyright (C) 2010-2013 Mamadou Diop.
* Copyright (C) 2013 Doubango Telecom <http://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.h
 * @brief Base object implementation.
 */
#ifndef TSK_OBJECT_H
#define TSK_OBJECT_H

#include "tinysak_config.h"

#include <stdarg.h>
#include <stdio.h>

TSK_BEGIN_DECLS

#define TSK_OBJECT(self) ((tsk_object_t*)(self))

/**@ingroup tsk_object_group
* Plain object.
*/
typedef void tsk_object_t;

/**@ingroup tsk_object_group
* @def TSK_OBJECT_SAFE_FREE
* Safely free any well-defined object. If the reference count of the object was equal to 1 then this
 * 	object will be freed otherwise the refrence counter will be decremented. 
 *	In all case this operation will set the pointer (the object itself) to NULL.<br>
 * <b>Very Important</b>: Mutexes, Semaphores and CondVars are not well-defined objects. You should never use this macro to destroy them.
 * @param	self	The object to free or unref. 
**/
#define TSK_OBJECT_SAFE_FREE(self)		if((self)) tsk_object_unref((self)), (self) = tsk_null

#define TSK_OBJECT_SAFE_FREE_ARRAY(self, count) { \
	int __i; \
	for(__i = 0; __i < (count); ++__i) \
		TSK_OBJECT_SAFE_FREE((self)[__i]); \
}
#define TSK_OBJECT_SAFE_FREE_TABLE(self) TSK_OBJECT_SAFE_FREE_ARRAY((self), (sizeof((self))/sizeof((self)[0])))

/**@ingroup tsk_object_group
* tag a structure as an object. If this macro is used then you MUST
* provide a constructor and a destructor functions into an object definition (or meta-data).
* @ref tsk_object_new or @ref tsk_object_new_2 are used to create the object and  @ref tsk_object_unref or @ref tsk_object_delete to destroy it.
* @code
* typedef struct person_s{
*	TSK_DECLARE_OBJECT;
*	int id;
*	char* firstName;
*	char* lastName;
* } person_t;
* @endcode
* To create the object:
* @code
* // person_def_t: See bellow to understand how to create an object definition.
* person_t* person = tsk_object_new(person_def_t, "My First Name", "My last Name");
* @endcode
* To safely free the object:
* @code
* TSK_OBJECT_SAFE_FREE(person);
* @endcode
*/
#define TSK_DECLARE_OBJECT \
	const void* __def__;  /**< Opaque data holding a pointer to the actual meta-data(size, constructor, destructor and comparator) */ \
	volatile long	refCount /**< Reference counter. */

/**@ingroup tsk_object_group
* Internal macro to get the definition of the object.
*/
#define TSK_OBJECT_DEF(self)			((const tsk_object_def_t*)self)

/** Object meta-data (definition) */
typedef struct tsk_object_header_s{
	TSK_DECLARE_OBJECT;
}
tsk_object_header_t;
#define TSK_OBJECT_HEADER(object)	((tsk_object_header_t*)object)

/**@ingroup tsk_object_group
* Meta-data used of define an object.
* You MUST provide at least a constructor and a destructor. The comparator should
* be provided if you would like to compare opaque object or sort linked lists.
* @code
*
* // constructor
* static void* person_create(tsk_object_t * self, va_list * app)
* {
* 	static int unique_id = 0;
* 	person_t *person = self;
* 	if(person){
* 		person->id = ++unique_id;
* 		person->firstName = tsk_strdup(va_arg(*app, const char *));
* 		person->lastName = tsk_strdup(va_arg(*app, const char *));
* 	}
* 	return self;
* }
* 
* // destructor
* static void* person_destroy(tsk_object_t * self)
* { 
* 	person_t *person = self;
* 	if(person){
* 		TSK_FREE(person->firstName);
* 		TSK_FREE(person->lastName);
* 	}
* 	return self;
* }
* 
* // comparator
* static int person_cmp(const tsk_object_t *object1, const tsk_object_t *object1)
* {
* 	const person_t *person1 = object1;
* 	const person_t *person2 = object2;
* 
* 	return (person1 && person2) ? (person1->id - person2->id) : -1;
* }
*
* // Meta-data (Object defnition)
* static const tsk_object_def_t person_def_s = 
* {
* 	sizeof(person_t),
* 	person_create,
* 	person_destroy,
* 	person_cmp, 
* }person_def_t;
* 
* @endcode
* Now, to create your object:
* @code
* person_t* person = tsk_object_new(person_def_t, "My First Name", "My last Name"); // Will call "person_create" function.
* @endcode
* Or
* @code
* #define PERSON_CREATE(firstName, lastName) tsk_object_new(person_def_t, firstName, lastName)
* person_t* person = PERSON_CREATE("My First Name", "My last Name") // For clarity, this form will be used in all projects declared using @ref TSK_DECLARE_OBJECT.
* @endcode
* To safely free your object:
* @code
* TSK_OBJECT_SAFE_FREE(person); // Will call "person_destroy" function.
* @endcode
*/
typedef struct tsk_object_def_s
{
	//! The size of the object.
	tsk_size_t size;
	//! Pointer to the constructor.
	tsk_object_t*	(* constructor) (tsk_object_t *, va_list *);
	//! Pointer to the destructor.
	tsk_object_t*	(* destructor) (tsk_object_t *);
	//! Pointer to the comparator.
	int		(* comparator) (const tsk_object_t *, const tsk_object_t *);
}
tsk_object_def_t;

TINYSAK_API tsk_object_t* tsk_object_new(const tsk_object_def_t *objdef, ...);
TINYSAK_API tsk_object_t* tsk_object_new_2(const tsk_object_def_t *objdef, va_list* ap);
TINYSAK_API tsk_size_t tsk_object_sizeof(const tsk_object_t *);
TINYSAK_API int tsk_object_cmp(const void *self, const tsk_object_t *object);
TINYSAK_API tsk_object_t* tsk_object_ref(tsk_object_t *self);
TINYSAK_API tsk_object_t* tsk_object_unref(tsk_object_t *self);
TINYSAK_API tsk_size_t tsk_object_get_refcount(tsk_object_t *self);
TINYSAK_API void tsk_object_delete(tsk_object_t *self);

TSK_END_DECLS

#endif /* TSK_OBJECT_H */

OpenPOWER on IntegriCloud