Make casts work again properly (bug #3155)
[asterisk/asterisk.git] / include / asterisk / astobj.h
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Object Model for Asterisk
5  * 
6  * Copyright (C) 2004-2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #ifndef _ASTERISK_ASTOBJ_H
15 #define _ASTERISK_ASTOBJ_H
16
17 #include <string.h>
18
19 /*!
20   \file astobj.h
21   \brief A set of macros implementing the asterisk object and container.  Macros
22          are used for maximum performance, to support multiple inheritance, and
23                  to be easily integrated into existing structures without additional 
24                  malloc calls, etc.
25 */
26
27 #if defined(__cplusplus) || defined(c_plusplus)
28 extern "C" {
29 #endif
30
31 #define ASTOBJ_DEFAULT_NAMELEN  80
32 #define ASTOBJ_DEFAULT_BUCKETS  256
33 #define ASTOBJ_DEFAULT_HASH             ast_strhash
34
35 #define ASTOBJ_FLAG_DELME       (1 << 0)                /* Object has been deleted, remove on last unref */
36 #define ASTOBJ_FLAG_MARKED      (1 << 1)                /* Object has been marked for possible deletion */
37
38 /* C++ is simply a syntactic crutch for those who cannot think for themselves
39    in an object oriented way. */
40
41 #define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock)
42 #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock)
43 #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock)
44
45 #ifdef ASTOBJ_CONTAINER_HASHMODEL 
46 #define __ASTOBJ_HASH(type,hashes) \
47         type *next[hashes] 
48 #else 
49 #define __ASTOBJ_HASH(type,hashes) \
50         type *next[1] 
51 #endif  
52
53 #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
54         char name[namelen]; \
55         int refcount; \
56         int objflags; \
57         __ASTOBJ_HASH(type,hashes)
58         
59 #define ASTOBJ_COMPONENTS_NOLOCK(type) \
60         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
61
62 #define ASTOBJ_COMPONENTS(type) \
63         ASTOBJ_COMPONENTS_NOLOCK(type); \
64         ast_mutex_t _lock; 
65         
66 #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
67         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \
68         ast_mutex_t _lock; 
69
70 #define ASTOBJ_REF(object) \
71         ({ \
72                 ASTOBJ_WRLOCK(object); \
73                 (object)->refcount++; \
74                 ASTOBJ_UNLOCK(object); \
75                 (object); \
76         })
77         
78 #define ASTOBJ_UNREF(object,destructor) \
79         do { \
80                 ASTOBJ_WRLOCK(object); \
81                 if (__builtin_expect((object)->refcount, 1)) \
82                         (object)->refcount--; \
83                 else \
84                         ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
85                 ASTOBJ_UNLOCK(object); \
86                 ASTOBJ_DESTROY(object,destructor); \
87                 (object) = NULL; \
88         } while(0)
89
90 #define ASTOBJ_MARK(object) \
91         do { \
92                 ASTOBJ_WRLOCK(object); \
93                 (object)->objflags |= ASTOBJ_FLAG_MARKED; \
94                 ASTOBJ_UNLOCK(object); \
95         } while(0)
96         
97 #define ASTOBJ_UNMARK(object) \
98         do { \
99                 ASTOBJ_WRLOCK(object); \
100                 (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
101                 ASTOBJ_UNLOCK(object); \
102         } while(0)
103
104 #define ASTOBJ_DESTROY(object,destructor) \
105         do { \
106                 if (__builtin_expect((object)->refcount, 1)) { \
107                         ASTOBJ_WRLOCK(object); \
108                         (object)->objflags |= ASTOBJ_FLAG_DELME; \
109                         ASTOBJ_UNLOCK(object); \
110                 } else { \
111                         ast_mutex_destroy(&(object)->_lock); \
112                         destructor((object)); \
113                 } \
114         } while(0)
115         
116 #define ASTOBJ_INIT(object) \
117         do { \
118                 ast_mutex_init(&(object)->_lock); \
119                 object->name[0] = '\0'; \
120                 object->refcount = 1; \
121         } while(0)
122
123 /* Containers for objects -- current implementation is linked lists, but
124    should be able to be converted to hashes relatively easily */
125
126 #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
127 #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
128 #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
129
130 #ifdef ASTOBJ_CONTAINER_HASHMODEL
131 #error "Hash model for object containers not yet implemented!"
132 #else
133 /* Linked lists */
134 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
135         type *head
136
137 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
138         do { \
139                 ast_mutex_init(&(container)->_lock); \
140         } while(0)
141         
142 #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
143         do { \
144                 ast_mutex_destroy(&(container)->_lock); \
145         } while(0)
146
147 #define ASTOBJ_CONTAINER_TRAVERSE(container,eval) \
148         do { \
149                 typeof((container)->head) iterator; \
150                 typeof((container)->head) next; \
151                 ASTOBJ_CONTAINER_RDLOCK(container); \
152                 next = (container)->head; \
153                 while((iterator = next)) { \
154                         next = iterator->next[0]; \
155                         eval; \
156                 } \
157                 ASTOBJ_CONTAINER_UNLOCK(container); \
158         } while(0)
159
160 #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
161         ({ \
162                 typeof((container)->head) found = NULL; \
163                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
164                         ASTOBJ_RDLOCK(iterator); \
165                         if (!(comparefunc(iterator->field, (data)))) { \
166                                 found = ASTOBJ_REF(iterator); \
167                         } \
168                         ASTOBJ_UNLOCK(iterator); \
169                         if (found) \
170                                 break; \
171                 } while (0)); \
172                 found; \
173         })
174
175 #define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \
176         do { \
177                 typeof((container)->head) iterator; \
178                 ASTOBJ_CONTAINER_WRLOCK(container); \
179                 while((iterator = (container)->head)) { \
180                         (container)->head = (iterator)->next[0]; \
181                         ASTOBJ_DESTROY(iterator,destructor); \
182                         ASTOBJ_UNREF(iterator,destructor); \
183                 } \
184                 ASTOBJ_CONTAINER_UNLOCK(container); \
185         } while(0)
186
187 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
188         ({ \
189                 typeof((container)->head) found = NULL; \
190                 typeof((container)->head) prev = NULL; \
191                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
192                         ASTOBJ_RDLOCK(iterator); \
193                         if (!(comparefunc(iterator->field, (data)))) { \
194                                 found = iterator; \
195                                 ASTOBJ_CONTAINER_WRLOCK(container); \
196                                 if (prev) \
197                                         prev->next[0] = next; \
198                                 else \
199                                         (container)->head = next; \
200                                 ASTOBJ_CONTAINER_UNLOCK(container); \
201                                 break; \
202                         } \
203                         ASTOBJ_UNLOCK(iterator); \
204                         if (found) \
205                                 break; \
206                         prev = iterator; \
207                 } while (0)); \
208                 found; \
209         })
210
211 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
212         do { \
213                 typeof((container)->head) prev = NULL; \
214                 ASTOBJ_CONTAINER_TRAVERSE(container, do { \
215                         ASTOBJ_RDLOCK(iterator); \
216                         if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
217                                 ASTOBJ_CONTAINER_WRLOCK(container); \
218                                 if (prev) \
219                                         prev->next[0] = next; \
220                                 else \
221                                         (container)->head = next; \
222                                 ASTOBJ_CONTAINER_UNLOCK(container); \
223                                 ASTOBJ_UNLOCK(iterator); \
224                                 ASTOBJ_DESTROY(iterator,destructor); \
225                                 continue; \
226                         } \
227                         ASTOBJ_UNLOCK(iterator); \
228                         prev = iterator; \
229                 } while (0)); \
230         } while(0)
231
232 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
233         do { \
234                 ASTOBJ_CONTAINER_WRLOCK(container); \
235                 (newobj)->next[0] = (container)->head; \
236                 (container)->head = ASTOBJ_REF(newobj); \
237                 ASTOBJ_CONTAINER_UNLOCK(container); \
238         } while(0)
239
240 #endif /* List model */
241
242 /* Common to hash and linked list models */
243 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
244         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
245
246 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
247         ast_mutex_t _lock; \
248         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
249
250 #define ASTOBJ_CONTAINER_INIT(container) \
251         ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
252
253 #define ASTOBJ_CONTAINER_DESTROY(container) \
254         ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
255
256 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
257         ASTOBJ_CONTAINER_FIND_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
258
259 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
260         ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
261
262 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
263         ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
264
265 #define ASTOBJ_CONTAINER_MARKALL(container) \
266         ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_MARK(iterator))
267
268 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
269         ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_UNMARK(iterator))
270
271 #define ASTOBJ_DUMP(s,slen,obj) \
272         snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
273
274 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
275         ASTOBJ_CONTAINER_TRAVERSE(container,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
276
277 #if defined(__cplusplus) || defined(c_plusplus)
278 }
279 #endif
280
281 #endif