/* * fifop: a FIFO (first-in first-out) with priorities * * (c) 1999-2011 IOhannes m zmölnig, forum::für::umläute, institute of electronic music and acoustics (iem) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "zexy.h" #include /* ------------------------- fifop ------------------------------- */ /* * a FIFO (first-in first-out) with priorities * * an incoming list is added to a fifo (based on its priority) * "bang" outputs the next element of the non-empty fifo with the highest priority * * high priority means low numeric value */ static t_class *fifop_class; typedef struct _fifop_list { int argc; t_atom *argv; struct _fifop_list *next; } t_fifop_list; typedef struct _fifop_prioritylist { t_float priority; t_fifop_list *fifo_start; t_fifop_list *fifo_end; struct _fifop_prioritylist *next; } t_fifop_prioritylist; typedef struct _fifop { t_object x_obj; t_fifop_prioritylist *fifo_list; t_float priority; /* current priority */ unsigned long counter; t_outlet *x_out, *x_infout; } t_fifop; static t_fifop_prioritylist*fifop_genprioritylist(t_fifop*x, t_float priority) { t_fifop_prioritylist*result=0, *dummy=0; if(x->fifo_list!=0) { /* * do we already have this priority ? * if so, just return a pointer to that fifo * else set the dummy-pointer to the fifo BEFORE the new one */ dummy=x->fifo_list; while(dummy!=0) { t_float prio=dummy->priority; if(prio==priority) { return dummy; } if(prio>priority) { break; } result=dummy; dummy=dummy->next; } dummy=result; /* dummy points to the FIFO-before the one we want to insert */ } /* create a new priority list */ result = (t_fifop_prioritylist*)getbytes(sizeof( t_fifop_prioritylist)); result->priority=priority; result->fifo_start=0; result->fifo_end=0; result->next=0; /* insert it into the list of priority lists */ if(dummy==0) { /* insert at the beginning */ result->next=x->fifo_list; x->fifo_list=result; } else { /* post insert into the list of FIFOs */ result->next=dummy->next; dummy->next =result; } /* return the result */ return result; } static int add2fifo(t_fifop_prioritylist*fifoprio, int argc, t_atom *argv) { t_fifop_list*fifo=0; t_fifop_list*entry=0; if(fifoprio==0) { error("pfifo: no fifos available"); return -1; } /* create an entry for the fifo */ if(!(entry = (t_fifop_list*)getbytes(sizeof(t_fifop_list)))) { error("pfifo: couldn't add entry to end of fifo"); return -1; } if(!(entry->argv=(t_atom*)getbytes(argc*sizeof(t_atom)))) { error("pfifo: couldn't add list to fifo!"); return -1; } memcpy(entry->argv, argv, argc*sizeof(t_atom)); entry->argc=argc; entry->next=0; /* insert entry into fifo */ if(fifoprio->fifo_end) { /* append to the end of the fifo */ fifo=fifoprio->fifo_end; /* add new entry to end of fifo */ fifo->next=entry; fifoprio->fifo_end=entry; } else { /* the new entry is the 1st entry of the fifo */ fifoprio->fifo_start=entry; /* and at the same time, it is the last entry */ fifoprio->fifo_end =entry; } return 0; } static t_fifop_prioritylist*getFifo(t_fifop_prioritylist*pfifo) { if(pfifo==0) { return 0; } /* get the highest non-empty fifo */ while(pfifo->fifo_start==0 && pfifo->next!=0) { pfifo=pfifo->next; } return pfifo; } static void fifop_list(t_fifop *x, t_symbol* UNUSED(s), int argc, t_atom *argv) { t_fifop_prioritylist*pfifo=0; if(!(pfifo=fifop_genprioritylist(x, x->priority))) { error("[fifop]: couldn't get priority fifo"); return; } if(!add2fifo(pfifo, argc, argv)) { x->counter++; } } static void fifop_bang(t_fifop *x) { t_fifop_prioritylist*pfifo=0; t_fifop_list*fifo=0; t_atom*argv=0; int argc=0; if(!(pfifo=getFifo(x->fifo_list))) { outlet_bang(x->x_infout); return; } if(!(fifo=pfifo->fifo_start)) { outlet_bang(x->x_infout); return; } x->counter--; pfifo->fifo_start=fifo->next; if(0==pfifo->fifo_start) { pfifo->fifo_end=0; } /* get the list from the entry */ argc=fifo->argc; argv=fifo->argv; fifo->argc=0; fifo->argv=0; fifo->next=0; /* destroy the fifo-entry (important for recursion! */ freebytes(fifo, sizeof(t_fifop_list)); /* output the list */ outlet_list(x->x_out, gensym("list"), argc, argv); /* free the list */ freebytes(argv, argc*sizeof(t_atom)); } static void fifop_query(t_fifop*x) { z_verbose(1, "%d elements in fifo", (int)x->counter); outlet_float(x->x_infout, (t_float)x->counter); } static void fifop_clear(t_fifop*x) { t_fifop_prioritylist *fifo_list=x->fifo_list; while(fifo_list) { t_fifop_prioritylist *fifo_list2=fifo_list; t_fifop_list*fifo=fifo_list2->fifo_start; fifo_list=fifo_list->next; while(fifo) { t_fifop_list*fifo2=fifo; fifo=fifo->next; if(fifo2->argv) { freebytes(fifo2->argv, fifo2->argc*sizeof(t_atom)); } fifo2->argv=0; fifo2->argc=0; fifo2->next=0; freebytes(fifo2, sizeof(t_fifop_list)); } fifo_list2->priority =0; fifo_list2->fifo_start=0; fifo_list2->fifo_end =0; fifo_list2->next =0; freebytes(fifo_list2, sizeof( t_fifop_prioritylist)); } x->fifo_list=0; x->counter=0; } /* this is NOT re-entrant! */ static void fifop_dump(t_fifop*x) { t_fifop_prioritylist*pfifo=getFifo(x->fifo_list); if(!pfifo||!pfifo->fifo_start) { outlet_bang(x->x_infout); return; } while(pfifo) { t_fifop_list*fifo=pfifo->fifo_start; while(fifo) { t_atom*argv=fifo->argv; int argc=fifo->argc; /* output the list */ outlet_list(x->x_out, gensym("list"), argc, argv); fifo=fifo->next; } pfifo=pfifo->next; } } static void fifop_help(t_fifop*x) { post("\n"HEARTSYMBOL" fifop\t\t:: a First-In-First-Out queue with priorities"); } static void fifop_free(t_fifop *x) { fifop_clear(x); outlet_free(x->x_out); outlet_free(x->x_infout); } static void *fifop_new(void) { t_fifop *x = (t_fifop *)pd_new(fifop_class); floatinlet_new(&x->x_obj, &x->priority); x->x_out =outlet_new(&x->x_obj, gensym("list" )); x->x_infout=outlet_new(&x->x_obj, gensym("float")); x->fifo_list = 0; x->priority=0; return (x); } void fifop_setup(void) { fifop_class = class_new(gensym("fifop"), (t_newmethod)fifop_new, (t_method)fifop_free, sizeof(t_fifop), 0, A_NULL); class_addbang (fifop_class, fifop_bang); class_addlist (fifop_class, fifop_list); class_addmethod (fifop_class, (t_method)fifop_clear, gensym("clear"), A_NULL); class_addmethod (fifop_class, (t_method)fifop_dump, gensym("dump"), A_NULL); class_addmethod (fifop_class, (t_method)fifop_query, gensym("info"), A_NULL); class_addmethod (fifop_class, (t_method)fifop_help, gensym("help"), A_NULL); zexy_register("fifop"); }