Archived
1
0
Fork 0
This repository has been archived on 2026-05-10. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
archived/src/queue.c
Henrik Hautakoski f973e29668 src/queue.c: don't deallocate the last block when queue becomes empty.
always keep one block in the queue so that in situations when the queue becomes empty
frequently. performance dosent blow up by calls to malloc/free.
2011-01-13 15:37:00 +01:00

131 lines
2.5 KiB
C

/* queue.c
*
* Copyright (C) 2010 Henrik Hautakoski <henrik@fiktivkod.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "xalloc.h"
#include "queue.h"
#define BLOCK_SIZE (1<<7)
/* linked list node holding a chunk of queue elements */
struct node {
void *block[BLOCK_SIZE];
struct node *next;
};
struct ref {
unsigned int i;
struct node *n;
};
struct __queue {
struct ref tail;
struct ref head;
};
static void alloc_node(struct ref *head) {
struct node *n = xmalloc(sizeof(struct node));
n->next = NULL;
head->n = head->n->next = n;
head->i = 0;
}
static void dealloc_node(struct ref *tail) {
struct node *next = tail->n->next;
if (next) {
xfree(tail->n);
tail->n = next;
tail->i = 0;
}
}
queue_t queue_init() {
queue_t q = xmalloc(sizeof(struct __queue));
q->tail.n = q->head.n = xmalloc(sizeof(struct node));
q->tail.n->next = q->head.n->next = NULL;
q->tail.i = q->head.i = 0;
return q;
}
void queue_destroy(queue_t q) {
if (q) {
struct node *n = q->tail.n;
while(n) {
struct node *next = n->next;
xfree(n);
n = next;
}
xfree(q);
}
}
void queue_enqueue(queue_t q, void *obj) {
if (q == NULL)
return;
if (q->head.i >= BLOCK_SIZE) {
alloc_node(&q->head);
}
q->head.n->block[q->head.i++] = obj;
}
void* queue_dequeue(queue_t q) {
void *obj;
if (queue_isempty(q))
return NULL;
obj = q->tail.n->block[q->tail.i++];
if (q->tail.n == q->head.n && q->tail.i > q->head.i) {
q->tail.i = q->head.i = 0;
} else if (q->tail.i >= BLOCK_SIZE) {
dealloc_node(&q->tail);
}
return obj;
}
int queue_isempty(queue_t q) {
if (q == NULL)
return -1;
return q->head.n == q->tail.n && q->head.i == q->tail.i;
}
size_t queue_num_items(queue_t q) {
size_t len;
struct node *n;
if (queue_isempty(q))
return 0;
if (q->head.n == q->tail.n)
return q->head.i - q->tail.i;
len = (BLOCK_SIZE - q->tail.i) + q->head.i;
for(n = q->tail.n->next; n != q->head.n; n = n->next)
len += BLOCK_SIZE;
return len;
}