Blame filter/ringbuf.c

Packit 67cb25
/* movstat/ringbuf.c
Packit 67cb25
 *
Packit 67cb25
 * Ring buffer module
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 2018 Patrick Alken
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#ifndef __GSL_RINGBUF_C__
Packit 67cb25
#define __GSL_RINGBUF_C__
Packit 67cb25
Packit 67cb25
/*typedef int ringbuf_type;*/
Packit 67cb25
Packit 67cb25
typedef struct
Packit 67cb25
{
Packit 67cb25
  ringbuf_type_t *array;
Packit 67cb25
  int head;
Packit 67cb25
  int tail;
Packit 67cb25
  int size;       /* total elements allocated */
Packit 67cb25
} ringbuf;
Packit 67cb25
Packit 67cb25
static size_t ringbuf_size(const size_t n);
Packit 67cb25
static int ringbuf_empty(ringbuf * d);
Packit 67cb25
static int ringbuf_is_empty(const ringbuf * d);
Packit 67cb25
static int ringbuf_is_full(const ringbuf * d);
Packit 67cb25
static int ringbuf_insert(const ringbuf_type_t x, ringbuf * d);
Packit 67cb25
static int ringbuf_pop_back(ringbuf * b);
Packit 67cb25
static ringbuf_type_t ringbuf_peek(const int i, const ringbuf * b);
Packit 67cb25
static ringbuf_type_t ringbuf_peek_front(const ringbuf * d);
Packit 67cb25
static ringbuf_type_t ringbuf_peek_back(const ringbuf * d);
Packit 67cb25
static size_t ringbuf_copy(double * dest, const ringbuf * b);
Packit 67cb25
Packit 67cb25
static size_t
Packit 67cb25
ringbuf_size(const size_t n)
Packit 67cb25
{
Packit 67cb25
  size_t size = 0;
Packit 67cb25
Packit 67cb25
  size += sizeof(ringbuf);
Packit 67cb25
  size += n * sizeof(ringbuf_type_t); /* b->array */
Packit 67cb25
Packit 67cb25
  return size;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
ringbuf_init(const size_t n, ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  b->array = (ringbuf_type_t *) ((char *) b + sizeof(ringbuf));
Packit 67cb25
  b->head = -1;
Packit 67cb25
  b->tail = 0;
Packit 67cb25
  b->size = (int) n;
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* empty the buffer */
Packit 67cb25
static int
Packit 67cb25
ringbuf_empty(ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  b->head = -1;
Packit 67cb25
  b->tail = 0;
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* check if buffer is empty */
Packit 67cb25
static int
Packit 67cb25
ringbuf_is_empty(const ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  return (b->head == -1);
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* check if buffer is full */
Packit 67cb25
static int
Packit 67cb25
ringbuf_is_full(const ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  return ((b->head == 0 && b->tail == b->size - 1) ||
Packit 67cb25
          (b->head == b->tail + 1));
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* insert element into buffer, overwriting oldest element if necessary */
Packit 67cb25
static int
Packit 67cb25
ringbuf_insert(const ringbuf_type_t x, ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  if (b->head == -1)     /* buffer is empty */
Packit 67cb25
    {
Packit 67cb25
      b->head = 0;
Packit 67cb25
      b->tail = 0;
Packit 67cb25
    }
Packit 67cb25
  else if (b->head == 0) /* head is in first position, wrap to end */
Packit 67cb25
    {
Packit 67cb25
      b->head = b->size - 1;
Packit 67cb25
Packit 67cb25
      if (b->tail == b->head && b->size > 1)
Packit 67cb25
        --(b->tail);     /* buffer is full so decrease tail */
Packit 67cb25
    }
Packit 67cb25
  else                   /* decrement head */
Packit 67cb25
    {
Packit 67cb25
      --(b->head);
Packit 67cb25
Packit 67cb25
      if (b->tail == b->head)
Packit 67cb25
        {
Packit 67cb25
          /* buffer is full so update tail */
Packit 67cb25
          if (b->tail == 0)
Packit 67cb25
            b->tail = b->size - 1;
Packit 67cb25
          else
Packit 67cb25
            --(b->tail);
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* insert element */
Packit 67cb25
  b->array[b->head] = x;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
ringbuf_pop_back(ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  if (ringbuf_is_empty(b) || b->tail < 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("buffer is empty", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      if (b->head == b->tail) /* buffer has only one element */
Packit 67cb25
        {
Packit 67cb25
          b->head = -1;
Packit 67cb25
          b->tail = -1;
Packit 67cb25
        }
Packit 67cb25
      else if (b->tail == 0)  /* tail is in first position, wrap to end */
Packit 67cb25
        {
Packit 67cb25
          b->tail = b->size - 1;
Packit 67cb25
        }
Packit 67cb25
      else                    /* decrement tail */
Packit 67cb25
        {
Packit 67cb25
          --(b->tail);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static ringbuf_type_t
Packit 67cb25
ringbuf_peek(const int i, const ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  if (ringbuf_is_empty(b))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("buffer is empty", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      return b->array[(b->head + i) % b->size];
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static ringbuf_type_t
Packit 67cb25
ringbuf_peek_front(const ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  if (ringbuf_is_empty(b))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("buffer is empty", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      return b->array[b->head];
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static ringbuf_type_t
Packit 67cb25
ringbuf_peek_back(const ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  if (ringbuf_is_empty(b) || b->tail < 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("buffer is empty", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      return b->array[b->tail];
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static size_t
Packit 67cb25
ringbuf_copy(double * dest, const ringbuf * b)
Packit 67cb25
{
Packit 67cb25
  if (ringbuf_is_empty(b) || b->tail < 0)
Packit 67cb25
    {
Packit 67cb25
      return 0;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      const int n = (b->head > b->tail) ? (b->size - b->head + b->tail + 1) : (b->tail - b->head + 1);
Packit 67cb25
      int i;
Packit 67cb25
Packit 67cb25
      for (i = 0; i < n; ++i)
Packit 67cb25
        dest[n - i - 1] = b->array[(b->head + i) % b->size];
Packit 67cb25
Packit 67cb25
      return (size_t) n;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
#endif /* __GSL_RINGBUF_C__ */