| |
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 |