myxce/src/lib/ordq.c

199 lines
3.3 KiB
C

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "mylock.h"
#include "ordq.h"
int ordq_init(ordq_t* q, ordq_data_killer_t killer, ordq_cmp_fn_t cmp)
{
if ((q == NULL) || (cmp == NULL)) {
return -EINVAL;
}
mylock_init(&(q->lock));
q->head = NULL;
q->killer = killer;
q->cmp = cmp;
q->ctx = NULL;
return 0;
}
static int ordq_put_(ordq_t* q, ordq_item_t* it)
{
ordq_item_t** p = &(q->head);
while ((*p) != NULL) {
if (q->cmp(q->ctx, (*p)->data, it->data) > 0) {
/* we found the location to insert */
break;
}
p = &((*p)->next);
}
it->next = *p;
*p = it;
return 0;
}
int ordq_put(ordq_t* q, void* data)
{
int rc = 0;
ordq_item_t* it;
it = (ordq_item_t*)calloc(1, sizeof(*it));
if (it == NULL) {
return -ENOMEM;
}
it->data = data;
mylock_lock(&(q->lock));
rc = ordq_put_(q, it);
mylock_unlock(&(q->lock));
return rc;
}
void ordq_fini(ordq_t* q)
{
ordq_item_t* p = q->head;
while (p != NULL) {
ordq_item_t* p1 = p->next;
if (q->killer != NULL) {
q->killer(p->data);
}
p->data = NULL;
free(p);
p = p1;
}
mylock_fini(&(q->lock));
}
static ordq_item_t* ordq_get_(ordq_t* q, ordq_match_fn_t matchfn, va_list ap)
{
ordq_item_t** p = NULL;
ordq_item_t* it = NULL;
p = &(q->head);
while ((*p) != NULL) {
va_list ap1;
int rc = 0;
if (matchfn == NULL) {
break;
}
va_copy(ap1, ap);
rc = matchfn((*p)->data, ap1);
va_end(ap1);
if (rc) {
break;
}
p = &((*p)->next);
}
it = *p;
if (it != NULL) {
*p = it->next;
it->next = NULL;
}
return it;
}
ordq_item_t* ordq_get(ordq_t* q, ordq_match_fn_t matchfn, ...)
{
ordq_item_t* it;
va_list ap;
va_start(ap, matchfn);
mylock_lock(&(q->lock));
it = ordq_get_(q, matchfn, ap);
mylock_unlock(&(q->lock));
va_end(ap);
return it;
}
int ordq_del(ordq_t* q, ordq_match_fn_t matchfn, ...)
{
ordq_item_t* it = NULL;
int count = 0;
va_list ap, ap1;
va_start(ap, matchfn);
va_copy(ap1, ap);
mylock_lock(&(q->lock));
while ((it = ordq_get_(q, matchfn, ap1)) != NULL) {
if (q->killer != NULL) {
q->killer(it->data);
}
free(it);
count++;
va_copy(ap1, ap);
}
mylock_unlock(&(q->lock));
va_end(ap1);
va_end(ap);
return count;
}
ordq_item_t* ordq_peek(ordq_t* q, ordq_match_fn_t matchfn, ...)
{
ordq_item_t* it = NULL;
va_list ap;
va_start(ap, matchfn);
mylock_lock(&(q->lock));
it = q->head;
while (it != NULL) {
int rc = 0;
va_list ap1;
if (matchfn == NULL) {
break;
}
va_copy(ap1, ap);
rc = matchfn(it->data, ap1);
va_end(ap1);
if (rc) {
break;
}
it = it->next;
}
mylock_unlock(&(q->lock));
va_end(ap);
return it;
}
void ordq_set_ctx(ordq_t* q, void* ctx)
{
if (q == NULL) {
return;
}
mylock_lock(&(q->lock));
q->ctx = ctx;
mylock_unlock(&(q->lock));
}