libtrbase
1.0.2
Web server and task management solution.
Main Page
Related Pages
Data Structures
Files
File List
Globals
class.h
Go to the documentation of this file.
1
/**
2
* \file
3
* My own class implementation for C. It combines a data structure with
4
* a set of interfaces. Each interface is another structure containing
5
* one or more function pointers to concrete implementations of this
6
* interface for the defined class.
7
*
8
* To each interface a set of caller functions exist, that take an instance
9
* of an object and then in turn call the implementation for the class of
10
* this object. If there is none within the class it looks into its
11
* parent class and so forth.
12
*
13
* This is somewhat similar to late binding in real OOP languages, but
14
* by far not so elaborated. This is not a real object oriented language
15
* and will surely never ever provide all features these have.
16
*
17
* That said it has proven very usefull for me to orgnize code and prevent
18
* code duplication.
19
*
20
* \author Georg Hopp
21
*
22
* \copyright
23
* Copyright © 2014 Georg Hopp
24
*
25
* This program is free software: you can redistribute it and/or modify
26
* it under the terms of the GNU General Public License as published by
27
* the Free Software Foundation, either version 3 of the License, or
28
* (at your option) any later version.
29
*
30
* This program is distributed in the hope that it will be useful,
31
* but WITHOUT ANY WARRANTY; without even the implied warranty of
32
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
* GNU General Public License for more details.
34
*
35
* You should have received a copy of the GNU General Public License
36
* along with this program. If not, see <http://www.gnu.org/licenses/>.
37
*/
38
#ifndef __TR_CLASS_CLASS_H__
39
#define __TR_CLASS_CLASS_H__
40
41
#include <stdarg.h>
42
#include <sys/types.h>
43
#include <string.h>
44
#include <assert.h>
45
46
#include "
tr/interface.h
"
47
48
/** \cond PRIVATE */
49
#ifndef _ISOC99_SOURCE
50
#define _ISOC99_SOURCE
51
#endif
52
/** \endcond */
53
54
/**
55
* A magic number that identifies instances of a TR_CLASS class.
56
*/
57
#define TR_CLASS_MAGIC 0xFEFE
58
59
/**
60
* Class declaration macro. This one declares all structures
61
* that are needed to create a new class.
62
*/
63
#define TR_CLASS(name) \
64
extern struct TR_class c_##name; \
65
struct c_##name; \
66
typedef struct c_##name * name; \
67
extern struct TR_class * const _##name; \
68
struct c_##name
69
70
#define TR_INSTANCE_INIT(name) \
71
struct c_##name##_object { \
72
void * TR_class; \
73
struct c_##name data; \
74
}
75
76
#define TR_CLASSVARS_DECL(name) struct c_##name##_vars
77
#define TR_CLASSVARS(name, class) ((struct c_##name##_vars *)(class)->vars)
78
#define TR_CLASSVARS_BY_NAME(name) \
79
((struct c_##name##_vars *)(TR_CLASS_BY_NAME(name))->vars)
80
#define TR_CLASSVARS_STATIC(name) \
81
((struct c_##name##_vars *)(TR_CLASS_BY_NAME_STATIC(name))->vars)
82
83
#define TR_INHERIT_CLASSVARS(dest, src) \
84
memcpy(TR_CLASSVARS_BY_NAME(dest), \
85
TR_CLASSVARS_BY_NAME(src), \
86
sizeof(TR_CLASSVARS_DECL(src)))
87
88
89
/**
90
* Make the new class a child of an existing class.
91
* This is used within the class declaration and can
92
* only be used once. If you do it twice the behaviour
93
* is undefined, but most likely the resulting code won't
94
* even compile.
95
*/
96
#define TR_EXTENDS(parent) const char _[sizeof(struct c_##parent)]
97
#define TR_CV_EXTENDS(parent) struct c_##parent##_vars _
98
99
/**
100
* Some macros might translate a give NULL to _NULL,
101
* this should in turn be a real NULL again.
102
*/
103
#define _NULL NULL
104
105
/**
106
* This will create a new class which previously has
107
* to be defined by TR_CLASS.
108
* This makro will create static variables and functions
109
* used to manage and controll the new class (and its
110
* instances.)
111
* Especially it creates and initializes tha class
112
* structure for this class. This structure contains all
113
* the meta informations of the new class. These are
114
* it's members as well as its interface implementations.
115
* Each class must at least provide an implementation
116
* for the ctor interface else no instances can be
117
* created.
118
*/
119
#define TR_CREATE_CLASS(name,_parent,cvInit,...) \
120
struct c_##name##_vars _##name##_vars; \
121
void (* TR_initClassVars##name)(TR_class_ptr) = cvInit; \
122
static TR_class_ptr _classInit##name##_(void) { \
123
c_##name.init = NULL; \
124
c_##name.parent = _##_parent; \
125
if (TR_initClassVars##name) \
126
TR_initClassVars##name(_##name); \
127
return &c_##name; \
128
}; \
129
struct TR_class c_##name = { \
130
TR_CLASS_MAGIC, \
131
NULL, \
132
sizeof(struct c_##name), \
133
_classInit##name##_, \
134
&_##name##_vars, \
135
TR_INIT_IFACE_IMPL(__VA_ARGS__) \
136
}; \
137
struct TR_class * const _##name = &c_##name; \
138
struct c_##name##_vars _##name##_vars
139
140
/**
141
* Create a static instance of a class.
142
* This is new and currently it is only possible to create
143
* instances for class that does not need a constructor.
144
*
145
* This does not call any constructor with any value...this
146
* has to be fixed. // When this macro is used within a global
147
* (static) context this can't be fixed. No function can be
148
* called from there. Instead I add a TR_objectInit function which
149
* takes an object name (created on either the stack or the
150
* heap) and a variable argument list and calls its constructor
151
* with the arguments.
152
*/
153
#define TR_INSTANCE(class, name, ...) \
154
struct c_##class##_object _##name; \
155
class name = &(_##name.data); \
156
struct c_##class##_object _##name = { \
157
&c_##class, \
158
{ __VA_ARGS__ } \
159
}
160
161
#define TR_INSTANCE_CAST(class, name) ((class)&(_##name.data))
162
163
/**
164
* I initialize _ (the class's base or parent class)
165
* with the identifier of that class.
166
* This identifier is not static and thus can't be used
167
* for a static initialization. As a workaround, until I
168
* find a better solution I create an initialization function
169
* with each class, that will be called once as soon as
170
* an interface implementation will be called. In any case
171
* this is a call to the constructor of this class.
172
* Well, not in any...if I remember correct the static
173
* instance does not call anything at all...
174
*
175
* \cond PRIVATE
176
*/
177
#define TR_INIT_CLASS(class) \
178
((class)->init? (class)->init() : (class))
179
/** \endcond */
180
181
/**
182
* Returns the pointer to the class structure of the given object.
183
* The class structure is the structure that contains all the
184
* metainformations about our class.
185
*
186
* \see TR_CREATE_CLASS
187
*/
188
#define TR_GET_CLASS(object) \
189
(TR_INIT_CLASS(*(TR_class_ptr *)((void*)(object) - sizeof(void*))))
190
191
#define TR_CLASS_BY_NAME(class_name) (TR_INIT_CLASS(& c_##class_name))
192
#define TR_CLASS_BY_NAME_STATIC(class_name) (& c_##class_name)
193
194
/**
195
* Returns this class's implementations of the interface
196
* identified by iface.
197
*/
198
#define TR_IFACE_GET(class,iface) \
199
(TR_interfaceGet(&((class)->impl),(iface)))
200
201
/**
202
* Check if the given class is a child of any base class.
203
* That is it has an TR_EXTENDS expression whithin its declaration.
204
*
205
* \see TR_EXTENDS
206
*/
207
#define TR_HAS_PARENT(class) \
208
(NULL != ((class)->parent) && TR_INIT_CLASS((class)->parent))
209
210
/**
211
* Check if obj really points to a class instance.
212
*
213
* /see TR_CLASS_MAGIC
214
*/
215
#define TR_IS_OBJECT(obj) \
216
((TR_GET_CLASS((obj)))->magic == TR_CLASS_MAGIC)
217
218
/**
219
* Check of obj points to an instance of class.
220
*/
221
#define TR_INSTANCE_OF(class,obj) \
222
((TR_GET_CLASS((obj))) == _##class)
223
224
/**
225
* Call the class's implementation for the given method of the
226
* given interface _iface.
227
* For this the makro searches through all interfaces defined within
228
* a class for the correct one...from a performance aspect this might
229
* not be ideal but on the other hand...we don't expect more than a
230
* hand full of interfaces per class.
231
*
232
* \cond PRIVATE
233
*/
234
#define _TR_CALL(_class,_iface,method) \
235
do { \
236
TR_class_ptr class = _class; \
237
iface = (struct i_##_iface *)TR_IFACE_GET(class, &i_##_iface); \
238
while ((NULL == iface || \
239
NULL == iface->method) && TR_HAS_PARENT(class)) { \
240
class = class->parent; \
241
iface = (struct i_##_iface *)TR_IFACE_GET(class, &i_##_iface); \
242
} \
243
assert(NULL != iface->method); \
244
} while(0)
245
/** \endcond */
246
247
/**
248
* Call the class's implementation for the given method of the
249
* given interface _iface. This one does not handle a return
250
* value of the called implementation and as such is only suitable
251
* if there is no return value or you are not interested in it.
252
*
253
* \todo actually i use gcc feature ## for variadoc... think about
254
* a way to make this standard.
255
*/
256
#define TR_CALL(object,_iface,method,...) \
257
do { \
258
struct i_##_iface * iface; \
259
_TR_CALL(TR_GET_CLASS(object), _iface, method); \
260
iface->method(object, ##__VA_ARGS__); \
261
} while(0)
262
263
/**
264
* Call the class's implementation for the given method of the
265
* given interface _iface. The return value of the function is assigned
266
* to ret.
267
*
268
* \see TR_CALL
269
*/
270
#define TR_RETCALL(object,_iface,method,ret,...) \
271
do { \
272
struct i_##_iface * iface; \
273
_TR_CALL(TR_GET_CLASS(object), _iface, method); \
274
ret = iface->method(object, ##__VA_ARGS__); \
275
} while(0)
276
277
/**
278
* Like call but this calls the implementation of the direct parent
279
* class of this object.
280
*
281
* \see TR_CALL
282
*/
283
#define TR_PARENTCALL(class, object,_iface,method,...) \
284
do { \
285
struct i_##_iface * iface; \
286
TR_class_ptr pc_class = TR_CLASS_BY_NAME(class); \
287
assert(TR_HAS_PARENT(pc_class)); \
288
_TR_CALL(pc_class->parent, _iface, method); \
289
iface->method(object, ##__VA_ARGS__); \
290
} while(0)
291
292
/*
293
* Like retcall but this calls the implementation of the direct parent
294
* class of this object.
295
*
296
* \see TR_RETCALL
297
*/
298
#define TR_PARENTRETCALL(class, object,_iface,method,ret,...) \
299
do { \
300
struct i_##_iface * iface; \
301
TR_class_ptr pc_class = TR_CLASS_BY_NAME(class); \
302
assert(TR_HAS_PARENT(pc_class)); \
303
_TR_CALL(pc_class->parent, _iface, method); \
304
ret = iface->method(object, ##__VA_ARGS__); \
305
} while(0)
306
307
308
/**
309
* Definition of the metadata structures and symbols used to
310
* manage classe.
311
*
312
* \cond PRIVATE
313
*/
314
struct
TR_class;
315
typedef
struct
TR_class * TR_class_ptr;
316
typedef
TR_class_ptr (* TR_fptr_classInit)(void);
317
struct
TR_class {
318
const
int
magic;
319
TR_class_ptr parent;
320
size_t
object_size;
321
TR_fptr_classInit init;
322
void
* vars;
323
struct
TR_iface_impl impl;
324
};
325
/** \endcond */
326
327
#endif // __TR_CLASS_CLASS_H__
328
329
// vim: set ts=4 sw=4:
interface.h
include
tr
class.h
Generated on Tue Apr 12 2016 10:15:56 for libtrbase by
1.8.10