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. .. code-block:: c #include #include #include #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. .. code-block:: c AGROW_DECL(Arr, T) **Parameters** * ``Arr``: New array type and also a prefix for methods * ``T``: 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()``. .. code-block:: c 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. .. code-block:: c int your_callback(size_t pos, T *ptr, void *data) {/*...*/} **Parameters** * ``pos``: Index of the element * ``ptr``: Pointer to the element * ``data``: Extra argument **Return value** The meaning of the return value varies for different methods. Api --- {?}_new() ^^^^^^^^^ Creates an empty array allocated on the heap. .. code-block:: c 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** .. code-block:: c 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()``. .. code-block:: c void myarray_destroy(myarray **selfptr, myarray_callback onfree, void *data) **Params:** * ``selfptr``: Pointer to **pointer** to array * ``onfree``: Callback function that is called on every element * ``data``: 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. .. code-block:: c elem *myarray_get_ptr(myarray *self, size_t pos) **Parameters** * ``self``: Pointer to array * ``pos``: 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. .. code-block:: c 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. .. code-block:: c int myarray_each(myarray *self, myarray_callback oneach, void *data) **Parameters** * ``self``: Pointer to array * ``oneach``: Callback function that is called on every element * ``data``: Extra argument passed to every invokation of `oneach()` The return value of ``oneach()`` callback * ``0``: success. Method ``each()`` 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. .. code-block:: c size_t myarray_size(myarray *self) **Parameters** * ``self``: Pointer to array **Example** .. code-block:: c 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. .. code-block:: c size_t myarray_capacity(myarray *self) **Parameters** * ``self``: Pointer to array **Example** .. code-block:: c 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. .. code-block:: c elem *myarray_append(myarray *self, myarray_callback onappend, void *data) If ``capacity`` is exceeded, it tries to allocate more memory. **Parameters** * ``self``: Pointer to array * ``onappend``: Callback function that is called on the appended element (if append was successful) * ``data``: Extra argument passed to the invokation of ``onappend()`` 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** .. code-block:: c /* 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). .. code-block:: c elem *myarray_shy_append(myarray *self, myarray_callback onappend, void *data, int *isfull) Unlike ``append()`` it never tries to allocate more memory. **Parameters** * (``self``, ``onappend`` and ``data`` are the same as for ``append()``) * ``isfull``: Pointer to a flag signalling that ``shy_append()`` failed due to exceeded ``capacity``. 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. .. code-block:: c 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 array * ``size``: The new size * ``onadd``: 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** .. code-block:: c 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. .. code-block:: c 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 array * ``isgarbage``: Callback function that is called on every element * ``onmove``: Callback function that is called on every moved element * ``data``: Extra argument passed to every invokation of ``isgarbage()`` and ``onmove()`` 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 kept * ``1``: the element should be removed and the ``vacuum()`` method should *continue* applying ``isgarbage()`` to other elements * ``2``: the element should be removed and the ``vacuum()`` method should *stop* applying ``isgarbage()`` 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. .. code-block:: c size_t myarray_reserve(myarray *self, size_t atleast) **Parameters** * ``self``: Pointer to array * ``atleast``: 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.