diff options
author | Søren Sandmann <sandmann@redhat.com> | 2008-11-08 10:40:43 -0500 |
---|---|---|
committer | Søren Sandmann <sandmann@redhat.com> | 2008-11-08 10:40:43 -0500 |
commit | 72813fba0400d4b8abf370fded95b0d7164e08b8 (patch) | |
tree | 176cec3e11788618925ed1c7b2a3abf16a55efae | |
parent | ce69ed5fcb4697b30b5637cfaed5b3697051d79e (diff) |
Add nul_buffer_t
-rw-r--r-- | array.c | 294 | ||||
-rw-r--r-- | libnul.h | 41 |
2 files changed, 300 insertions, 35 deletions
@@ -57,13 +57,19 @@ get_array (const void *data, const int *magic) } static void -array_free (array_t *array, const int *magic) +array_free (array_t *array) { - g_return_if_fail (array->magic == magic); - g_free (array); } +static void +nul_terminate (array_t *array) +{ + char *end = (char *)array->data + array->n_elements * array->element_size; + + memset (end, 0, array->element_size); +} + static array_t * G_GNUC_WARN_UNUSED_RESULT realloc_array (array_t *array, int n_elements) { @@ -71,12 +77,9 @@ realloc_array (array_t *array, int n_elements) /* FIXME: overflow? */ n_bytes = NUL_STRUCT_OFFSET (array_t, data); - if (!array) - n_bytes += 128; - else - n_bytes += (n_elements + 1) * array->element_size; + n_bytes += (n_elements + 1) * array->element_size; - if (!array || n_bytes > array->n_bytes) + if (n_bytes > array->n_bytes) { gssize pot; @@ -86,6 +89,8 @@ realloc_array (array_t *array, int n_elements) array = g_realloc (array, pot); array->n_bytes = pot; + + nul_terminate (array); } return array; @@ -94,17 +99,40 @@ realloc_array (array_t *array, int n_elements) static void * array_new (int element_size, const int *magic) { - array_t *array = realloc_array (NULL, -1); + array_t *array = g_new (array_t, 1); - array->element_size = element_size; array->magic = magic; + array->element_size = element_size; + array->n_bytes = sizeof (array_t); array->n_elements = 0; - memset (array->data, 0, element_size); + + array = realloc_array (array, 16); return array->data; } +static array_t * +array_delete_head (array_t *array, int n_elements) +{ + int n_bytes = n_elements * array->element_size; + + /* FIXME: this should be done in constant time */ + + memmove (array->data, (char *)array->data + n_bytes, n_bytes); + nul_terminate (array); + + return array; +} +static array_t * +array_delete_tail (array_t *array, int n_elements) +{ + array->n_elements -= n_elements; + + nul_terminate (array); + + return array; +} /* Pointer arrays. The idiomatic way to iterate through such an array is: * @@ -173,7 +201,7 @@ nul_ptr_array_append (void **arr, gpointer data) void nul_ptr_array_free (void **arr) { - array_free (get_array (arr, &parr_t_magic), &parr_t_magic); + array_free (get_array (arr, &parr_t_magic)); } gsize @@ -196,7 +224,7 @@ nul_string_new (void) void nul_string_free (nul_string_t *str) { - array_free (get_array (str, &string_t_magic), &string_t_magic); + array_free (get_array (str, &string_t_magic)); } gsize @@ -211,16 +239,6 @@ nul_string_empty (const nul_string_t *str) return nul_string_len (str) == 0; } -static nul_string_t * -string_nul_terminate (nul_string_t *str) -{ - array_t *array = get_array (str, &string_t_magic); - - str[array->n_elements] = 0; - - return str; -} - nul_string_t * G_GNUC_WARN_UNUSED_RESULT nul_string_append_undefined (nul_string_t *str, gsize n_bytes, @@ -288,22 +306,238 @@ nul_string_append_vprintf (nul_string_t *str, return str; } -void -nul_string_transfer_data (nul_string_t **dest, - nul_string_t **src, - gssize n_bytes) -{ -} - nul_string_t * nul_string_delete_head (nul_string_t *str, gsize n_bytes) { + array_t *array = get_array (str, &string_t_magic); + + array = array_delete_head (array, n_bytes); + + return (nul_string_t *)array->data; } nul_string_t * nul_string_delete_tail (nul_string_t *str, gsize n_bytes) { + array_t *array = get_array (str, &string_t_magic); + + array = array_delete_tail (array, n_bytes); + + return (nul_string_t *)array->data; +} + +/* + * Buffer + */ +struct nul_buffer_t +{ + nul_string_t *data; +}; + +nul_buffer_t * +nul_buffer_new (void) +{ + nul_buffer_t *buffer = g_new0 (nul_buffer_t, 1); + + buffer->data = nul_string_new (); + + return buffer; +} + +gsize +nul_buffer_get_length (nul_buffer_t *buffer) +{ + return nul_string_len (buffer->data); +} + +nul_string_t * +nul_buffer_free (nul_buffer_t *buffer, + gboolean free_data) +{ + char *result; + + if (free_data) + { + nul_string_free (buffer->data); + result = NULL; + } + else + { + result = buffer->data; + } + + return result; +} + +/* The data returned is owned by the byte buffer and becomes invalid + * as soon as any method is called on the buffer. + */ +const gchar * +nul_buffer_peek (nul_buffer_t *buffer, + gsize *n_bytes) +{ + if (n_bytes) + *n_bytes = nul_string_len (buffer->data); + return buffer->data; +} + +gboolean +nul_buffer_is_empty (nul_buffer_t *buffer) +{ + return nul_string_empty (buffer->data); +} + +/* This function appends uninitialized data of length @size + * to the buffer, then returns a pointer to the added data. + * The intention is that the app can read() into this + * memory, then use nul_buffer_pop_tail() to delete the + * area that wasn't read into. Example + * + * guint8 *area = nul_buffer_alloc_tail (buffer, 8192); + * + * n_read = read (fd, area, 8192); + * + * nul_buffer_delete_tail (buffer, 8192 - (n_read < 0)? 0 : n_read); + * + * if (n_read < 0) + * { + * nul_buffer_delete_tail (buffer, 8192); + * handle_error(); + * n_read = 0; + * } + * else + * { + * nul_buffer_delete_tail (8192 - n_read); + * + * // enjoy the new data in the buffer + * } + */ +char * +nul_buffer_alloc_tail (nul_buffer_t *buffer, + gsize size) +{ + char *tail; + + buffer->data = nul_string_append_undefined (buffer->data, size, &tail); + + return tail; +} + +void +nul_buffer_delete_head (nul_buffer_t *buffer, + gsize size) +{ + buffer->data = nul_string_delete_head (buffer->data, size); +} + +void +nul_buffer_delete_tail (nul_buffer_t *buffer, + gsize size) +{ + buffer->data = nul_string_delete_tail (buffer->data, size); +} + +void +nul_buffer_append (nul_buffer_t *buffer, + const gchar *bytes, + gsize n_bytes) +{ + buffer->data = nul_string_append (buffer->data, bytes, n_bytes); +} + +void +nul_buffer_append_printf (nul_buffer_t *buffer, + const gchar *fmt, + ...) +{ + va_list args; + + g_return_if_fail (fmt != NULL); + + va_start (args, fmt); + + buffer->data = nul_string_append_vprintf (buffer->data, fmt, args); + + va_end (args); +} + +nul_string_t * +nul_buffer_steal (nul_buffer_t *buffer, + gsize *n_bytes) +{ + nul_string_t *result = buffer->data; + + if (n_bytes) + *n_bytes = nul_string_len (result); + + buffer->data = nul_string_new (); + + return result; +} + +static void +nul_buffer_swap_content (nul_buffer_t *buffer1, + nul_buffer_t *buffer2) +{ + nul_string_t *tmp; + + tmp = buffer1->data; + buffer2->data = buffer1->data; + buffer1->data = tmp; +} + + +/* Transfer n_bytes data from the head of @src to tail of @dest, + * if possible without copying. The data is appended to @dest's data + * if @dest is not empty + */ +void +nul_buffer_transfer_data (nul_buffer_t *dest, + nul_buffer_t *src, + gssize n_bytes) +{ + gsize total = nul_buffer_get_length (src); + + if (n_bytes < 0 || n_bytes > total) + n_bytes = total; + + if (nul_buffer_is_empty (dest)) + { + const char *source = src->data; + gboolean swap_contents = FALSE; + + if (n_bytes > total / 2) + { + source = src->data + n_bytes; + n_bytes = total - n_bytes; + swap_contents = TRUE; + } + + nul_buffer_append (dest, source, n_bytes); + + if (swap_contents) + { + nul_buffer_delete_tail (src, n_bytes); + nul_buffer_swap_content (dest, src); + } + else + { + nul_buffer_delete_head (src, n_bytes); + } + } + else + { + /* FIXME: + * + * check whether one of the strings fit in the other's segment. + * if both fit, copy the shortest, if only one, copy that one. + * if none, just append. + */ + nul_buffer_append (dest, src->data, n_bytes); + + nul_buffer_delete_head (src, n_bytes); + } } @@ -47,7 +47,9 @@ typedef void * nul_ptr_t; typedef void * const nul_const_ptr_t; -/* Pointer arrays */ +/* + * Pointer arrays + */ nul_ptr_t *nul_ptr_array_new (void); nul_ptr_t *nul_ptr_array_append (nul_ptr_t *arr, nul_ptr_t data) G_GNUC_WARN_UNUSED_RESULT; @@ -55,7 +57,9 @@ gsize nul_ptr_array_len (nul_const_ptr_t *arr); void nul_ptr_array_free (nul_ptr_t *arr); -/* Strings */ +/* + * Strings + */ typedef char nul_string_t; nul_string_t *nul_string_new (void); @@ -74,14 +78,41 @@ nul_string_t *nul_string_append_printf (nul_string_t *string, nul_string_t *nul_string_append_vprintf (nul_string_t *string, const char *fmt, va_list args); -void nul_string_transfer_data (nul_string_t **dest, - nul_string_t **src, - gssize n_bytes); nul_string_t *nul_string_delete_head (nul_string_t *str, gsize n_bytes); nul_string_t *nul_string_delete_tail (nul_string_t *str, gsize n_bytes); +/* + * Buffers + */ +typedef struct nul_buffer_t nul_buffer_t; + +nul_buffer_t * nul_buffer_new (void); +char * nul_buffer_free (nul_buffer_t *queue, + gboolean free_data); +gsize nul_buffer_get_length (nul_buffer_t *queue); +gboolean nul_buffer_is_empty (nul_buffer_t *queue); +const nul_string_t *nul_buffer_peek (nul_buffer_t *queue, + gsize *n_bytes); +nul_string_t * nul_buffer_steal (nul_buffer_t *queue, + gsize *n_bytes); +nul_string_t * nul_buffer_alloc_tail (nul_buffer_t *queue, + gsize size); +void nul_buffer_append (nul_buffer_t *queue, + const char *bytes, + gsize n_bytes); +void nul_buffer_append_printf (nul_buffer_t *queue, + const char *fmt, + ...); +void nul_buffer_transfer_data (nul_buffer_t *dest, + nul_buffer_t *src, + gssize n_bytes); +void nul_buffer_delete_head (nul_buffer_t *queue, + gsize size); +void nul_buffer_delete_tail (nul_buffer_t *queue, + gsize size); + typedef union { uint32_t v_uint32; |