changeset 136:c6d9eb5702e8

array: o add ARRAY_FASTREMOVE, use last object when removing, o add ARRAY_CLEARBITS, set to 0 the bytes when removing parray: o add PARRAY_FASTREMOVE, use last object when removing, o add PARRAY_NULLEND, always has a last NULL entry
author David Demelier <markand@malikania.fr>
date Mon, 26 Mar 2012 10:24:49 +0200
parents 07800b7af208
children 97c9c20535e2
files array.c array.h parray.c parray.h
diffstat 4 files changed, 160 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/array.c	Tue Mar 20 22:49:37 2012 +0100
+++ b/array.c	Mon Mar 26 10:24:49 2012 +0200
@@ -43,6 +43,9 @@
 	if ((arr->data = arr->malloc(arr->size)) == NULL)
 		return -1;
 
+	if (arr->flags & ARRAY_CLEARBITS)
+		memset(arr->data, 0, arr->size);
+
 	return 0;
 }
 
@@ -51,7 +54,7 @@
  * l -> optional array block size of type int
  * m -> malloc function that must matches void * (*malloc)(size_t)
  * r -> realloc function that must matches void * (*realloc)(void *, size_t)
- * t -> type of array of type int
+ * f -> array flags of type int
  */
 
 void
@@ -72,8 +75,8 @@
 		case 'r':
 			arr->realloc = va_arg(ap, void *(*)(void *, size_t));
 			break;
-		case 't':
-			arr->type = va_arg(ap, int);
+		case 'f':
+			arr->flags = va_arg(ap, int);
 			break;
 		default:
 			break;
@@ -141,11 +144,7 @@
 void
 array_pop(struct array *arr)
 {
-	if (arr->length > 0) {
-		memmove((char *)arr->data, (char *)arr->data + OFFSET(1),
-		    OFFSET(--arr->length));
-		memset((char *)arr->data + OFFSET(arr->length), 0, arr->unit);
-	}
+	array_iremove(arr, 0);
 }
 
 /*
@@ -155,8 +154,7 @@
 void
 array_unqueue(struct array *arr)
 {
-	if (arr->length > 0)
-		memset((char *)arr->data + OFFSET(--arr->length), 0, arr->unit);
+	array_iremove(arr, arr->length - 1);
 }
 
 /*
@@ -167,11 +165,18 @@
 array_iremove(struct array *arr, int index)
 {
 	if (arr->length > 0 && index >= 0 && index < arr->length) {
-		memmove((char *)arr->data + OFFSET(index),
-		    (char *)arr->data + OFFSET(index + 1),
-		    OFFSET(arr->length - index - 1));
-		memset((char *)arr->data + OFFSET(--arr->length), 0, arr->unit);
+		if (arr->flags & ARRAY_FASTREMOVE)
+			memmove((char *)arr->data + OFFSET(index),
+			    (char *)arr->data + OFFSET(--arr->length),
+			    arr->unit);
+		else
+			memmove((char *)arr->data + OFFSET(index),
+			    (char *)arr->data + OFFSET(index + 1),
+			    OFFSET(arr->length-- - index - 1));
 	}
+
+	if (arr->flags & ARRAY_CLEARBITS)
+		memset((char *)arr->data + OFFSET(arr->length), 0, arr->unit);
 }
 
 /*
@@ -188,8 +193,10 @@
 	for (i = 0; i < arr->length; ++i) {
 		elm = (char *)arr->data + OFFSET(i);
 
-		if (memcmp(elm, data, arr->unit) == 0)
+		if (memcmp(elm, data, arr->unit) == 0) {
 			array_iremove(arr, i);
+			break;
+		}
 	}
 }
 
@@ -208,11 +215,6 @@
 	if (i1 >= arr->length || i1 < 0 || i2 >= arr->length || i2 < 0)
 		return -1;
 
-	/*
-	 * Only allocate at this time, the user may do not want to use this
-	 * function.
-	 */
-
 	if ((tmp = arr->malloc(arr->unit)) == NULL)
 		return -1;
 
@@ -226,7 +228,8 @@
 	 * secure data to be left somewhere in the memory.
 	 */
 
-	memset(tmp, 0, arr->unit);
+	if (arr->flags & ARRAY_CLEARBITS)
+		memset(tmp, 0, arr->unit);
 	free(tmp);
 
 	return 0;
@@ -292,6 +295,33 @@
 	return (st) ? i - 1 : -1;
 }
 
+void *
+array_first(const struct array *arr)
+{
+	return arr->data;
+}
+
+void *
+array_last(const struct array *arr)
+{
+	if (arr->length == 0)
+		return array_first(arr);
+
+	return (char *)arr->data + OFFSET(arr->length - 1);
+
+}
+
+void *
+array_index(const struct array *arr, int idx)
+{
+	if (idx < 0)
+		return array_first(arr);
+	if (idx >= arr->length)
+		return array_last(arr);
+
+	return (char *)arr->data + OFFSET(idx);
+}
+
 /*
  * Erase every bytes and set the length to 0.
  */
