1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2014.  ALL RIGHTS RESERVED.
3 *
4 * See file LICENSE for terms.
5 */
6 
7 #ifndef UCS_OBJECT_H_
8 #define UCS_OBJECT_H_
9 
10 #include <ucs/sys/compiler_def.h>
11 #include <ucs/sys/preprocessor.h>
12 #include <ucs/type/status.h>
13 #include <stddef.h>
14 
15 BEGIN_C_DECLS
16 
17 /** @file class.h */
18 
19 typedef struct ucs_class     ucs_class_t;
20 
21 
22 typedef ucs_status_t (*ucs_class_init_func_t)   (void *self, ...);
23 typedef void         (*ucs_class_cleanup_func_t)(void *self);
24 
25 struct ucs_class {
26     const char               *name;
27     size_t                   size;
28     ucs_class_t              *superclass;
29     ucs_class_init_func_t    init;
30     ucs_class_cleanup_func_t cleanup;
31 };
32 
33 
34 /*
35  * Helper: Define names of class-related identifiers.
36  */
37 #define UCS_CLASS_DECL_NAME(_type) \
38     _UCS_CLASS_DECL_NAME(_type)
39 #define _UCS_CLASS_DECL_NAME(_type) \
40     UCS_PP_TOKENPASTE(_type, _class)
41 #define _UCS_CLASS_INIT_NAME(_type) \
42     UCS_PP_TOKENPASTE(_type, _init)
43 #define _UCS_CLASS_CLEANUP_NAME(_type) \
44     UCS_PP_TOKENPASTE(_type, _cleanup)
45 
46 /**
47  * Class initialization/cleanup function prototypes.
48  */
49 #define UCS_CLASS_INIT_FUNC(_type, ...) \
50     ucs_status_t _UCS_CLASS_INIT_NAME(_type)(_type *self, ucs_class_t *_myclass, \
51                                              int *_init_count, ## __VA_ARGS__)
52 #define UCS_CLASS_CLEANUP_FUNC(_type) \
53     void _UCS_CLASS_CLEANUP_NAME(_type)(_type *self)
54 
55 
56 /**
57  * Declare a class.
58  *
59  * @param _type     Class type.
60  */
61 #define UCS_CLASS_DECLARE(_type, ...) \
62     extern ucs_class_t _UCS_CLASS_DECL_NAME(_type); \
63     UCS_CLASS_INIT_FUNC(_type, ## __VA_ARGS__);
64 
65 #define UCS_CLASS_NAME(_type) \
66     _UCS_CLASS_DECL_NAME(_type)
67 
68 /**
69  * Define a class.
70  *
71  * @param _type     Class type.
72  * @param _super    Superclass type (may be void to indicate top-level class)
73  */
74 #define UCS_CLASS_DEFINE(_type, _super) \
75     extern ucs_class_t _UCS_CLASS_DECL_NAME(_super); \
76     ucs_class_t _UCS_CLASS_DECL_NAME(_type) = { \
77         UCS_PP_QUOTE(_type), \
78         sizeof(_type), \
79         &_UCS_CLASS_DECL_NAME(_super), \
80         (ucs_class_init_func_t)(_UCS_CLASS_INIT_NAME(_type)), \
81         (ucs_class_cleanup_func_t)(_UCS_CLASS_CLEANUP_NAME(_type)) \
82     };
83 
84 
85 /**
86  * Initialize a class in-place.
87  *
88  * @param _type  Class type.
89  * @param _obj   Instance pointer to initialize.
90  * @param ...    Additional arguments to the constructor.
91  *
92  * @return UCS_OK, or error code if failed.
93  */
94 #define UCS_CLASS_INIT(_type, _obj, ...) \
95     ({ \
96         ucs_class_t *_cls = &_UCS_CLASS_DECL_NAME(_type); \
97         int _init_counter = 1; \
98         ucs_status_t __status; \
99         \
100         __status = _UCS_CLASS_INIT_NAME(_type)((_type*)(_obj), _cls, \
101                                              &_init_counter, ## __VA_ARGS__); \
102         if (__status != UCS_OK) { \
103             ucs_class_call_cleanup_chain(&_UCS_CLASS_DECL_NAME(_type), \
104                                          (_obj), _init_counter); \
105         } \
106         \
107         (__status); \
108     })
109 
110 
111 /**
112  * Cleanup a class in-place.
113  *
114  * @param _type  Class type.
115  * @param _obj   Instance pointer to cleanup.
116  */
117 #define UCS_CLASS_CLEANUP_CALL(_cls, _obj) \
118     ucs_class_call_cleanup_chain(_cls, _obj, -1)
119 
120 
121 /**
122  * Cleanup a class in-place.
123  *
124  * @param _type  Class type.
125  * @param _obj   Instance pointer to cleanup.
126  */
127 #define UCS_CLASS_CLEANUP(_type, _obj) \
128     { \
129         UCS_CLASS_CLEANUP_CALL(&_UCS_CLASS_DECL_NAME(_type), _obj); \
130     }
131 
132 
133 /**
134  * Instantiate a class.
135  *
136  * @param _type  Class type.
137  * @param _obj   Variable to save the new instance to.
138  * @param ...    Additional arguments to the constructor.
139  *
140  * @return UCS_OK, or error code if failed.
141  */
142 #define UCS_CLASS_NEW(_type, _obj, ...) \
143     _UCS_CLASS_NEW (_type, _obj, ## __VA_ARGS__)
144 #define _UCS_CLASS_NEW(_type, _obj, ...) \
145     ({ \
146         ucs_class_t *cls = &_UCS_CLASS_DECL_NAME(_type); \
147         ucs_status_t _status; \
148         void *obj; \
149         \
150         obj = ucs_class_malloc(cls); \
151         if (obj != NULL) { \
152             _status = UCS_CLASS_INIT(_type, obj, ## __VA_ARGS__); \
153             if (_status == UCS_OK) { \
154                 *(_obj) = (typeof(*(_obj)))obj; /* Success - assign pointer */ \
155             } else { \
156                 ucs_class_free(obj); /* Initialization failure */ \
157             } \
158         } else { \
159             _status = UCS_ERR_NO_MEMORY; /* Allocation failure */ \
160         } \
161         \
162         (_status); \
163     })
164 
165 
166 /**
167  * Destroy a class instance.
168  *
169  * @param _type  Class type.
170  * @param _obj   Instance to destroy.
171  */
172 #define UCS_CLASS_DELETE(_type, _obj) \
173     { \
174         UCS_CLASS_CLEANUP(_type, _obj); \
175         ucs_class_free(_obj); \
176     }
177 
178 
179 /**
180  * Invoke the parent constructor.
181  * Should be used only from init function (which defines "self" and "_myclass")
182  *
183  * @param _superclass  Type of the superclass.
184  * @param ...          Arguments to parent constructor.
185  */
186 #define UCS_CLASS_CALL_SUPER_INIT(_superclass, ...) \
187     { \
188         { \
189             ucs_status_t _status = _UCS_CLASS_INIT_NAME(_superclass)\
190                     (&self->super, _myclass->superclass, _init_count, ## __VA_ARGS__); \
191             if (_status != UCS_OK) { \
192                 return _status; \
193             } \
194             if (_myclass->superclass != &_UCS_CLASS_DECL_NAME(void)) { \
195                 ++(*_init_count); \
196             } \
197         } \
198     }
199 
200 
201 /**
202  * Declare / define a function which creates an instance of a class.
203  *
204  * @param _name     Function name.
205  * @param _type     Class type.
206  * @param _argtype  Type to use for the instance argument. Should be a superclass of _type.
207  * @param ...       List of types for initialization arguments (without variable names).
208  *
209  * Defines a function which can be used as follows:
210  * {
211  *      ucs_status_t status;
212  *      _type *obj;
213  *      status = _type##_new(arg1, arg2, arg3, &obj);
214  * }
215  */
216 #define UCS_CLASS_DECLARE_NAMED_NEW_FUNC(_name, _argtype, ...) \
217     ucs_status_t _name(UCS_PP_FOREACH(_UCS_CLASS_INIT_ARG_DEFINE, _, \
218                                       UCS_PP_ZIP((UCS_PP_SEQ(UCS_PP_NUM_ARGS(__VA_ARGS__))), \
219                                                  (__VA_ARGS__))) \
220                                       _argtype **obj_p)
221 #define UCS_CLASS_DEFINE_NAMED_NEW_FUNC(_name, _type, _argtype, ...) \
222     UCS_CLASS_DECLARE_NAMED_NEW_FUNC(_name, _argtype, ## __VA_ARGS__) { \
223         ucs_status_t status; \
224         \
225         *obj_p = NULL; \
226         \
227         status = UCS_CLASS_NEW(_type, obj_p \
228                                UCS_PP_FOREACH(_UCS_CLASS_INIT_ARG_PASS, _, \
229                                               UCS_PP_SEQ(UCS_PP_NUM_ARGS(__VA_ARGS__)))); \
230         ucs_class_check_new_func_result(status, *obj_p); \
231         return status; \
232     }
233 #define UCS_CLASS_DECLARE_NEW_FUNC(_type, _argtype, ...) \
234     UCS_CLASS_DECLARE_NAMED_NEW_FUNC(UCS_CLASS_NEW_FUNC_NAME(_type), _argtype, ## __VA_ARGS__)
235 #define UCS_CLASS_DEFINE_NEW_FUNC(_type, _argtype, ...) \
236     UCS_CLASS_DEFINE_NAMED_NEW_FUNC(UCS_CLASS_NEW_FUNC_NAME(_type), _type, _argtype, ## __VA_ARGS__)
237 
238 
239 /*
240  * Helper macros for creating argument list
241  */
242 #define _UCS_CLASS_INIT_ARG_DEFINE(_, _bundle) \
243     __UCS_CLASS_INIT_ARG_DEFINE(_, UCS_PP_TUPLE_0 _bundle, UCS_PP_TUPLE_1 _bundle)
244 #define __UCS_CLASS_INIT_ARG_DEFINE(_, _index, _type) \
245     _type _UCS_CLASS_INIT_ARG_NAME(_, _index),
246 #define _UCS_CLASS_INIT_ARG_PASS(_, _index) \
247     , _UCS_CLASS_INIT_ARG_NAME(_, _index)
248 #define _UCS_CLASS_INIT_ARG_NAME(_, _index) \
249     UCS_PP_TOKENPASTE(arg, _index)
250 
251 
252 /**
253  * Name of the function created by UCS_CLASS_DEFINE_NEW_FUNC.
254  */
255 #define UCS_CLASS_NEW_FUNC_NAME(_type) \
256     UCS_PP_TOKENPASTE(_type, _new)
257 
258 
259 /**
260  * Define a function which deletes class instance.
261  *
262  * @param _type     Class type.
263  * @param _argtype  Type to use for the instance argument. Should be a superclass of _type.
264  *
265  * Defines a function which can be used as follows:
266  * {
267  *      _type *obj = ...;
268  *      _type##_delete(obj);
269  */
270 #define UCS_CLASS_DECLARE_NAMED_DELETE_FUNC(_name, _argtype) \
271     void _name(_argtype *self)
272 #define UCS_CLASS_DEFINE_NAMED_DELETE_FUNC(_name, _type, _argtype) \
273     UCS_CLASS_DECLARE_NAMED_DELETE_FUNC(_name, _argtype) \
274     { \
275         UCS_CLASS_DELETE(_type, self); \
276     }
277 #define UCS_CLASS_DECLARE_DELETE_FUNC(_type, _argtype) \
278     UCS_CLASS_DECLARE_NAMED_DELETE_FUNC(UCS_CLASS_DELETE_FUNC_NAME(_type), _argtype)
279 #define UCS_CLASS_DEFINE_DELETE_FUNC(_type, _argtype) \
280     UCS_CLASS_DEFINE_NAMED_DELETE_FUNC(UCS_CLASS_DELETE_FUNC_NAME(_type), _type, _argtype)
281 
282 
283 /**
284  * Name of the function created by UCS_CLASS_DEFINE_DELETE_FUNC.
285  */
286 #define UCS_CLASS_DELETE_FUNC_NAME(_type) \
287     UCS_PP_TOKENPASTE(_type, _delete)
288 
289 
290 /**
291  * Helper: Call class destructor chain.
292  *
293  * @param cls    Class type.
294  * @param obj    Instance pointer.
295  * @param limit  How many destructors to call (0: none, -1: all, 1: only ucs_object_t's).
296  */
297 void ucs_class_call_cleanup_chain(ucs_class_t *cls, void *obj, int limit);
298 
299 
300 /*
301  * Helpers:
302  */
303 /* Allocate objects */
304 void *ucs_class_malloc(ucs_class_t *cls);
305 /* Release objects */
306 void ucs_class_free(void *obj);
307 /* Check new function result */
308 void ucs_class_check_new_func_result(ucs_status_t status, void *obj);
309 
310 
311 /**
312  * The empty class.
313  */
314 UCS_CLASS_DECLARE(void);
315 
316 END_C_DECLS
317 
318 #endif
319