void *data;
} priv_t;
-/* make sure we have at least n elements in the buffer, grow if needed */
+/* make sure we have at least n+1 elements in the buffer, grow if needed */
+/* +1 is so we can always end with a NULL value for array_data/convert() */
static int array_assure(array_t *me, size_t nb_elem);
/* for qsort operations */
// convert to void * data (free the rest)
void *array_convert(array_t *me) {
priv_t *priv = (priv_t *) me->priv;
- void *data = priv->data;
+ void *data = array_data(me);
free(priv);
free(me);
return data;
void *array_data(array_t *me) {
priv_t *priv = (priv_t *) me->priv;
+
+ // Note: this should be impossible
+ if (me->count >= priv->buffer)
+ array_assure(me, me->count + 1);
+
+ // cast to (char *) because we want 'byte' arithmetic
+ void *after_end = (void *) (((char *) priv->data)
+ + (me->count * priv->elem_size));
+
+ // last item is always NULL
+ memset(after_end, '\0', priv->elem_size);
+
return priv->data;
}
}
void *array_first(array_t *me) {
+ if (!me->count)
+ return NULL;
+
priv_t *priv = (priv_t *) me->priv;
return priv->data;
}
+void *array_last(array_t *me) {
+ if (!me->count)
+ return NULL;
+
+ priv_t *priv = (priv_t *) me->priv;
+ // cast to (char *) because we want 'byte' arithmetic
+ return (void *) (((char *) priv->data) + ((me->count - 1) * priv->elem_size));
+}
+
+void *array_prev(array_t *me, void *ptr) {
+ priv_t *priv = (priv_t *) me->priv;
+
+ // cast to (char *) because we want 'byte' arithmetic
+ char *cptr = (char *) ptr;
+ char *cdata = (char*) priv->data;
+
+ if (cptr) {
+ cptr -= priv->elem_size;
+ if (cptr >= cdata) {
+ return cptr;
+ }
+ }
+
+ return NULL;
+}
+
void *array_next(array_t *me, void *ptr) {
priv_t *priv = (priv_t *) me->priv;
static int array_assure(array_t *me, size_t nb_elem) {
priv_t *priv = (priv_t *) me->priv;
- if (priv->buffer < nb_elem) {
+ if (priv->buffer <= nb_elem) {
priv->buffer *= 2;
if (priv->buffer < nb_elem) {
priv->buffer = nb_elem;
array_t *new_array(size_t elem_size, size_t initial);
/**
- * Create a new array.
+ * Initialise a new array.
*
* @param elem_size the size of one element
* @param initial the initial number of items the buffer can hold (<b>not</b> 0)
/**
* Clear the array, that is, resets its current size to 0 (buffer unchanged).
+ *
+ * @note if you hold custom structures with owned resources in the array, you
+ * should deallocate them properly before
*/
void array_clear(array_t *me);
/**
* Convert the array to a block of memory where all values are adjacent.
*
+ * @note an extra NULL value is assured to be present as last element
+ *
* @return the data (you must later call `free()` on it)
*/
void *array_convert(array_t *me);
*
* Be careful if you change the content (you should not).
*
+ * @note an extra NULL value is assured to be present as last element
+ *
* @return the internal storage area
*/
void *array_data(array_t *me);
* store integers, it will be <tt>(int *)</tt>; if you store strings, it will
* be <tt>char **</tt>).
*
- * @return a <i>pointer</i> to the first element
+ * @return a <i>pointer</i> to the first element, or NULL if no elements are
+ * present
*/
void *array_first(array_t *me);
+/**
+ * Return a pointer to the last element of the array (for instance, if you
+ * store integers, it will be <tt>(int *)</tt>; if you store strings, it will
+ * be <tt>char **</tt>).
+ *
+ * @return a <i>pointer</i> to the last element, or NULL if no elements are
+ * present
+ */
+void *array_last(array_t *me);
+
+/**
+ * Return the pointer to the previous element, or NULL if it was the first.
+ *
+ * @param ptr a pointer from an array (the array must be valid)
+ *
+ * @return the previous element, or NULL
+ */
+void *array_prev(array_t *me, void *ptr);
+
/**
* Return the pointer to the next element, or NULL if it was the last.
*
*
* @param i the index of the element to retrieve
*
+ * @note if the index is out of bounds, you will get invalid data
+ *
* @return the pointer to the i'th element
*/
void *array_get(array_t *me, size_t i);
* Cut the array at the given size and return a pointer to the first element
* that was removed if any.
*
+ * @note be careful, the memory pointed to by the element(s) will be reused the
+ * next time we add an element -- you should not use it after this; in
+ * short, the return value is mainly so you can call <tt>free</tt> on
+ * value(s) pointed to by this pointer (<b>not</b> the pointer itself) if
+ * it is a pointer to memory you own, or use it locally before continuing
+ * to use the array
+ * @note in case this was not clear, do <b>not</b> call <tt>free</tt> on the
+ * returned value(s)
+ *
* @return a pointer to the first removed element, or NULL
*/
void *array_cut_at(array_t *me, size_t n);
void array_qsortf(array_t *me, int rev);
/**
- * Add an element to the array.
+ * Add an element to the array (will create a new item in the array and copy the
+ * data from the given element in it).
*
* @param data the memory position of the element to add
*
int array_push(array_t *me, void *data);
/**
- * Add multiple elements to the array.
+ * Add multiple elements to the array (will create new items in the array and
+ * copy the data from the given elements in them).
*
* @param data the memory position of the elements to add, adjacent to each
* other
/**
* Set an element of the array to the given value.
- * Can also append a new elements.
+ * Can also append an element at the end of the array (i.e., <tt>i</tt> can be
+ * the size of the array and this will result in an array with one more
+ * element).
* Memory will be copied from the given data to the array.
*
* @param i the element index
/**
* Set elements of the array to the given value.
- * Can also append some of them to the array if no values were present.
+ * Can also append elements at the end of the array (i.e., <tt>i</tt> can be
+ * the size of the array and this will result in an array with <tt>n</tt> more
+ * elements).
* Memory will be copied from the given data to the array.
*
* @param i the element index to start the insertion at
#endif
#if _POSIX_C_SOURCE < 200809L && _XOPEN_SOURCE < 500
/**
- * The strndup() function is similar, but copies at most n bytes.
- * If s is longer than n, only n bytes are copied, and a terminating null byte
- * ('\0') is added.
+ * The strdup() function returns a pointer to a new string which is a
+ * duplicate of the string s. Memory for the new string is obtained with
+ * malloc(3), and can be freed with free(3).
*
- * @return On success, the strndup() function returns a pointer to the
- * duplicated string. It returns NULL if insufficient memory was
- * available, with errno set to indicate the error
+ *
+ * @return On success, the strdup() function returns a pointer to the duplicated
+ * string. It returns NULL if insufficient memory was available, with
+ * errno set to indicate the error.
*/
char *strdup(const char *source);
#endif