Blame movstat/deque.c

Packit 67cb25
/* movstat/deque.c
Packit 67cb25
 *
Packit 67cb25
 * Double-ended queue based on a circular buffer
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
typedef int deque_type_t;
Packit 67cb25
Packit 67cb25
typedef struct
Packit 67cb25
{
Packit 67cb25
  int head;
Packit 67cb25
  int tail;
Packit 67cb25
  int size;       /* total elements allocated */
Packit 67cb25
  deque_type_t *array;
Packit 67cb25
} deque;
Packit 67cb25
Packit 67cb25
static size_t deque_size(const size_t n);
Packit 67cb25
static int deque_init(const size_t n, deque * d);
Packit 67cb25
static int deque_empty(deque * d);
Packit 67cb25
static int deque_is_empty(const deque * d);
Packit 67cb25
static int deque_is_full(const deque * d);
Packit 67cb25
static int deque_push_front(const deque_type_t x, deque * d);
Packit 67cb25
static int deque_push_back(const deque_type_t x, deque * d);
Packit 67cb25
static int deque_pop_front(deque * d);
Packit 67cb25
static int deque_pop_back(deque * d);
Packit 67cb25
static deque_type_t deque_peek_front(const deque * d);
Packit 67cb25
static deque_type_t deque_peek_back(const deque * d);
Packit 67cb25
Packit 67cb25
static size_t
Packit 67cb25
deque_size(const size_t n)
Packit 67cb25
{
Packit 67cb25
  size_t size = 0;
Packit 67cb25
Packit 67cb25
  size += sizeof(deque);
Packit 67cb25
  size += n * sizeof(deque_type_t); /* array */
Packit 67cb25
Packit 67cb25
  return size;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
deque_init(const size_t n, deque * d)
Packit 67cb25
{
Packit 67cb25
  d->head = -1;
Packit 67cb25
  d->tail = 0;
Packit 67cb25
  d->size = (int) n;
Packit 67cb25
  d->array = (deque_type_t *) ((unsigned char *) d + sizeof(deque));
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* empty the queue */
Packit 67cb25
static int
Packit 67cb25
deque_empty(deque * d)
Packit 67cb25
{
Packit 67cb25
  d->head = -1;
Packit 67cb25
  d->tail = 0;
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* check if queue is empty */
Packit 67cb25
static int
Packit 67cb25
deque_is_empty(const deque * d)
Packit 67cb25
{
Packit 67cb25
  return (d->head == -1);
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* check if queue is full */
Packit 67cb25
static int
Packit 67cb25
deque_is_full(const deque * d)
Packit 67cb25
{
Packit 67cb25
  return ((d->head == 0 && d->tail == d->size - 1) ||
Packit 67cb25
          (d->head == d->tail + 1));
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
deque_push_front(const deque_type_t x, deque * d)
Packit 67cb25
{
Packit 67cb25
  if (deque_is_full(d))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("deque is full", GSL_EOVRFLW);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      if (d->head == -1)     /* queue is empty */
Packit 67cb25
        {
Packit 67cb25
          d->head = 0;
Packit 67cb25
          d->tail = 0;
Packit 67cb25
        }
Packit 67cb25
      else if (d->head == 0) /* head is in first position, wrap to end */
Packit 67cb25
        {
Packit 67cb25
          d->head = d->size - 1;
Packit 67cb25
        }
Packit 67cb25
      else                   /* decrement head */
Packit 67cb25
        {
Packit 67cb25
          --(d->head);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* insert element */
Packit 67cb25
      d->array[d->head] = x;
Packit 67cb25
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
deque_push_back(const deque_type_t x, deque * d)
Packit 67cb25
{
Packit 67cb25
  if (deque_is_full(d))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("deque is full", GSL_EOVRFLW);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      if (d->head == -1)               /* queue is empty */
Packit 67cb25
        {
Packit 67cb25
          d->head = 0;
Packit 67cb25
          d->tail = 0;
Packit 67cb25
        }
Packit 67cb25
      else if (d->tail == d->size - 1) /* tail is in last position, wrap to 0 */
Packit 67cb25
        {
Packit 67cb25
          d->tail = 0;
Packit 67cb25
        }
Packit 67cb25
      else                             /* increment tail */
Packit 67cb25
        {
Packit 67cb25
          ++(d->tail);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* insert element */
Packit 67cb25
      d->array[d->tail] = x;
Packit 67cb25
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
deque_pop_front(deque * d)
Packit 67cb25
{
Packit 67cb25
  if (deque_is_empty(d))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("cannot pop element from empty queue", GSL_EOVRFLW);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      if (d->head == d->tail)          /* queue has only one element */
Packit 67cb25
        {
Packit 67cb25
          d->head = -1;
Packit 67cb25
          d->tail = -1;
Packit 67cb25
        }
Packit 67cb25
      else if (d->head == d->size - 1) /* head is in last position, wrap to 0 */
Packit 67cb25
        {
Packit 67cb25
          d->head = 0;
Packit 67cb25
        }
Packit 67cb25
      else                             /* increment head */
Packit 67cb25
        {
Packit 67cb25
          ++(d->head);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static int
Packit 67cb25
deque_pop_back(deque * d)
Packit 67cb25
{
Packit 67cb25
  if (deque_is_empty(d))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("cannot pop element from empty queue", GSL_EOVRFLW);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      if (d->head == d->tail)    /* queue has only one element */
Packit 67cb25
        {
Packit 67cb25
          d->head = -1;
Packit 67cb25
          d->tail = -1;
Packit 67cb25
        }
Packit 67cb25
      else if (d->tail == 0)     /* tail is in first position, wrap to end */
Packit 67cb25
        {
Packit 67cb25
          d->tail = d->size - 1;
Packit 67cb25
        }
Packit 67cb25
      else                       /* decrement tail */
Packit 67cb25
        {
Packit 67cb25
          --(d->tail);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static deque_type_t
Packit 67cb25
deque_peek_front(const deque * d)
Packit 67cb25
{
Packit 67cb25
  if (deque_is_empty(d))
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("queue is empty", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      return d->array[d->head];
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
static deque_type_t
Packit 67cb25
deque_peek_back(const deque * d)
Packit 67cb25
{
Packit 67cb25
  if (deque_is_empty(d) || d->tail < 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR("queue is empty", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      return d->array[d->tail];
Packit 67cb25
    }
Packit 67cb25
}