- implementation of growable queues; to replace fix-sized queues used
in recursive traversal functions.
This commit is contained in:
parent
91f2c7c382
commit
f96061a1bd
2 changed files with 135 additions and 0 deletions
123
src/pobj/queue.c
Normal file
123
src/pobj/queue.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
#include "xmem.h"
|
||||
|
||||
#define QUEUE_SEG_MAX_EXP 10
|
||||
#define QUEUE_SEG_MAX (1 << QUEUE_SEG_MAX_EXP)
|
||||
|
||||
struct queue_seg {
|
||||
int head;
|
||||
int tail;
|
||||
struct queue_seg *next;
|
||||
};
|
||||
#define SEG_OFFSET ALIGN(sizeof(struct queue_seg))
|
||||
#define SEG_TOTAL_SIZE(n) (SEG_OFFSET + ((n) * sizeof(unsigned long)))
|
||||
#define SEG_BUF(s) ((unsigned long *) ((char *)s + SEG_OFFSET))
|
||||
|
||||
struct queue {
|
||||
struct queue_seg *head_seg;
|
||||
struct queue_seg *tail_seg;
|
||||
int segsize;
|
||||
};
|
||||
|
||||
static struct queue_seg *
|
||||
queue_seg_alloc (int segsize)
|
||||
{
|
||||
struct queue_seg *seg;
|
||||
|
||||
seg = (struct queue_seg *) XMALLOC (SEG_TOTAL_SIZE (segsize));
|
||||
if (! seg)
|
||||
return NULL;
|
||||
|
||||
memset (seg, 0, sizeof (struct queue_seg));
|
||||
return seg;
|
||||
}
|
||||
|
||||
struct queue *
|
||||
queue_new (int segsize)
|
||||
{
|
||||
struct queue *q;
|
||||
|
||||
q = (struct queue *) XMALLOC (sizeof (struct queue));
|
||||
if (q)
|
||||
q->tail_seg = q->head_seg = queue_seg_alloc (segsize);
|
||||
if (! (q && q->head_seg)) {
|
||||
if (q)
|
||||
XFREE (q);
|
||||
debug ("allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
q->segsize = segsize;
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
queue_free (struct queue *q)
|
||||
{
|
||||
struct queue_seg *seg, *next;
|
||||
|
||||
for (seg = q->head_seg; seg; seg = next) {
|
||||
next = seg->next;
|
||||
XFREE (seg);
|
||||
}
|
||||
XFREE (q);
|
||||
}
|
||||
|
||||
|
||||
unsigned long
|
||||
queue_deq (struct queue *q)
|
||||
{
|
||||
struct queue_seg *seg = q->head_seg;
|
||||
unsigned long *buf = SEG_BUF (seg);
|
||||
unsigned long val;
|
||||
|
||||
/* Verify head segment is not empty. */
|
||||
if (seg->head == seg->tail && ! seg->next) {
|
||||
debug ("queue empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dequeue head value. */
|
||||
val = buf[seg->head++];
|
||||
if (seg->head == q->segsize)
|
||||
seg->head = 0;
|
||||
debug ("dequeued %lu (%p)", val, (void *) val);
|
||||
|
||||
/* Deallocate empty head segment, if it isn't the last one. */
|
||||
if (seg->head == seg->tail && seg->next) {
|
||||
q->head_seg = seg->next;
|
||||
XFREE (seg);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int
|
||||
queue_enq (struct queue *q, unsigned long val)
|
||||
{
|
||||
struct queue_seg *seg = q->tail_seg;
|
||||
unsigned long *buf = SEG_BUF (seg);
|
||||
|
||||
/* Enqueue value. */
|
||||
buf[seg->head++] = val;
|
||||
if (seg->head == q->segsize)
|
||||
seg->head = 0;
|
||||
|
||||
debug ("enqueued %lu (%p)", val, (void *) val);
|
||||
|
||||
/* Allocate new segment if current was exhausted. */
|
||||
if (seg->head == seg->tail) {
|
||||
seg->next = queue_seg_alloc (q->segsize);
|
||||
if (! seg->next) {
|
||||
if (! seg->head--)
|
||||
seg->head += q->segsize;
|
||||
debug ("segment allocation failed, enqueue undone");
|
||||
return -1;
|
||||
}
|
||||
q->tail_seg = seg->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
12
src/pobj/queue.h
Normal file
12
src/pobj/queue.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef __QUEUE_H
|
||||
#define __QUEUE_H
|
||||
|
||||
struct queue;
|
||||
|
||||
struct queue *queue_new (int);
|
||||
void queue_free (struct queue *);
|
||||
unsigned long queue_deq (struct queue *);
|
||||
int queue_enq (struct queue *, unsigned long);
|
||||
|
||||
#endif /* __QUEUE_H */
|
||||
|
Loading…
Reference in a new issue