diff options
author | Max Kellermann <max@duempel.org> | 2013-01-15 01:00:59 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-01-15 01:02:13 +0100 |
commit | f9fc3a42cc859c90b55c10743bd84832fa156b98 (patch) | |
tree | 628f67f0672f5f84c5d8ea82d5792018de71b3e9 /src/util | |
parent | 76bc28ab1e4ce17926905cbdae455cee8e275a1d (diff) | |
download | mpd-f9fc3a42cc859c90b55c10743bd84832fa156b98.tar.gz mpd-f9fc3a42cc859c90b55c10743bd84832fa156b98.tar.xz mpd-f9fc3a42cc859c90b55c10743bd84832fa156b98.zip |
fifo_buffer: move to util/
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/fifo_buffer.c | 210 | ||||
-rw-r--r-- | src/util/fifo_buffer.h | 161 | ||||
-rw-r--r-- | src/util/growing_fifo.c | 90 | ||||
-rw-r--r-- | src/util/growing_fifo.h | 73 |
4 files changed, 534 insertions, 0 deletions
diff --git a/src/util/fifo_buffer.c b/src/util/fifo_buffer.c new file mode 100644 index 000000000..915fb0579 --- /dev/null +++ b/src/util/fifo_buffer.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "fifo_buffer.h" + +#include <glib.h> + +#include <assert.h> +#include <string.h> + +struct fifo_buffer { + size_t size, start, end; + unsigned char buffer[sizeof(size_t)]; +}; + +struct fifo_buffer * +fifo_buffer_new(size_t size) +{ + struct fifo_buffer *buffer; + + assert(size > 0); + + buffer = (struct fifo_buffer *)g_malloc(sizeof(*buffer) - + sizeof(buffer->buffer) + size); + + buffer->size = size; + buffer->start = 0; + buffer->end = 0; + + return buffer; +} + +static void +fifo_buffer_move(struct fifo_buffer *buffer); + +struct fifo_buffer * +fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size) +{ + if (buffer == NULL) + return new_size > 0 + ? fifo_buffer_new(new_size) + : NULL; + + /* existing data must fit in new size */ + assert(new_size >= buffer->end - buffer->start); + + if (new_size == 0) { + fifo_buffer_free(buffer); + return NULL; + } + + /* compress the buffer when we're shrinking and the tail of + the buffer would exceed the new size */ + if (buffer->end > new_size) + fifo_buffer_move(buffer); + + /* existing data must fit in new size: second check */ + assert(buffer->end <= new_size); + + buffer = g_realloc(buffer, sizeof(*buffer) - sizeof(buffer->buffer) + + new_size); + buffer->size = new_size; + return buffer; +} + +void +fifo_buffer_free(struct fifo_buffer *buffer) +{ + assert(buffer != NULL); + + g_free(buffer); +} + +size_t +fifo_buffer_capacity(const struct fifo_buffer *buffer) +{ + assert(buffer != NULL); + + return buffer->size; +} + +size_t +fifo_buffer_available(const struct fifo_buffer *buffer) +{ + assert(buffer != NULL); + + return buffer->end - buffer->start; +} + +void +fifo_buffer_clear(struct fifo_buffer *buffer) +{ + assert(buffer != NULL); + + buffer->start = 0; + buffer->end = 0; +} + +const void * +fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r) +{ + assert(buffer != NULL); + assert(buffer->end >= buffer->start); + assert(length_r != NULL); + + if (buffer->start == buffer->end) + /* the buffer is empty */ + return NULL; + + *length_r = buffer->end - buffer->start; + return buffer->buffer + buffer->start; +} + +void +fifo_buffer_consume(struct fifo_buffer *buffer, size_t length) +{ + assert(buffer != NULL); + assert(buffer->end >= buffer->start); + assert(buffer->start + length <= buffer->end); + + buffer->start += length; +} + +/** + * Move data to the beginning of the buffer, to make room at the end. + */ +static void +fifo_buffer_move(struct fifo_buffer *buffer) +{ + if (buffer->start == 0) + return; + + if (buffer->end > buffer->start) + memmove(buffer->buffer, + buffer->buffer + buffer->start, + buffer->end - buffer->start); + + buffer->end -= buffer->start; + buffer->start = 0; +} + +void * +fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r) +{ + assert(buffer != NULL); + assert(buffer->end <= buffer->size); + assert(max_length_r != NULL); + + if (buffer->end == buffer->size) { + fifo_buffer_move(buffer); + if (buffer->end == buffer->size) + return NULL; + } else if (buffer->start > 0 && buffer->start == buffer->end) { + buffer->start = 0; + buffer->end = 0; + } + + *max_length_r = buffer->size - buffer->end; + return buffer->buffer + buffer->end; +} + +void +fifo_buffer_append(struct fifo_buffer *buffer, size_t length) +{ + assert(buffer != NULL); + assert(buffer->end >= buffer->start); + assert(buffer->end + length <= buffer->size); + + buffer->end += length; +} + +bool +fifo_buffer_is_empty(struct fifo_buffer *buffer) +{ + return buffer->start == buffer->end; +} + +bool +fifo_buffer_is_full(struct fifo_buffer *buffer) +{ + return buffer->start == 0 && buffer->end == buffer->size; +} diff --git a/src/util/fifo_buffer.h b/src/util/fifo_buffer.h new file mode 100644 index 000000000..49c7f4992 --- /dev/null +++ b/src/util/fifo_buffer.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file + * + * This is a general purpose FIFO buffer library. You may append data + * at the end, while another instance reads data from the beginning. + * It is optimized for zero-copy usage: you get pointers to the real + * buffer, where you may operate on. + * + * This library is not thread safe. + */ + +#ifndef MPD_FIFO_BUFFER_H +#define MPD_FIFO_BUFFER_H + +#include <stdbool.h> +#include <stddef.h> + +struct fifo_buffer; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Creates a new #fifo_buffer object. Free this object with + * fifo_buffer_free(). + * + * @param size the size of the buffer in bytes + * @return the new #fifo_buffer object + */ +struct fifo_buffer * +fifo_buffer_new(size_t size); + +/** + * Change the capacity of the #fifo_buffer, while preserving existing + * data. + * + * @param buffer the old buffer, may be NULL + * @param new_size the requested new size of the #fifo_buffer; must + * not be smaller than the data which is stored in the old buffer + * @return the new buffer, may be NULL if the requested new size is 0 + */ +struct fifo_buffer * +fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size); + +/** + * Frees the resources consumed by this #fifo_buffer object. + */ +void +fifo_buffer_free(struct fifo_buffer *buffer); + +/** + * Return the capacity of the buffer, i.e. the size that was passed to + * fifo_buffer_new(). + */ +size_t +fifo_buffer_capacity(const struct fifo_buffer *buffer); + +/** + * Return the number of bytes currently stored in the buffer. + */ +size_t +fifo_buffer_available(const struct fifo_buffer *buffer); + +/** + * Clears all data currently in this #fifo_buffer object. This does + * not overwrite the actuall buffer; it just resets the internal + * pointers. + */ +void +fifo_buffer_clear(struct fifo_buffer *buffer); + +/** + * Reads from the beginning of the buffer. To remove consumed data + * from the buffer, call fifo_buffer_consume(). + * + * @param buffer the #fifo_buffer object + * @param length_r the maximum amount to read is returned here + * @return a pointer to the beginning of the buffer, or NULL if the + * buffer is empty + */ +const void * +fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r); + +/** + * Marks data at the beginning of the buffer as "consumed". + * + * @param buffer the #fifo_buffer object + * @param length the number of bytes which were consumed + */ +void +fifo_buffer_consume(struct fifo_buffer *buffer, size_t length); + +/** + * Prepares writing to the buffer. This returns a buffer which you + * can write to. To commit the write operation, call + * fifo_buffer_append(). + * + * @param buffer the #fifo_buffer object + * @param max_length_r the maximum amount to write is returned here + * @return a pointer to the end of the buffer, or NULL if the buffer + * is already full + */ +void * +fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r); + +/** + * Commits the write operation initiated by fifo_buffer_write(). + * + * @param buffer the #fifo_buffer object + * @param length the number of bytes which were written + */ +void +fifo_buffer_append(struct fifo_buffer *buffer, size_t length); + +/** + * Checks if the buffer is empty. + */ +bool +fifo_buffer_is_empty(struct fifo_buffer *buffer); + +/** + * Checks if the buffer is full. + */ +bool +fifo_buffer_is_full(struct fifo_buffer *buffer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/growing_fifo.c b/src/util/growing_fifo.c new file mode 100644 index 000000000..88431f60e --- /dev/null +++ b/src/util/growing_fifo.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "growing_fifo.h" +#include "fifo_buffer.h" + +#include <assert.h> +#include <string.h> + +/** + * Align buffer sizes at 8 kB boundaries. Must be a power of two. + */ +static const size_t GROWING_FIFO_ALIGN = 8192; + +/** + * Align the specified size to the next #GROWING_FIFO_ALIGN boundary. + */ +static size_t +align(size_t size) +{ + return ((size - 1) | (GROWING_FIFO_ALIGN - 1)) + 1; +} + +struct fifo_buffer * +growing_fifo_new(void) +{ + return fifo_buffer_new(GROWING_FIFO_ALIGN); +} + +void * +growing_fifo_write(struct fifo_buffer **buffer_p, size_t length) +{ + assert(buffer_p != NULL); + + struct fifo_buffer *buffer = *buffer_p; + assert(buffer != NULL); + + size_t max_length; + void *p = fifo_buffer_write(buffer, &max_length); + if (p != NULL && max_length >= length) + return p; + + /* grow */ + size_t new_size = fifo_buffer_available(buffer) + length; + assert(new_size > fifo_buffer_capacity(buffer)); + *buffer_p = buffer = fifo_buffer_realloc(buffer, align(new_size)); + + /* try again */ + p = fifo_buffer_write(buffer, &max_length); + assert(p != NULL); + assert(max_length >= length); + + return p; +} + +void +growing_fifo_append(struct fifo_buffer **buffer_p, + const void *data, size_t length) +{ + void *p = growing_fifo_write(buffer_p, length); + memcpy(p, data, length); + fifo_buffer_append(*buffer_p, length); +} diff --git a/src/util/growing_fifo.h b/src/util/growing_fifo.h new file mode 100644 index 000000000..723c3b3ff --- /dev/null +++ b/src/util/growing_fifo.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file + * + * Helper functions for our FIFO buffer library (fifo_buffer.h) that + * allows growing the buffer on demand. + * + * This library is not thread safe. + */ + +#ifndef MPD_GROWING_FIFO_H +#define MPD_GROWING_FIFO_H + +#include <stddef.h> + +struct fifo_buffer; + +/** + * Allocate a new #fifo_buffer with the default size. + */ +struct fifo_buffer * +growing_fifo_new(void); + +/** + * Prepares writing to the buffer, see fifo_buffer_write() for + * details. The difference is that this function will automatically + * grow the buffer if it is too small. + * + * The caller is responsible for limiting the capacity of the buffer. + * + * @param length the number of bytes that will be written + * @return a pointer to the end of the buffer (will not be NULL) + */ +void * +growing_fifo_write(struct fifo_buffer **buffer_p, size_t length); + +/** + * A helper function that combines growing_fifo_write(), memcpy(), + * fifo_buffer_append(). + */ +void +growing_fifo_append(struct fifo_buffer **buffer_p, + const void *data, size_t length); + +#endif |