obj.c

changeset 60
a4033700e35c
child 62
aae5facf9fc5
equal deleted inserted replaced
59:d8ecbeda7683 60:a4033700e35c
1 /*
2 * libtu/obj.c
3 *
4 * Copyright (c) Tuomo Valkonen 1999-2004.
5 *
6 * You may distribute and modify this library under the terms of either
7 * the Clarified Artistic License or the GNU LGPL, version 2.1 or later.
8 */
9
10 #include <string.h>
11
12 #include "types.h"
13 #include "obj.h"
14 #include "objp.h"
15 #include "misc.h"
16 #include "dlist.h"
17
18
19 ClassDescr CLASSDESCR(Obj)={"Obj", NULL, 0, NULL, NULL};
20
21
22 static void do_watches(Obj *obj, bool call);
23
24
25 /*{{{ Destroy */
26
27
28 void destroy_obj(Obj *obj)
29 {
30 ClassDescr *d;
31
32 if(OBJ_IS_BEING_DESTROYED(obj))
33 return;
34
35 obj->flags|=OBJ_DEST;
36
37 do_watches(obj, TRUE);
38
39 d=obj->obj_type;
40
41 while(d!=NULL){
42 if(d->destroy_fn!=NULL){
43 d->destroy_fn(obj);
44 break;
45 }
46 d=d->ancestor;
47 }
48
49 do_watches(obj, FALSE);
50
51 free(obj);
52 }
53
54
55 /*}}}*/
56
57
58 /*{{{ is/cast */
59
60
61 bool obj_is(const Obj *obj, const ClassDescr *descr)
62 {
63 ClassDescr *d;
64
65 if(obj==NULL)
66 return FALSE;
67
68 d=obj->obj_type;
69
70 while(d!=NULL){
71 if(d==descr)
72 return TRUE;
73 d=d->ancestor;
74 }
75 return FALSE;
76 }
77
78
79 bool obj_is_str(const Obj *obj, const char *str)
80 {
81 ClassDescr *d;
82
83 if(obj==NULL || str==NULL)
84 return FALSE;
85
86 d=obj->obj_type;
87
88 while(d!=NULL){
89 if(strcmp(d->name, str)==0)
90 return TRUE;
91 d=d->ancestor;
92 }
93 return FALSE;
94 }
95
96
97 const void *obj_cast(const Obj *obj, const ClassDescr *descr)
98 {
99 ClassDescr *d;
100
101 if(obj==NULL)
102 return NULL;
103
104 d=obj->obj_type;
105
106 while(d!=NULL){
107 if(d==descr)
108 return (void*)obj;
109 d=d->ancestor;
110 }
111 return NULL;
112 }
113
114
115 /*}}}*/
116
117
118 /*{{{ Dynamic functions */
119
120
121 /* This function is called when no handler is found.
122 */
123 static void dummy_dyn()
124 {
125 }
126
127
128 static int comp_fun(const void *a, const void *b)
129 {
130 void *af=(void*)((DynFunTab*)a)->func;
131 void *bf=(void*)((DynFunTab*)b)->func;
132
133 return (af<bf ? -1 : (af==bf ? 0 : 1));
134 }
135
136
137 DynFun *lookup_dynfun(const Obj *obj, DynFun *func,
138 bool *funnotfound)
139 {
140 ClassDescr *descr;
141 DynFunTab *df;
142 /*DynFunTab dummy={NULL, NULL};*/
143 /*dummy.func=func;*/
144
145 if(obj==NULL)
146 return NULL;
147
148 descr=obj->obj_type;
149
150 for(; descr!=&Obj_classdescr; descr=descr->ancestor){
151 if(descr->funtab==NULL)
152 continue;
153
154 if(descr->funtab_n==-1){
155 /* Need to sort the table. */
156 descr->funtab_n=0;
157 df=descr->funtab;
158 while(df->func!=NULL){
159 descr->funtab_n++;
160 df++;
161 }
162
163 if(descr->funtab_n>0){
164 qsort(descr->funtab, descr->funtab_n, sizeof(DynFunTab),
165 comp_fun);
166 }
167 }
168
169 /*
170 if(descr->funtab_n==0)
171 continue;
172
173 df=(DynFunTab*)bsearch(&dummy, descr->funtab, descr->funtab_n,
174 sizeof(DynFunTab), comp_fun);
175 if(df!=NULL){
176 *funnotfound=FALSE;
177 return df->handler;
178 }
179 */
180
181 /* Using custom bsearch instead of the one in libc is probably
182 * faster as the overhead of calling a comparison function would
183 * be significant given that the comparisons are simple and
184 * funtab_n not that big.
185 */
186 {
187 int min=0, max=descr->funtab_n-1;
188 int ndx;
189 df=descr->funtab;
190 while(max>=min){
191 ndx=(max+min)/2;
192 if((void*)df[ndx].func==(void*)func){
193 *funnotfound=FALSE;
194 return df[ndx].handler;
195 }
196 if((void*)df[ndx].func<(void*)func)
197 min=ndx+1;
198 else
199 max=ndx-1;
200 }
201 }
202 }
203
204 *funnotfound=TRUE;
205 return dummy_dyn;
206 }
207
208
209 bool has_dynfun(const Obj *obj, DynFun *func)
210 {
211 bool funnotfound;
212 lookup_dynfun(obj, func, &funnotfound);
213 return !funnotfound;
214 }
215
216
217 /*}}}*/
218
219
220 /*{{{ Watches */
221
222
223 bool watch_setup(Watch *watch, Obj *obj, WatchHandler *handler)
224 {
225 if(OBJ_IS_BEING_DESTROYED(obj))
226 return FALSE;
227
228 watch_reset(watch);
229
230 watch->handler=handler;
231 LINK_ITEM(obj->obj_watches, watch, next, prev);
232 watch->obj=obj;
233
234 return TRUE;
235 }
236
237 void do_watch_reset(Watch *watch, bool call)
238 {
239 WatchHandler *handler=watch->handler;
240 Obj *obj=watch->obj;
241
242 watch->handler=NULL;
243
244 if(obj==NULL)
245 return;
246
247 UNLINK_ITEM(obj->obj_watches, watch, next, prev);
248 watch->obj=NULL;
249
250 if(call && handler!=NULL)
251 handler(watch, obj);
252 }
253
254
255 void watch_reset(Watch *watch)
256 {
257 do_watch_reset(watch, FALSE);
258 }
259
260
261 bool watch_ok(Watch *watch)
262 {
263 return watch->obj!=NULL;
264 }
265
266
267 static void do_watches(Obj *obj, bool call)
268 {
269 Watch *watch, *next;
270
271 watch=obj->obj_watches;
272
273 while(watch!=NULL){
274 next=watch->next;
275 do_watch_reset(watch, call);
276 watch=next;
277 }
278 }
279
280
281 void watch_call(Obj *obj)
282 {
283 do_watches(obj, FALSE);
284 }
285
286
287 void watch_init(Watch *watch)
288 {
289 watch->obj=NULL;
290 watch->next=NULL;
291 watch->prev=NULL;
292 watch->handler=NULL;
293 }
294
295
296 /*}}}*/
297

mercurial