/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#include "config.h"
#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 (!cool_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 unsigned 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;
hval = hash(name) % o->methods->size;
for (m = o->methods->table[hval], prev = 0; m; prev = m, m = m->next) {
if (!cool_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;
}