@@ -299,7 +329,9 @@
 void
 array_clear(struct array *arr)
 {
-	memset(arr->data, 0, arr->size);
+	if (arr->flags & ARRAY_CLEARBITS)
+		memset(arr->data, 0, arr->size);
+
 	arr->length = 0;
 }
 
@@ -310,7 +342,11 @@
 void
 array_free(struct array *arr)
 {
+	array_clear(arr);
 	free(arr->data);
+
+	arr->data	= NULL;
+	arr->size	= 0;
 }
 
 /*
@@ -322,13 +358,15 @@
 static int
 grow(struct array *arr)
 {
-	if ((arr->size / arr->unit) > (size_t) arr->length)
+	if ((arr->size / arr->unit) > (size_t)arr->length)
 		return 0;
 
-	if (arr->type == ARRAY_AUTO) {
+	if (!(arr->flags & ARRAY_FIXED)) {
 		if ((arr->data = arr->realloc(arr->data, arr->size +
-		    OFFSET(arr->bsize))) == NULL)
+		    OFFSET(arr->bsize))) == NULL) {
+			arr->size = arr->length = 0;
 			return -1;
+		}
 
 		arr->size += OFFSET(arr->bsize);
 	} else
--- a/array.h	Tue Mar 20 22:49:37 2012 +0100
+++ b/array.h	Mon Mar 26 10:24:49 2012 +0200
@@ -30,12 +30,14 @@
 #endif
 
 enum {
-	ARRAY_AUTO	= 0,
-	ARRAY_FIXED	= 1
+	ARRAY_AUTO		= 0,		/* array grows automatically */
+	ARRAY_FIXED		= (1 << 0),	/* fixed size length */
+	ARRAY_FASTREMOVE	= (1 << 1),	/* use last object when removing */
+	ARRAY_CLEARBITS		= (1 << 2)	/* clear data when inserting/removing */
 };
 
 struct array {
-	int	type;		/* (ro) array's type (default FIXED) */
+	int	flags;		/* (ro) array flags (default AUTO) */
 	void	*data;		/* (rw) array of data */
 	int	length;		/* (ro) number of element inside */
 	size_t	size;		/* (ro) current buffer size (allocated memory) */
@@ -89,16 +91,25 @@
 int
 array_find(const struct array *, array_cmp_fn, void *, void *);
 
+void *
+array_first(const struct array *);
+
+void *
+array_last(const struct array *);
+
+void *
+array_index(const struct array *, int);
+
 void
 array_clear(struct array *);
 
 void
 array_free(struct array *);
-
+	
 #define ARRAY_FOREACH(a, var, i)						\
-	for (i = 0, (var) = (a)->data;						\
+	for (i = 0, (var) = array_first((a));					\
 		i < (a)->length;						\
-		++i, ++(var))
+		(var) = array_index(a, ++i))
 
 #ifdef __cplusplus
 }
--- a/parray.c	Tue Mar 20 22:49:37 2012 +0100
+++ b/parray.c	Mon Mar 26 10:24:49 2012 +0200
@@ -34,12 +34,13 @@
 	arr->malloc	= (arr->malloc == NULL) ? &malloc : arr->malloc;
 	arr->realloc	= (arr->realloc == NULL) ? &realloc : arr->realloc;
 
+	arr->bsize	+= (arr->flags & PARRAY_NULLEND) ? 1 : 0;
 	arr->size	= LENGTH(arr->bsize);
 
 	if ((arr->data = arr->malloc(arr->size)) == NULL)
 		return -1;
 
-	memset(arr->data, 0, LENGTH(arr->bsize));
+	memset(arr->data, 0, arr->size);
 
 	return 0;
 }
@@ -49,7 +50,7 @@
  * l -> optional array block size of type int
  * m -> malloc function that must matches void * (*malloc)(size_t)
  * r -> realloc function that must matches void * (*realloc)(void *, size_t)
- * t -> type of array of type int
+ * f -> parray flags of type int
  */
 
 void
@@ -70,8 +71,8 @@
 		case 'r':
 			arr->realloc = va_arg(ap, void * (*)(void *, size_t));
 			break;
-		case 't':
-			arr->type = va_arg(ap, int);
+		case 'f':
+			arr->flags = va_arg(ap, int);
 			break;
 		default:
 			break;
@@ -93,6 +94,9 @@
 	memmove(&arr->data[1], &arr->data[0], LENGTH(arr->length++));
 	arr->data[0] = data;
 
+	if (arr->flags & PARRAY_NULLEND)
+		arr->data[arr->length] = NULL;
+
 	return 0;
 }
 
@@ -114,6 +118,9 @@
 		LENGTH(arr->length++ - index));
 	arr->data[index] = data;
 
+	if (arr->flags & PARRAY_NULLEND)
+		arr->data[arr->length] = NULL;
+
 	return 0;
 }
 
@@ -129,6 +136,9 @@
 
 	arr->data[arr->length++] = data;
 
