/**********
 * Copyright (c) 2004 Greg Parker.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **********/

#include "includes.h"
#include "assert.h"
#include "queue.h"
#include "ssh/openssh/buffer.h"

struct queue_t {
    Buffer b;
};


queue_t *queue_new(void)
{
    queue_t *q = arena_calloc(sizeof(queue_t));
    buffer_init(&q->b);
    return q;
}

void queue_free(queue_t *q)
{
    if (q) {
        buffer_free(&q->b);
        arena_free(q);
    }
}

uint16_t queue_count(queue_t *q)
{
    return buffer_len(&q->b) / sizeof(void *);
}

Boolean queue_empty(queue_t *q)
{
    return buffer_len(&q->b) == 0;
}

void queue_enqueue(queue_t *q, void *e)
{
    buffer_append(&q->b, &e, sizeof(void *));
}

void *queue_dequeue(queue_t *q)
{
    void *result;
    assert(queue_count(q) > 0);
    buffer_get(&q->b, &result, sizeof(void *));
    return result;
}

void *queue_peek(queue_t *q, uint16_t index)
{
    assert(index < queue_count(q));
    return ((void **)buffer_ptr(&q->b))[index];
}

void queue_remove_if_present(queue_t *q, void *e)
{
    void **p = buffer_ptr(&q->b);
    void **end = (void **)(buffer_len(&q->b) + (uint8_t *)buffer_ptr(&q->b));

    for ( ; p < end; p++) {
        if (*p == e) {
            memcpy(p, p+1, (end - p+1) * sizeof(void *));
            buffer_consume_end(&q->b, sizeof(void *));
            return;
        }
    }
}
