agrow¶
https://bitbucket.org/iwcrhsimmcotf/agrow
This is a macros based library in pure C that implements resizable arrays.
It’s similar to C++ std::vector in that it uses contiguous, automatically
growing memory to store the elements.
Just like std::vector it allocates more memory than actually needed
to handle future growth.
To use it in your project, copy agrow.h to the include folder.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "agrow.h"
AGROW_DECL(myarray, int) /* expands to prototypes */
AGROW_DEF(myarray, int) /* expands to definitions */
int
main(void)
{
printf(" * simple: ");
/* reserve space for at least 3 elements */
myarray *a = myarray_new(3);
/* append 5 elements */
int *p = myarray_append(a, NULL, NULL);
*p = 6;
p = myarray_append(a, NULL, NULL);
*p = 7;
p = myarray_append(a, NULL, NULL);
*p = 8;
p = myarray_append(a, NULL, NULL);
*p = 9;
p = myarray_append(a, NULL, NULL);
*p = 10;
assert(myarray_size(a) == 5);
/* iteration */
p = myarray_data(a);
int sum = 0;
for (size_t i = 0, s = myarray_size(a); i < s; i++) {
sum += p[i];
}
assert(sum == 6 + 7 + 8 + 9 + 10);
/* (there is also myarray_each() that accepts a callback) */
myarray_destroy(&a, NULL, NULL); /* free memory */
printf("OK\n");
return 0;
}
Contents
Macros¶
AGROW_DECL()¶
Creates forward declarations for struct and methods that comprise a new dynamic array.
AGROW_DECL(Arr, T)
Parameters
Arr: New array type and also a prefix for methodsT: Type of the elements
To generate complete definitions of struct and methods, you should also call
AGROW_DEF().
AGROW_DEF()¶
Expands to complete definitions of struct and methods previously declared with
AGROW_DECL().
AGROW_DEF(Arr, T)
Parameters
Same as for AGROW_DECL()
Callbacks¶
Some api methods require a callback function as one of their parameters. The api method then may invoke that function on individual array elements. All such callbacks share the same signature.
int your_callback(size_t pos, T *ptr, void *data) {/*...*/}
Parameters
pos: Index of the elementptr: Pointer to the elementdata: Extra argument
Return value
The meaning of the return value varies for different methods.
Api¶
{?}_new()¶
Creates an empty array allocated on the heap.
myarray *myarray_new(size_t atleast)
Parameters
atleast: How many elements should be reserved
The actual amount of reserved elements (capacity) may be equal or
greater than the value of atleast.
Return value
Pointer to created array or NULL on failure.
Example
myarray *a = myarray_new(AT_LEAST_ELEMS);
if (a == NULL) {
printf("couldn't create an array\n");
return -1;
}
/* ... */
myarray_destroy(&a, onfree, NULL);
Notes
Instances created with this method should be destroyed with destroy()
method.
{?}_destroy()¶
Destroys an instance of an array created with new().
void myarray_destroy(myarray **selfptr,
myarray_callback onfree,
void *data)
Params:
selfptr: Pointer to pointer to arrayonfree: Callback function that is called on every elementdata: Extra argument passed to every invokation of onfree()
If selfptr points to NULL, this methods does nothing.
The purpose of onfree() is to finalize array elements.
If no such finalization is needed, you may pass NULL instead of onfree.
The value returned from onfree() is ignored.
{?}_get_ptr()¶
Returns a pointer to the element with index pos or NULL if position
is out of range.
elem *myarray_get_ptr(myarray *self, size_t pos)
Parameters
self: Pointer to arraypos: Element’s index
Return value
Element’s pointer on success or NULL on failure.
Notes
To get the beginning of elements space, you can also use data().
{?}_data()¶
Returns a pointer to the beginning of allocated space.
elem *myarray_data(myarray *self)
It’s equivalent to myarray_get_ptr(a, 0) except it succeeds even if
size == 0.
Parameters
self: Pointer to array
{?}_each()¶
Iterates over the elements.
int myarray_each(myarray *self,
myarray_callback oneach,
void *data)
Parameters
self: Pointer to arrayoneach: Callback function that is called on every elementdata: Extra argument passed to every invokation of oneach()
The return value of oneach() callback
0: success. Methodeach()should proceed iterating- a negative value: failure. Method
each()should stop iterating and return failure - a positive value: success. Method
each()should stop iterating and return success (early exit).
Return value
0 on success and -1 on failure.
{?}_size()¶
Returns the current number of elements.
size_t myarray_size(myarray *self)
Parameters
self: Pointer to array
Example
myarray *a = myarray_new(1000);
printf("%zu\n", myarray_size(a)); /* 0 */
myarray_append(a, /*...*/);
myarray_append(a, /*...*/);
myarray_append(a, /*...*/);
printf("%zu\n", myarray_size(a)); /* 3 */
{?}_capacity()¶
Returns the amount of elements that can fit into currently allocated memory.
size_t myarray_capacity(myarray *self)
Parameters
self: Pointer to array
Example
myarray *a = myarray_new(1000);
printf("%s\n", myarray_capacity(a) >= 1000? "true" : "false"); /* true */
{?}_append()¶
Appends a new element to the end of array.
elem *myarray_append(myarray *self,
myarray_callback onappend,
void *data)
If capacity is exceeded, it tries to allocate more memory.
Parameters
self: Pointer to arrayonappend: Callback function that is called on the appended element (if append was successful)data: Extra argument passed to the invokation ofonappend()
The purpose of onappend is to initialize the new element.
If no such initialization is needed, you may pass NULL instead of
onappend.
The return value of onappend()
0:append()should succeed- a negative value:
append()should fail
Return value
A valid pointer to the new element on success, NULL on failure.
Example
/* if elem is integer type */
int
onap(size_t idx, elem *p, void *data)
{
*p = 77;
return 0;
}
/* ... */
elem *p = myarray_append(a, onap, NULL);
printf("%d\n", *p); /* 77 */
{?}_shy_append()¶
Appends a new element to the end of array (fail if capacity is exceeded).
elem *myarray_shy_append(myarray *self,
myarray_callback onappend,
void *data,
int *isfull)
Unlike append() it never tries to allocate more memory.
Parameters
- (
self,onappendanddataare the same as forappend()) isfull: Pointer to a flag signalling thatshy_append()failed due to exceededcapacity.
If isfull points to NULL, it is ignored.
If shy_append() fails due to capacity limit is reached, the flag
pointed by isfull is set to a true value.
If shy_append() fails due to some other error, the flag pointed by
isfull is set to a false value.
Return value
A valid pointer to the new element on success, NULL on failure.
{?}_resize()¶
Sets the new size of the array.
size_t myarray_resize(myarray *self,
size_t size,
myarray_callback onadd,
myarray_callback ondel,
void *data)
Just like append() it will try to allocate more memory if the new size is
greater than capacity.
Parameters
self: Pointer to arraysize: The new sizeonadd: Callback function that is called on every appended element (if the new size is greater than the current one)ondel: Callback function that is called on every discarded element (if the new size is less than the current one)data: Extra argument passed to the invokation of whichever used callback
The purpose of onadd function is to initialize new elements.
The purpose of ondel function is to finalize discarded elements.
If no such initialization or finalization is needed, you may pass NULL
instead of the corresponding callback.
The return value of onadd() and ondel()
0: the method should proceed resizing (adding or deleting elements)- a negative value: the method should stop and return failure
Return value
The new size of array. On errors it might be different from what was requested.
Notes
This method never frees any allocated memory even when discarding elements.
Example
myarray *a = myarray_new(10);
printf("%zu\n", myarray_size(a)); /* 0 */
myarray_resize(a, 1000, NULL, NULL, NULL);
printf("%zu\n", myarray_size(a)); /* 1000 */
{?}_vacuum()¶
Removes certain elements from array.
size_t myarray_vacuum(myarray *self,
myarray_callback isgarbage,
myarray_callback onmove,
void *data)
If removed elements create gaps, the kept elements are shifted down to close these gaps.
Parameters
self: Pointer to arrayisgarbage: Callback function that is called on every elementonmove: Callback function that is called on every moved elementdata: Extra argument passed to every invokation ofisgarbage()andonmove()
The purpose of isgarbage() function is to tell whether the element should
be kept or removed.
The return value of isgarbage()
0: the element should be kept1: the element should be removed and thevacuum()method should continue applyingisgarbage()to other elements2: the element should be removed and thevacuum()method should stop applyingisgarbage()to other elements keeping them in the array
Also isgarbage() callback should finalize the element if it decides to
return 1 or 2.
The purpose of onmove() function is to perform additional logic when an
element is shifted to close gaps.
It is called after the element is copied to the new location.
The return value of onmove() is ignored.
Return value
The new size.
Notes
This method never frees any allocated memory even when elements get removed.
{?}_reserve()¶
Set new minimal amount of preallocated elements.
size_t myarray_reserve(myarray *self, size_t atleast)
Parameters
self: Pointer to arrayatleast: Minimal amount of elements to reserve
Return value
New capacity (which might be bigger than requested value atleast).
Notes
If atleast param is less than the current array size, the current size
is used as the minimal amount of reserved elements and atleast is
ignored.
If atleast is greater than current capacity, this method may allocate
more memory.
If atleast is less than current capacity, this method may free
some memory.