summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann <sandmann@redhat.com>2008-11-08 10:40:43 -0500
committerSøren Sandmann <sandmann@redhat.com>2008-11-08 10:40:43 -0500
commit72813fba0400d4b8abf370fded95b0d7164e08b8 (patch)
tree176cec3e11788618925ed1c7b2a3abf16a55efae
parentce69ed5fcb4697b30b5637cfaed5b3697051d79e (diff)
Add nul_buffer_t
-rw-r--r--array.c294
-rw-r--r--libnul.h41
2 files changed, 300 insertions, 35 deletions
diff --git a/array.c b/array.c
index 8f9cfa9..2bd6ab2 100644
--- a/array.c
+++ b/array.c
@@ -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);
+ }
}
diff --git a/libnul.h b/libnul.h
index 473c751..f1b760e 100644
--- a/libnul.h
+++ b/libnul.h
@@ -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;