/* Copyright (c) 1993 Stephen F. White */ #include "cool.h" #include "proto.h" static void do_fmr (Object * o, const char *name); /* * find_method() - find a method on an object * * returns a pointer to the method if found, 0 if not. */ Method *find_method (Object * o, const char *name) { Method *m; int hval; if (!o || !o->methods) { return 0; } hval = hash (name) % o->methods->size; for (m = o->methods->table[hval]; m; m = m->next) { if (!strcasecmp (sym_get (o, m->name)->str, name)) { return m; } } return 0; } /* * find_method_recursive() - find a method on an object or its ancestors * * Uses a post-order depth first search reversing the order of the * parents, and marks searched objects using a generational index. * This actually results in a reverse topological search, with a left to * right ordering of branches. Thus, an object is only searched after * all the objects that point to it are searched. Thanks to greg hudson * for help with the algorithm. */ static Method *found_m; static Object *found_o; static int found_blocked_method; /* flag */ static int search_gen = 0; Method *find_method_recursive (Object * o, const char *name, Object ** where) { if (!o || !name) return 0; search_gen += 1; found_m = 0; found_o = 0; found_blocked_method = 0; #ifdef METHOD_DEBUG printf ("#%d.%s: ", o->id.id, name); #endif /* METHOD_DEBUG */ do_fmr (o, name); #ifdef METHOD_DEBUG if (found_m) { if (found_blocked_method) { printf (", found on #%d, blocked\n", found_o->id.id); } else { printf (", found on #%d\n", found_o->id.id); } /* if */ } else { printf (", not found\n"); } /* if */ #endif /* METHOD_DEBUG */ *where = found_o; return found_m; } /* find_method_recursive */ static void do_fmr (Object * o, const char *name) { Method *m; int i; Object *p; /* bail if we've already searched this one */ if (!o || o->last_search == search_gen) return; /* bail if we already found a blocked method */ if (found_blocked_method) return; /* search parents, in reverse order */ for (i = o->parents->len - 1; i >= 0; i--) { p = retrieve (o->parents->el[i].v.obj); do_fmr (p, name); if (found_blocked_method) return; } /* for */ o->last_search = search_gen; /* mark this object searched */ m = find_method (o, name); #ifdef METHOD_DEBUG printf ("#%d ", o->id.id); #endif /* METHOD_DEBUG */ if (m) { /* if we hit one, */ found_m = m; /* save it */ found_o = o; if (m->blocked) { /* if it was blocked, */ found_blocked_method = 1; /* set the flag */ } /* if */ } /* if */ } /* find_method_recursive */ void add_method (Object * o, Method * new_method) { Method *m; int hval; if (!o || !new_method) return; new_method->next = 0; if (!o->methods) { o->methods = hash_new (HASH_INIT_SIZE); } hval = hash (sym_get (o, new_method->name)->str) % o->methods->size; /* skip to end of chain */ for (m = o->methods->table[hval]; m && m->next; m = m->next); if (m) { m->next = new_method; } else { o->methods->table[hval] = new_method; } o->methods->num++; } Error rm_method (Object * o, const char *name) { Method *m, *prev; int hval; if (!o || !name) return E_INVIND; if (!o->methods) return E_METHODNF; hval = hash (name) % o->methods->size; for (m = o->methods->table[hval], prev = 0; m; prev = m, m = m->next) { if (!strcasecmp (sym_get (o, m->name)->str, name)) { if (prev) { prev->next = m->next; } else { o->methods->table[hval] = m->next; } free_method (o, m); o->methods->num--; return E_NONE; } } return E_METHODNF; }