|
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 |
}
|