+	if (arr->flags & PARRAY_NULLEND)
+		arr->data[arr->length] = NULL;
+
 	return 0;
 }
 
@@ -139,10 +149,7 @@
 void
 parray_pop(struct parray *arr)
 {
-	if (arr->length > 0) {
-		memmove(&arr->data[0], &arr->data[1], LENGTH(--arr->length));
-		arr->data[arr->length] = NULL;
-	}
+	parray_iremove(arr, 0);
 }
 
 /*
@@ -152,8 +159,7 @@
 void
 parray_unqueue(struct parray *arr)
 {
-	if (arr->length > 0)
-		arr->data[--arr->length] = NULL;
+	parray_iremove(arr, arr->length - 1);
 }
 
 /*
@@ -164,10 +170,14 @@
 parray_iremove(struct parray *arr, int index)
 {
 	if (arr->length > 0 && index >= 0 && index < arr->length) {
-		memmove(&arr->data[index], &arr->data[index + 1],
-		    LENGTH(arr->length - index - 1));
-		arr->data[--arr->length] = NULL;
+		if (arr->flags & PARRAY_FASTREMOVE)
+			arr->data[index] = arr->data[--arr->length];
+		else
+			memmove(&arr->data[index], &arr->data[index + 1],
+			    LENGTH(arr->length-- - index - 1));
 	}
+
+	arr->data[arr->length] = NULL;
 }
 
 /*
@@ -272,6 +282,33 @@
 	return (st) ? i - 1 : -1;
 }
 
+void *
+parray_first(const struct parray *arr)
+{
+	return arr->data[0];
+}
+
+void *
+parray_last(const struct parray *arr)
+{
+	if (arr->length == 0)
+		return parray_first(arr);
+
+	return arr->data[arr->length - 1];
+
+}
+
+void *
+parray_index(const struct parray *arr, int idx)
+{
+	if (idx < 0)
+		return parray_first(arr);
+	if (idx >= arr->length)
+		return parray_last(arr);
+
+	return arr->data[idx];
+}
+
 /*
  * Reset the array by setting each pointer to NULL and the length to 0.
  */
@@ -279,8 +316,8 @@
 void
 parray_clear(struct parray *arr)
 {
-	memset(arr->data, 0, arr->size);
-	arr->length = 0;
+	arr->data[0]	= NULL;
+	arr->length	= 0;
 }
 
 /*
@@ -290,7 +327,11 @@
 void
 parray_free(struct parray *arr)
 {
+	parray_clear(arr);
 	free(arr->data);
+
+	arr->data	= NULL;
+	arr->size	= 0;
 }
 
 /*
@@ -302,13 +343,19 @@
 static int
 grow(struct parray *arr)
 {
-	if ((arr->size / sizeof (void *)) > (size_t) arr->length)
+	int toadd;
+
+	toadd = (arr->flags & PARRAY_NULLEND) ? 2 : 1;
+
+	if ((arr->size / sizeof (void *)) - arr->length >= toadd)
 		return 0;
 
-	if (arr->type == PARRAY_AUTO) {
+	if (!(arr->flags & PARRAY_FIXED)) {
 		if ((arr->data = arr->realloc(arr->data, arr->size +
-		    LENGTH(arr->bsize))) == NULL)
+		    LENGTH(arr->bsize))) == NULL) {
+			arr->size = arr->length = 0;
 			return -1;
+		}
 
 		arr->size += LENGTH(arr->bsize);
 	} else
--- a/parray.h	Tue Mar 20 22:49:37 2012 +0100
+++ b/parray.h	Mon Mar 26 10:24:49 2012 +0200
@@ -1,5 +1,5 @@
 /*
- * array.h -- manipulate dynamic pointer arrays
+ * parray.h -- manipulate dynamic pointer arrays
  *
  * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr>
  *
@@ -30,12 +30,14 @@
 #endif
 
 enum {
-	PARRAY_AUTO	= 0,
-	PARRAY_FIXED	= 1
+	PARRAY_AUTO		= 0,		/* array grows automatically */
+	PARRAY_FIXED		= (1 << 0),	/* fixed size length */
+	PARRAY_FASTREMOVE	= (1 << 1),	/* use last object when removing */
+	PARRAY_NULLEND		= (1 << 2)	/* always has a NULL pointer at end */
 };
 
 struct parray {
-	int	type;		/* (ro) array type (default FIXED) */
+	int	flags;		/* (ro) array flags (default AUTO) */
 	void	**data;		/* (rw) array of data */
 	int	length;		/* (ro) number of element inside */
 	size_t	size;		/* (ro) current buffer size (allocated memory) */
@@ -88,6 +90,15 @@
 int
 parray_find(const struct parray *, parray_cmp_fn, void *, void *);
 
+void *
+parray_first(const struct parray *);
+
+void *
+parray_last(const struct parray *);
+
+void *
+parray_index(const struct parray *, int);
+
 void
 parray_clear(struct parray *);