#include "a/que.h"
static a_list *a_que_new_(a_que *ctx)
{
a_list *node;
if (ctx->cur_ == 0)
{
node = (a_list *)a_alloc(A_NULL, sizeof(a_list) + ctx->siz_);
if (A_UNLIKELY(!node)) { return node; }
}
else
{
node = ctx->ptr_[--ctx->cur_];
}
++ctx->num_;
return node;
}
static int a_que_die_(a_que *ctx, a_list *node)
{
if (A_UNLIKELY(!node)) { return A_INVALID; }
if (ctx->mem_ <= ctx->cur_)
{
a_size const mem = ctx->mem_ + (ctx->mem_ >> 1) + 1;
a_list **const ptr = (a_list **)a_alloc((void *)ctx->ptr_, sizeof(void *) * mem);
if (A_UNLIKELY(!ptr)) { return A_FAILURE; }
ctx->ptr_ = ptr;
ctx->mem_ = mem;
}
ctx->ptr_[ctx->cur_++] = node;
--ctx->num_;
return A_SUCCESS;
}
a_que *a_que_new(a_size size)
{
a_que *const ctx = (a_que *)a_alloc(A_NULL, sizeof(a_que));
if (ctx) { a_que_ctor(ctx, size); }
return ctx;
}
void a_que_die(a_que *ctx, void (*dtor)(void *))
{
if (ctx)
{
a_que_dtor(ctx, dtor);
a_alloc(ctx, 0);
}
}
void a_que_ctor(a_que *ctx, a_size size)
{
if (!size) { size = sizeof(void *); }
a_list_ctor(&ctx->head_);
ctx->ptr_ = A_NULL;
ctx->siz_ = size;
ctx->num_ = 0;
ctx->cur_ = 0;
ctx->mem_ = 0;
}
void a_que_dtor(a_que *ctx, void (*dtor)(void *))
{
if (dtor)
{
for (a_list **node = ctx->ptr_; ctx->cur_; --ctx->cur_)
{
dtor(*node + 1);
a_alloc(*node++, 0);
}
a_list_forsafe_next(node, next, &ctx->head_)
{
dtor(node + 1);
a_alloc(node, 0);
}
}
else
{
for (a_list **node = ctx->ptr_; ctx->cur_; --ctx->cur_)
{
a_alloc(*node++, 0);
}
a_list_forsafe_next(node, next, &ctx->head_)
{
a_alloc(node, 0);
}
}
a_alloc((void *)ctx->ptr_, 0);
ctx->ptr_ = A_NULL;
ctx->siz_ = 0;
ctx->mem_ = 0;
}
void a_que_move(a_que *ctx, a_que *obj)
{
a_copy(ctx, obj, sizeof(*obj));
a_zero(obj, sizeof(*obj));
}
void *a_que_at(a_que const *ctx, a_diff idx)
{
a_diff cur = 0;
if (idx >= 0)
{
a_list_foreach_next(it, &ctx->head_)
{
if (cur++ == idx) { return it + 1; }
}
}
else
{
a_list_foreach_prev(it, &ctx->head_)
{
if (--cur == idx) { return it + 1; }
}
}
return A_NULL;
}
int a_que_drop(a_que *ctx, void (*dtor)(void *))
{
a_list *const head = &ctx->head_;
for (a_list *node = head->next; node != head; node = head->next)
{
if (a_que_die_(ctx, node) == A_SUCCESS)
{
a_list_del_node(node);
a_list_dtor(node);
}
else { return A_FAILURE; }
}
if (dtor)
{
a_size cur = ctx->cur_;
a_list **node = ctx->ptr_;
for (; cur; ++node, --cur)
{
dtor(*node + 1);
}
}
return A_SUCCESS;
}
int a_que_edit(a_que *ctx, a_size size, void (*dtor)(void *))
{
int ok = a_que_drop(ctx, dtor);
if (ok == A_SUCCESS)
{
if (!size) { size = sizeof(void *); }
if (size > ctx->siz_)
{
a_size cur = ctx->cur_;
a_list **node = ctx->ptr_;
for (; cur; ++node, --cur)
{
void *const ptr = a_alloc(*node, sizeof(a_list) + size);
if (A_UNLIKELY(!ptr)) { return A_FAILURE; }
*node = (a_list *)ptr;
}
}
ctx->siz_ = size;
}
return ok;
}
int a_que_swap(a_que const *ctx, a_size lhs, a_size rhs)
{
a_size cur = 0;
int ok = A_FAILURE;
a_list *at = A_NULL;
a_size const num = ctx->num_ - 1;
lhs = lhs < ctx->num_ ? lhs : num;
rhs = rhs < ctx->num_ ? rhs : num;
if (lhs == rhs) { return A_SUCCESS; }
a_list_foreach_next(it, &ctx->head_)
{
if (cur == lhs || cur == rhs)
{
if (at)
{
a_list_swap_node(it, at);
ok = A_SUCCESS;
break;
}
else { at = it; }
}
++cur;
}
return ok;
}
void a_que_sort_fore(a_que const *ctx, int (*cmp)(void const *, void const *))
{
if (ctx->num_ > 1)
{
a_list *const it = ctx->head_.next;
a_list *at = it->next;
do {
if (cmp(it + 1, at + 1) <= 0) { break; }
at = at->next;
} while (at != &ctx->head_);
if (at != it->next)
{
at = at->prev; a_list_link(it->prev, it->next); a_list_link(it, at->next); a_list_link(at, it); }
}
}
void a_que_sort_back(a_que const *ctx, int (*cmp)(void const *, void const *))
{
if (ctx->num_ > 1)
{
a_list *const it = ctx->head_.prev;
a_list *at = it->prev;
do {
if (cmp(at + 1, it + 1) <= 0) { break; }
at = at->prev;
} while (at != &ctx->head_);
if (at != it->prev)
{
at = at->next; a_list_link(it->prev, it->next); a_list_link(at->prev, it); a_list_link(it, at); }
}
}
void *a_que_push_sort(a_que *ctx, void const *key, int (*cmp)(void const *, void const *))
{
a_list *it = ctx->head_.prev;
a_list *const node = a_que_new_(ctx);
if (A_UNLIKELY(!node)) { return node; }
if (ctx->num_ > 1)
{
do {
if (cmp(it + 1, key) <= 0) { break; }
it = it->prev;
} while (it != &ctx->head_);
}
a_list_link(node, it->next);
a_list_link(it, node);
return node + 1;
}
void *a_que_push_fore(a_que *ctx)
{
a_list *const node = a_que_new_(ctx);
if (A_UNLIKELY(!node)) { return node; }
a_list_add_next(&ctx->head_, node);
return node + 1;
}
void *a_que_push_back(a_que *ctx)
{
a_list *const node = a_que_new_(ctx);
if (A_UNLIKELY(!node)) { return node; }
a_list_add_prev(&ctx->head_, node);
return node + 1;
}
void *a_que_pull_fore(a_que *ctx)
{
if (ctx->head_.next != &ctx->head_)
{
a_list *const node = (a_list *)ctx->head_.next;
if (a_que_die_(ctx, node) == A_SUCCESS)
{
a_list_del_node(node);
a_list_dtor(node);
return node + 1;
}
}
return A_NULL;
}
void *a_que_pull_back(a_que *ctx)
{
if (ctx->head_.prev != &ctx->head_)
{
a_list *const node = (a_list *)ctx->head_.prev;
if (a_que_die_(ctx, node) == A_SUCCESS)
{
a_list_del_node(node);
a_list_dtor(node);
return node + 1;
}
}
return A_NULL;
}
void *a_que_insert(a_que *ctx, a_size idx)
{
if (idx < ctx->num_)
{
a_size cur = 0;
a_list *const node = a_que_new_(ctx);
if (node)
{
a_list_foreach_next(it, &ctx->head_)
{
if (cur++ == idx)
{
a_list_add_prev(it, node);
break;
}
}
return node + 1;
}
return A_NULL;
}
return a_que_push_back(ctx);
}
void *a_que_remove(a_que *ctx, a_size idx)
{
if (idx < ctx->num_)
{
a_size cur = 0;
a_list *node = A_NULL;
a_list_foreach_next(it, &ctx->head_)
{
if (cur++ == idx)
{
node = it;
break;
}
}
if (a_que_die_(ctx, node) == A_SUCCESS)
{
a_list_del_node(node);
a_list_dtor(node);
return node + 1;
}
return A_NULL;
}
return a_que_pull_back(ctx);
}