Import libtu instead of using submodules
[notion/jeffpc.git] / libtu / obj.c
blob0f4910dfee281a29ed2212187c4b3e90a7ba76bb
1 /*
2 * libtu/obj.c
4 * Copyright (c) Tuomo Valkonen 1999-2004.
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 */
10 #include <string.h>
12 #include "types.h"
13 #include "obj.h"
14 #include "objp.h"
15 #include "misc.h"
16 #include "dlist.h"
19 ClassDescr CLASSDESCR(Obj)={"Obj", NULL, 0, NULL, NULL};
22 static void do_watches(Obj *obj, bool call);
25 /*{{{ Destroy */
28 void destroy_obj(Obj *obj)
30 ClassDescr *d;
32 if(OBJ_IS_BEING_DESTROYED(obj))
33 return;
35 obj->flags|=OBJ_DEST;
37 do_watches(obj, TRUE);
39 d=obj->obj_type;
41 while(d!=NULL){
42 if(d->destroy_fn!=NULL){
43 d->destroy_fn(obj);
44 break;
46 d=d->ancestor;
49 do_watches(obj, FALSE);
51 free(obj);
55 /*}}}*/
58 /*{{{ is/cast */
61 bool obj_is(const Obj *obj, const ClassDescr *descr)
63 ClassDescr *d;
65 if(obj==NULL)
66 return FALSE;
68 d=obj->obj_type;
70 while(d!=NULL){
71 if(d==descr)
72 return TRUE;
73 d=d->ancestor;
75 return FALSE;
79 bool obj_is_str(const Obj *obj, const char *str)
81 ClassDescr *d;
83 if(obj==NULL || str==NULL)
84 return FALSE;
86 d=obj->obj_type;
88 while(d!=NULL){
89 if(strcmp(d->name, str)==0)
90 return TRUE;
91 d=d->ancestor;
93 return FALSE;
97 const void *obj_cast(const Obj *obj, const ClassDescr *descr)
99 ClassDescr *d;
101 if(obj==NULL)
102 return NULL;
104 d=obj->obj_type;
106 while(d!=NULL){
107 if(d==descr)
108 return (void*)obj;
109 d=d->ancestor;
111 return NULL;
115 /*}}}*/
118 /*{{{ Dynamic functions */
121 /* This function is called when no handler is found.
123 static void dummy_dyn()
128 static int comp_fun(const void *a, const void *b)
130 void *af=(void*)((DynFunTab*)a)->func;
131 void *bf=(void*)((DynFunTab*)b)->func;
133 return (af<bf ? -1 : (af==bf ? 0 : 1));
137 DynFun *lookup_dynfun(const Obj *obj, DynFun *func,
138 bool *funnotfound)
140 ClassDescr *descr;
141 DynFunTab *df;
142 /*DynFunTab dummy={NULL, NULL};*/
143 /*dummy.func=func;*/
145 if(obj==NULL)
146 return NULL;
148 descr=obj->obj_type;
150 for(; descr!=&Obj_classdescr; descr=descr->ancestor){
151 if(descr->funtab==NULL)
152 continue;
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++;
163 if(descr->funtab_n>0){
164 qsort(descr->funtab, descr->funtab_n, sizeof(DynFunTab),
165 comp_fun);
170 if(descr->funtab_n==0)
171 continue;
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;
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.
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;
196 if((void*)df[ndx].func<(void*)func)
197 min=ndx+1;
198 else
199 max=ndx-1;
204 *funnotfound=TRUE;
205 return dummy_dyn;
209 bool has_dynfun(const Obj *obj, DynFun *func)
211 bool funnotfound;
212 lookup_dynfun(obj, func, &funnotfound);
213 return !funnotfound;
217 /*}}}*/
220 /*{{{ Watches */
223 bool watch_setup(Watch *watch, Obj *obj, WatchHandler *handler)
225 if(OBJ_IS_BEING_DESTROYED(obj))
226 return FALSE;
228 watch_reset(watch);
230 watch->handler=handler;
231 LINK_ITEM(obj->obj_watches, watch, next, prev);
232 watch->obj=obj;
234 return TRUE;
237 void do_watch_reset(Watch *watch, bool call)
239 WatchHandler *handler=watch->handler;
240 Obj *obj=watch->obj;
242 watch->handler=NULL;
244 if(obj==NULL)
245 return;
247 UNLINK_ITEM(obj->obj_watches, watch, next, prev);
248 watch->obj=NULL;
250 if(call && handler!=NULL)
251 handler(watch, obj);
255 void watch_reset(Watch *watch)
257 do_watch_reset(watch, FALSE);
261 bool watch_ok(Watch *watch)
263 return watch->obj!=NULL;
267 static void do_watches(Obj *obj, bool call)
269 Watch *watch, *next;
271 watch=obj->obj_watches;
273 while(watch!=NULL){
274 next=watch->next;
275 do_watch_reset(watch, call);
276 watch=next;
281 void watch_call(Obj *obj)
283 do_watches(obj, FALSE);
287 void watch_init(Watch *watch)
289 watch->obj=NULL;
290 watch->next=NULL;
291 watch->prev=NULL;
292 watch->handler=NULL;
296 /*}}}*/