#include #include "time.h" #include "vars.h" #include "pline.h" #include "fuses.h" typedef struct fuse FUSE; struct fuse { TIME time; void (*fxn)(long int, void *); long int arg_li; void *arg_vp; int x; int id; unsigned long int serial; } ; static FUSE **fuses; static int fuses_a; static int fuses_n; static FUSE **idtbl; static int ids_a; static int *freeids; static int freeids_a; static int freeids_n; static unsigned long int next_serial; void initfuses(void) { fuses = 0; fuses_a = 0; fuses_n = 0; idtbl = 0; ids_a = 0; freeids = 0; freeids_a = 0; freeids_n = 0; next_serial = 0; } static void free_id(int id) { idtbl[id] = 0; if (freeids_n >= freeids_a) freeids = realloc(freeids,(freeids_a=freeids_n+16)*sizeof(*freeids)); freeids[freeids_n++] = id; } static int getid(void) { int i; if (freeids_n < 1) { idtbl = realloc(idtbl,(ids_a+16)*sizeof(*idtbl)); for (i=0;i<16;i++) free_id(ids_a++); } return(freeids[--freeids_n]); } static int fuselt(FUSE *f1, FUSE *f2) { if (! f2->fxn) return(0); if (! f1->fxn) return(1); switch (time_cmp(f1->time,f2->time)) { case -1: return(1); break; case 1: return(0); break; } return(f1->serial < f2->serial); } static void bubble_up(FUSE *f, unsigned int x) { unsigned int u; FUSE *t; while (x > 0) { u = (x-1) >> 1; if (! fuselt(f,fuses[u])) break; t = fuses[u]; fuses[x] = t; t->x = x; x = u; } f->x = x; fuses[x] = f; } static void bubble_down(FUSE *f, unsigned int x) { unsigned int l; unsigned int r; unsigned int s; FUSE *t; while (1) { l = (x << 1) + 1; r = l + 1; if ((l < fuses_n) && fuselt(fuses[l],f)) { if ((r < fuses_n) && fuselt(fuses[r],f)) { s = fuselt(fuses[l],fuses[r]) ? l : r; } else { s = l; } } else { if ((r < fuses_n) && fuselt(fuses[r],f)) { s = r; } else { break; } } t = fuses[s]; t->x = x; fuses[x] = t; x = s; } f->x = x; fuses[x] = f; } static void addfuse(FUSE *f) { if (fuses_n >= fuses_a) fuses = realloc(fuses,(fuses_a=fuses_n+16)*sizeof(*fuses)); f->serial = next_serial ++; bubble_up(f,fuses_n++); } int addfuse_abs(void (*fxn)(long int, void *), long int arg_li, void *arg_vp, TIME time) { FUSE *f; f = malloc(sizeof(FUSE)); f->time = time; f->fxn = fxn; f->arg_li = arg_li; f->arg_vp = arg_vp; f->id = getid(); idtbl[f->id] = f; addfuse(f); return(f->id); } int addfuse_rel(void (*fxn)(long int, void *), long int arg_li, void *arg_vp, TIME time) { return(addfuse_abs(fxn,arg_li,arg_vp,time_add_time(curtime,time))); } int addfuse_rtu(void (*fxn)(long int, void *), long int arg_li, void *arg_vp, unsigned long int ticks, unsigned long int uticks) { return(addfuse_abs(fxn,arg_li,arg_vp,time_add_tut(curtime,ticks,uticks))); } void cancelfuse(int id) { FUSE *f; if ((id < 0) || (id >= ids_a)) panic("cancelfuse impossible id"); f = idtbl[id]; if (f->id != id) panic("cancelfuse id wrong"); if ((f->x < 0) || (f->x >= fuses_n)) panic("cancelfuse impossible index"); if (fuses[f->x] != f) panic("cancelfuse index wrong"); f->fxn = 0; bubble_up(f,f->x); } void tick(void) { FUSE *f; if (fuses_n < 1) abort(); f = fuses[0]; bubble_down(fuses[--fuses_n],0); if (f->fxn) { curtime = f->time; (*f->fxn)(f->arg_li,f->arg_vp); } free_id(f->id); free(f); }