#include #include #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; }