aboutsummaryrefslogtreecommitdiff
path: root/src/oreceive.c
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-07-23 10:16:01 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-07-23 10:16:01 +0000
commit9f6788bcefbb20328794eca9aba8be45542b8b92 (patch)
tree8d09ad41629b597ebb1328f1ef9977cf68b4593a /src/oreceive.c
parent9ede9e7fa473a7941ed0b1d91f571646aabadd0a (diff)
ordered receive: this is similar as [gemhead] priorities
but more general svn path=/trunk/externals/iem/iemguts/; revision=10209
Diffstat (limited to 'src/oreceive.c')
-rw-r--r--src/oreceive.c272
1 files changed, 272 insertions, 0 deletions
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);
+}