/* rb.c - ring buffer routines */ #ifdef DOCUMENTATION title rb Ring Buffers index RingBuffers index rb index rbin() index rbout() index struct rb usage #include struct rb r; BOOL ok; /* true if done successfully */ #define ITMSIZ (...) /* # chars in item */ #define NUM (...) /* # items in buf */ char it[ITMSIZ]; /* an item */ char mybuffer[ITMSIZ*NUM]; /* ringbuf */ rbnew(&r,mybuffer,ITMSIZ,NUM); /* init */ ok = rbin(&r,it); /* false: no room */ ok = rbout(&r,it); /* false: empty */ description Two routines, and a struct, implement the basic idea of a ring buffer. Items put into/outof the buffer are fixed length. The ring buffer is controlled by a header (struct rb) that contains details like buffer element size, where the buffer is etc. The header need not be near the buffer. For an example of how to set up a buffer header, see RBTEST.C. Rbin(r,it) will either (a) add elemnet 'it' to the buffer, returning TRUE, or (b) determine the buffer is full, not touch the buffer, and return FALSE. Rbout(r,it) will either (a) remove the next element from the buffer, copying it to 'it', returning TRUE, or (b) determine the ringbuffer is empty, preserve both the buffer and 'it', and return FALSE. The header is seperate from the buffer. This allows eg the buffer to be mapped very differently from the header. All buffer knowledge is in the header. This allows two different buffers to have different element sizes, or other details different, so you may use these routines to maintain all your fixed-element-size ring buffers. Rbnew() is used to initialise a struct rb. bugs internal Test with rbtest.c . A n-slot ring buffer has n*n+1 states: EMPTY, and n data lengths starting at n positions. Since rb_in and rb_out are normally pointing at one of the n buffer slots we can't represent the EMPTY case. So we define rb_in==NULL to mean empty buffer. #endif /* * E D I T H I S T O R Y * * 3aug85 DLE Create. * */ #include #include VOID rbnew(r,buf,siz,num) /* set up struct rb */ struct rb * r; char * buf; /* where the ring buffer starts */ unsigned siz; /* length (chars) of item */ unsigned num; /* number of items in ring */ BEGIN r -> rb_in = NULL; r -> rb_len = siz; r -> rb_beg = buf; r -> rb_end = buf + num*siz; END BOOL rbin(r,it) /* TRUE if was done OK */ struct rb * r; /* the ring buffer */ char * it; /* thing to add to ring buffer */ BEGIN register BOOL retval; /* TRUE if was done */ /* FALSE if no room */ register char * i; /* next slot to input to */ register char * o; /* next slot to output from */ register unsigned len; /* length of a unit (chars) */ register char * beg; /* start of buffer ring */ beg = r -> rb_beg; o = r -> rb_out; IF ( (i=r->rb_in) ) THEN /* at least something in ring */ retval = (i!=o); /* FALSE if ring is full, i==o */ ELSE /* empty ring */ r -> rb_out = i = o = beg; retval = TRUE; FI IF (retval) THEN copy(i,it,len=r->rb_len); i += len; IF (i>=r->rb_end) THEN i = beg; FI r -> rb_in = i; FI return(retval); END BOOL rbout(r,it) /* TRUE if was done OK */ struct rb * r; /* the ring buffer */ char * it; /* where to copy data to */ BEGIN register unsigned len; /* length of object */ register BOOL retval; /* true if was done OK */ /* FALSE if noting in buffer to */ /* return via it */ register char * i; /* address of next input slot */ register char * o; /* address of next output slot */ IF (retval = i = r->rb_in) THEN /* buffer has at least one item */ copy(it,o=r->rb_out,len=r->rb_len); /* output item */ o += len; /* advance to next output slot */ IF (o >= r->rb_end) THEN o = r->rb_beg; /* wrap output slot */ FI IF (o==i) THEN /* we just emptied last item */ r -> rb_in = NULL; /* rb_out random */ ELSE r -> rb_out = o; FI END return(retval); END /* end: rb.c */