text: /**
   * @file math/ring_buffer.c
   *
   * @brief      Ring buffer implementation for single-precision floats
   *
   *             Ring buffers are FIFO (first in first out) buffers of fixed
   *             length which efficiently boot out the oldest value when full.
   *             They are particularly well suited for storing the last n values
   *             in a discrete time filter.
   *
   *             The user creates their own instance of a buffer and passes a
   *             pointer to the these ring_buf functions to perform normal
   *             operations.
   *
   * @author     James Strawson
   * @date       2016
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <math.h>
  
  #include <rc/math/ring_buffer.h>
  
  // preposessor macros
  #define unlikely(x)	__builtin_expect (!!(x), 0)
  
  
  
  rc_ringbuf_t rc_ringbuf_empty()
  {
  	rc_ringbuf_t out;
  	// zero-out piecemeal instead of with memset to avoid issues with padding
  	out.d=NULL;
  	out.size=0;
  	out.index=0;
  	out.initialized=0;
  	return out;
  }
  
  
  int rc_ringbuf_alloc(rc_ringbuf_t* buf, int size)
  {
  	// sanity checks
  	if(unlikely(buf==NULL)){
  		fprintf(stderr,"ERROR in rc_ringbuf_alloc, received NULL pointer\n");
  		return -1;
  	}
  	if(unlikely(size<2)){
  		fprintf(stderr,"ERROR in rc_ringbuf_alloc, size must be >=2\n");
  		return -1;
  	}
  	// if it's already allocated, nothing to do
  	if(buf->initialized && buf->size==size && buf->d!=NULL) return 0;
  	// make sure it's zero'd out
  	buf->size = 0;
  	buf->index = 0;
  	buf->initialized = 0;
  	// free memory and allocate fresh
  	free(buf->d);
  	buf->d = (float*)calloc(size,sizeof(float));
  	if(buf->d==NULL){
  		fprintf(stderr,"ERROR in rc_ringbuf_alloc, failed to allocate memory\n");
  		return -1;
  	}
  	// write out other details
  	buf->size = size;
  	buf->initialized = 1;
  	return 0;
  }
  
  
  int rc_ringbuf_free(rc_ringbuf_t* buf)
  {
  	if(unlikely(buf==NULL)){
  		fprintf(stderr, "ERROR in rc_ringbuf_free, received NULL pointer\n");
  		return -1;
  	}
  	if(buf->initialized) free(buf->d);
  	*buf=rc_ringbuf_empty();
  	return 0;
  }
  
  
  int rc_ringbuf_reset(rc_ringbuf_t* buf)
  {
  	// sanity checks
  	if(unlikely(buf==NULL)){
  		fprintf(stderr, "ERROR in rc_ringbuf_reset, received NULL pointer\n");
  		return -1;
  	}
  	if(unlikely(!buf->initialized)){
  		fprintf(stderr,"ERROR rc_ringbuf_reset, ringbuf uninitialized\n");
  		return -1;
  	}
  	// wipe the data and index
  	memset(buf->d,0,buf->size*sizeof(float));
  	buf->index=0;
  	return 0;
  }
  
  
  int rc_ringbuf_insert(rc_ringbuf_t* buf, float val)
  {
  	int new_index;
  	// sanity checks
  	if(unlikely(buf==NULL)){
  		fprintf(stderr,"ERROR in rc_ringbuf_insert, received NULL pointer\n");
  		return -1;
  	}
  	if(unlikely(!buf->initialized)){
  		fprintf(stderr,"ERROR in rc_ringbuf_insert, ringbuf uninitialized\n");
  		return -1;
  	}
  	// increment index and check for loop-around
  	new_index=buf->index+1;
  	if(new_index>=buf->size) new_index=0;
  	// write out new value
  	buf->d[new_index]=val;
  	buf->index=new_index;
  	return 0;
  }
  
  
  float rc_ringbuf_get_value(rc_ringbuf_t* buf, int pos)
  {
  	int return_index;
  	// sanity checks
  	if(unlikely(buf==NULL)){
  		fprintf(stderr,"ERROR in rc_ringbuf_get_value, received NULL pointer\n");
  		return -1.0f;
  	}
  	if(unlikely(pos<0 || pos>buf->size-1)){
  		fprintf(stderr,"ERROR in rc_ringbuf_get_value, position out of bounds\n");
  		return -1.0f;
  	}
  	if(unlikely(!buf->initialized)){
  		fprintf(stderr,"ERROR in rc_ringbuf_get_value, ringbuf uninitialized\n");
  		return -1.0f;
  	}
  	// check for looparound
  	return_index=buf->index-pos;
  	if(return_index<0) return_index+=buf->size;
  	return buf->d[return_index];
  }
  
  
  float rc_ringbuf_std_dev(rc_ringbuf_t buf)
  {
  	int i;
  	float mean, mean_sqr, diff;
  	// sanity checks
  	if(unlikely(!buf.initialized)){
  		fprintf(stderr,"ERROR in rc_ringbuf_std_dev, ringbuf not initialized yet\n");
  		return -1.0f;
  	}
  	// shortcut if buffer is of length 1
  	if(buf.size == 1) return 0.0f;
  	// calculate mean
  	mean = 0.0f;
  	for(i=0;i<buf.size;i++) mean+=buf.d[i];
  	mean = mean/(float)buf.size;
  	// calculate mean square
  	mean_sqr = 0.0f;
  	for(i=0;i<buf.size;i++){
  		diff = buf.d[i]-mean;
  		mean_sqr += diff*diff;
  	}
  	return sqrt(mean_sqr/(float)(buf.size-1));
  }
  
  
  