From 9f6788bcefbb20328794eca9aba8be45542b8b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Wed, 23 Jul 2008 10:16:01 +0000 Subject: ordered receive: this is similar as [gemhead] priorities but more general svn path=/trunk/externals/iem/iemguts/; revision=10209 --- src/oreceive.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 src/oreceive.c (limited to 'src') diff --git a/src/oreceive.c b/src/oreceive.c new file mode 100644 index 0000000..13f2102 --- /dev/null +++ b/src/oreceive.c @@ -0,0 +1,272 @@ + +#include "m_pd.h" + +#if 0 +# define debug_post post +#else +# define debug_post +#endif + +static t_class *oreceive_class, *oreceive_proxy_class, *oreceive_guts_class; + + +/* ------------------------------------------------------------- */ +/* there come the guts: our own bind/unbind mechanism that + * includes priorities + * + * the plan is as follows: + * [oreceive] tells us, which name it wants to bind to; + * it doesn't _really_ get bound to this name! + * + * we have an invisible permanent object, that keeps track of + * sorted (by priority) lists of the [oreceive] objects + * + * this object binds itself to the requested name + * and when it gets called, it in turn calls all the [oreceive] objects + * + * that's it + */ + + +typedef struct _bind_element { + t_pd *object; + t_float priority; + struct _bind_element*next; +} t_bind_element; + +typedef struct _bind_list { + t_object p_obj; + + t_symbol*key; + t_bind_element*elements; + struct _bind_list*next; +} t_oreceive_proxy; + +static t_oreceive_proxy*priority_receiver=0; + +static t_oreceive_proxy*guts_find_key(t_symbol*key) +{ + t_oreceive_proxy*binding=0; + + for(binding=priority_receiver; binding; binding=binding->next) { + if(binding->key == key) + return binding; + } + /* not found */ + return 0; +} + + +static t_oreceive_proxy*guts_add_key(t_symbol*key) +{ + t_oreceive_proxy*bind_list=0; + bind_list=(t_oreceive_proxy*)pd_new(oreceive_proxy_class); + bind_list->key=key; + bind_list->elements=0; + bind_list->next=0; + + debug_post("binding %x to %s", bind_list, key->s_name); + pd_bind(&bind_list->p_obj.ob_pd, key); + + t_oreceive_proxy*last=priority_receiver; + + if(last) { + while(last->next) { + last=last->next; + } + last->next = bind_list; + } else { + priority_receiver = bind_list; + } + + return bind_list; +} + +static void guts_add_element(t_oreceive_proxy*bind_list, t_bind_element*element) +{ + /* insert the object according to it's priority + * this is already the right queue + */ + t_float priority=element->priority; + t_bind_element*elements=bind_list->elements, *last=0; + debug_post("priority insert of %x:%g", element, priority); + + if(!elements || elements->priority >= priority) { + bind_list->elements = element; + element->next = elements; + debug_post("inserting in the beginngin"); + return; + } + + + debug_post("trying %x:%g", elements, elements->priority); + while(elements && elements->priority < priority) { + debug_post("skipping %x:%g to %x", elements, elements->priority, elements->next); + last=elements; + elements=elements->next; + } + + debug_post("inserting after %x:%g", last, (last ? (last->priority):0)); + debug_post("inserting befor %x:%g", elements, (elements?(elements->priority):0)); + + element->next=elements; + if(last) { + last->next = element; + } else { + bug("\nlast object invalid when inserting prioritized receiver\n"); + } +} + + +static void pd_bind_priority(t_pd*x, t_symbol*key, t_float priority) { + t_oreceive_proxy*bind_list=0; + t_bind_element*element=0; + debug_post("trying to bind '%s':%g via %x", key->s_name, priority, priority_receiver); + + bind_list=guts_find_key(key); + if(!bind_list) + bind_list=guts_add_key(key); + if(!bind_list)return; + + element=(t_bind_element*)getbytes(sizeof(t_bind_element)); + element->object=x; + element->priority=priority; + element->next=0; + + guts_add_element(bind_list, element); +} + + +static void pd_unbind_priority(t_pd*x, t_symbol*key) { + t_oreceive_proxy*list=0, *last=0; + t_bind_element*elements=0, *lastlmn=0; + + debug_post("trying to unbind '%s' from %x", key->s_name, priority_receiver); + + for(list=priority_receiver; list && list->key!=key; list=list->next){ + last=list; + } + if(!list)return; + + for(elements=list->elements; elements && elements->object != x; elements=elements->next) { + lastlmn=elements; + } + + if(elements) { + /* found it, now remove it */ + if(lastlmn) { + lastlmn->next=elements->next; + } else { + list->elements=elements->next; + } + + elements->object=0; + elements->priority=0; + elements->next=0; + + freebytes(elements, sizeof(elements)); + } else { + // not here... + } + + if(0==list->elements) { + // should we unbind ?? + if(last) { + last->next=list->next; + } else { + priority_receiver=list->next; + } + + pd_unbind(&list->p_obj.ob_pd, list->key); + list->next=0; + list->key=0; + + pd_free(&list->p_obj.ob_pd); + } +} + +/* -------------------- oreceive ------------------------------ */ + +typedef struct _oreceive +{ + t_object x_obj; + t_symbol *x_sym; + t_float x_priority; + + t_inlet*x_symin,*x_fltin; +} t_oreceive; + +static void oreceive_anything(t_oreceive *x, t_symbol *s, int argc, t_atom *argv); + +static void oreceive_proxy_anything(t_oreceive_proxy*p, t_symbol*s, int argc, t_atom*argv) +{ + t_bind_element*elements=p->elements; + + debug_post("proxy anything: %x", p); + + while(elements) { + t_pd*o=elements->object; + elements=elements->next; + if(o) { + oreceive_anything((t_oreceive*)o, s, argc, argv); + } + } +} + +/* ------------------------------------------------------------- */ + +static void oreceive_anything(t_oreceive *x, t_symbol *s, int argc, t_atom *argv) +{ + outlet_anything(x->x_obj.ob_outlet, s, argc, argv); +} + +static void oreceive_priority(t_oreceive *x, t_float p) +{ + x->x_priority=p; + if(x->x_sym) { + pd_unbind_priority(&x->x_obj.ob_pd, x->x_sym); + } + pd_bind_priority(&x->x_obj.ob_pd, x->x_sym, x->x_priority); +} + +static void oreceive_name(t_oreceive *x, t_symbol*s) +{ + if(x->x_sym) { + pd_unbind_priority(&x->x_obj.ob_pd, x->x_sym); + } + x->x_sym=s; + pd_bind_priority(&x->x_obj.ob_pd, x->x_sym, x->x_priority); +} + + +static void *oreceive_new(t_symbol *s, t_float priority) +{ + t_oreceive *x = (t_oreceive *)pd_new(oreceive_class); + + x->x_symin = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_symbol, &s_symbol); + x->x_fltin = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, &s_float); + + x->x_sym = s; + x->x_priority = priority; + pd_bind_priority(&x->x_obj.ob_pd, s, priority); + // pd_bind(&x->x_obj.ob_pd, s); + outlet_new(&x->x_obj, 0); + return (x); +} + +static void oreceive_free(t_oreceive *x) +{ + pd_unbind_priority(&x->x_obj.ob_pd, x->x_sym); +} + +void oreceive_setup(void) +{ + oreceive_class = class_new(gensym("oreceive"), (t_newmethod)oreceive_new, + (t_method)oreceive_free, sizeof(t_oreceive), CLASS_NOINLET, A_DEFSYM, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)oreceive_new, gensym("r"), A_DEFSYM, A_DEFFLOAT, 0); + class_addsymbol(oreceive_class, oreceive_name); + class_addmethod(oreceive_class, (t_method)oreceive_priority, &s_float, A_FLOAT, 0); + + oreceive_proxy_class = class_new(0, 0, 0, sizeof(t_oreceive_proxy), CLASS_NOINLET | CLASS_PD, 0); + class_addanything(oreceive_proxy_class, oreceive_proxy_anything); +} -- cgit v1.2.1