summaryrefslogtreecommitdiffstats
path: root/src/memblockq.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-06-08 23:54:24 +0000
committerLennart Poettering <lennart@poettering.net>2004-06-08 23:54:24 +0000
commit9cb0b933e260008c6a03e24a4a149f726b8d86b2 (patch)
treeb54651bafe32d1a817e779f884d1628176465bf0 /src/memblockq.c
parentb1c00dcd0ae51d201f772e7f5fa61acae436a2cf (diff)
initial commit
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@3 fefdeb5f-60dc-0310-8127-8f9354f1896f
Diffstat (limited to 'src/memblockq.c')
-rw-r--r--src/memblockq.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/memblockq.c b/src/memblockq.c
new file mode 100644
index 00000000..1424c556
--- /dev/null
+++ b/src/memblockq.c
@@ -0,0 +1,156 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#include "memblockq.h"
+
+struct memblock_list {
+ struct memblock_list *next;
+ struct memchunk chunk;
+};
+
+struct memblockq {
+ struct memblock_list *blocks, *blocks_tail;
+ unsigned n_blocks;
+ size_t total_length;
+ size_t maxlength;
+ size_t base;
+};
+
+struct memblockq* memblockq_new(size_t maxlength, size_t base) {
+ struct memblockq* bq;
+ assert(maxlength && base);
+
+ bq = malloc(sizeof(struct memblockq));
+ assert(bq);
+ bq->blocks = bq->blocks_tail = 0;
+ bq->n_blocks = 0;
+ bq->total_length = 0;
+ bq->base = base;
+ bq->maxlength = ((maxlength+base-1)/base)*base;
+ assert(bq->maxlength >= base);
+ return bq;
+}
+
+void memblockq_free(struct memblockq* bq) {
+ struct memblock_list *l;
+ assert(bq);
+
+ while ((l = bq->blocks)) {
+ bq->blocks = l->next;
+ memblock_unref(l->chunk.memblock);
+ free(l);
+ }
+
+ free(bq);
+}
+
+void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) {
+ struct memblock_list *q;
+ assert(bq && chunk && chunk->memblock && chunk->index);
+
+ q = malloc(sizeof(struct memblock_list));
+ assert(q);
+
+ q->chunk = *chunk;
+ memblock_ref(q->chunk.memblock);
+ assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length);
+ q->next = NULL;
+
+ if (bq->blocks_tail)
+ bq->blocks_tail->next = q;
+ else
+ bq->blocks = q;
+
+ bq->blocks_tail = q;
+
+ bq->n_blocks++;
+ bq->total_length += chunk->length;
+
+ memblockq_shorten(bq, bq->maxlength);
+}
+
+int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) {
+ assert(bq && chunk);
+
+ if (!bq->blocks)
+ return -1;
+
+ *chunk = bq->blocks->chunk;
+ memblock_ref(chunk->memblock);
+ return 0;
+}
+
+int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) {
+ struct memblock_list *q;
+
+ assert(bq && chunk);
+
+ if (!bq->blocks)
+ return -1;
+
+ q = bq->blocks;
+ bq->blocks = bq->blocks->next;
+
+ *chunk = q->chunk;
+
+ bq->n_blocks--;
+ bq->total_length -= chunk->length;
+
+ free(q);
+ return 0;
+}
+
+void memblockq_drop(struct memblockq *bq, size_t length) {
+ assert(bq);
+
+ while (length > 0) {
+ size_t l = length;
+ assert(bq->blocks && bq->total_length >= length);
+
+ if (l > bq->blocks->chunk.length)
+ l = bq->blocks->chunk.length;
+
+ bq->blocks->chunk.index += l;
+ bq->blocks->chunk.length -= l;
+ bq->total_length -= l;
+
+ if (bq->blocks->chunk.length == 0) {
+ struct memblock_list *q;
+
+ q = bq->blocks;
+ bq->blocks = bq->blocks->next;
+ memblock_unref(q->chunk.memblock);
+ free(q);
+
+ bq->n_blocks--;
+ }
+
+ length -= l;
+ }
+}
+
+void memblockq_shorten(struct memblockq *bq, size_t length) {
+ size_t l;
+ assert(bq);
+
+ if (bq->total_length <= length)
+ return;
+
+ l = bq->total_length - length;
+ l /= bq->base;
+ l *= bq->base;
+
+ memblockq_drop(bq, l);
+}
+
+
+void memblockq_empty(struct memblockq *bq) {
+ assert(bq);
+ memblockq_shorten(bq, 0);
+}
+
+int memblockq_is_empty(struct memblockq *bq) {
+ assert(bq);
+
+ return bq->total_length >= bq->base;
+}