]> git.decadent.org.uk Git - ion3.git/blob - libtu/obj.c
[svn-inject] Installing original source of ion3
[ion3.git] / libtu / obj.c
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