diff options
author | Andrew Mahone <andrew.mahone@gmail.com> | 2009-05-16 00:45:08 +0000 |
---|---|---|
committer | Andrew Mahone <andrew.mahone@gmail.com> | 2009-05-16 00:45:08 +0000 |
commit | c909878f94073a364f9b3c75663080c044bff3b8 (patch) | |
tree | 9ba9ad0efd7def7c77816ddd83e9bf0eb1fa51b2 | |
parent | d59bff092d461c013c0fed34ffa950e1f4ae2aa2 (diff) |
Extend buflib to support shifting space out off the buffer for other use, and returning space to the buffer.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20952 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/plugins/lib/buflib.c | 48 | ||||
-rw-r--r-- | apps/plugins/lib/buflib.h | 5 |
2 files changed, 53 insertions, 0 deletions
diff --git a/apps/plugins/lib/buflib.c b/apps/plugins/lib/buflib.c index 514479600e..ddfc82c521 100644 --- a/apps/plugins/lib/buflib.c +++ b/apps/plugins/lib/buflib.c @@ -61,6 +61,7 @@ buflib_init(struct buflib_context *ctx, void *buf, size_t size) ctx->last_handle = bd_buf + size; ctx->first_free_handle = bd_buf + size - 1; ctx->first_free_block = bd_buf; + ctx->buf_start = bd_buf; /* A marker is needed for the end of allocated data, to make sure that it * does not collide with the handle table, and to detect end-of-buffer. */ @@ -167,6 +168,53 @@ buflib_compact(struct buflib_context *ctx) return ret || shift; } +/* Shift buffered items by size units, and update handle pointers. The shift + * value must be determined to be safe *before* calling. + */ +static void +buflib_buffer_shift(struct buflib_context *ctx, int shift) +{ + rb->memmove(ctx->buf_start + shift, ctx->buf_start, + (ctx->alloc_end - ctx->buf_start) * sizeof(union buflib_data)); + union buflib_data *ptr; + for (ptr = ctx->last_handle; ptr < ctx->handle_table; ptr++) + if (ptr->ptr) + ptr->ptr += shift; + ctx->first_free_block += shift; + ctx->buf_start += shift; + ctx->alloc_end += shift; +} + +/* Shift buffered items up by size bytes, or as many as possible if size == 0. + * Set size to the number of bytes freed. + */ +void* +buflib_buffer_out(struct buflib_context *ctx, size_t *size) +{ + if (!ctx->compact) + buflib_compact(ctx); + size_t avail = ctx->last_handle - ctx->alloc_end; + size_t avail_b = avail * sizeof(union buflib_data); + if (*size && *size < avail_b) + { + avail = (*size + sizeof(union buflib_data) - 1) + / sizeof(union buflib_data); + avail_b = avail * sizeof(union buflib_data); + } + *size = avail_b; + void *ret = ctx->buf_start; + buflib_buffer_shift(ctx, avail); + return ret; +} + +/* Shift buffered items down by size bytes */ +void +buflib_buffer_in(struct buflib_context *ctx, int size) +{ + size /= sizeof(union buflib_data); + buflib_buffer_shift(ctx, -size); +} + /* Allocate a buffer of size bytes, returning a handle for it */ int buflib_alloc(struct buflib_context *ctx, size_t size) diff --git a/apps/plugins/lib/buflib.h b/apps/plugins/lib/buflib.h index ddadb1b9a9..d4ef4af9ff 100644 --- a/apps/plugins/lib/buflib.h +++ b/apps/plugins/lib/buflib.h @@ -38,6 +38,7 @@ struct buflib_context union buflib_data *first_free_handle; union buflib_data *last_handle; union buflib_data *first_free_block; + union buflib_data *buf_start; union buflib_data *alloc_end; bool compact; }; @@ -45,6 +46,10 @@ struct buflib_context void buflib_init(struct buflib_context *context, void *buf, size_t size); int buflib_alloc(struct buflib_context *context, size_t size); void buflib_free(struct buflib_context *context, int handle); +void* buflib_buffer_out(struct buflib_context *ctx, size_t *size); +void buflib_buffer_in(struct buflib_context *ctx, int size); + + /* always_inline is due to this not getting inlined when not optimizing, which * leads to an unresolved reference since it doesn't exist as a non-inline |