facil.io

View On GitHub

Simple Dynamic Arrays

The simple dynamic array offers a simple data structure that manages only it’s own memory (but not the memory of any objects placed in the array).

Overview

The simple dynamic array type is included in a single file library, fio_ary.h that can be used independently as well.

The Core Array is designed to contain void * pointers and doesn’t manage any memory except it’s own.

As a general rule, facil.io doen’s make assumptions about allocation / deallocation except where mentioned. A good example is the sock_write function that copies the data vs. sock_write2 which asks about the correct deallocation function to be used (defaults to free) and takes ownership of the data.

Example

Here’s a short example from the introduction to the simple core types:

#include "fio_ary.h"

int main(void) {
  // The array container.
  fio_ary_s ary;
  // allocate and initialize internal data
  fio_ary_new(&ary, 0);
  // perform some actions
  fio_ary_push(&ary, (void *)1);
  FIO_ARY_FOR(&ary, pos) {
    printf("index: %lu == %lu\n", (unsigned long)pos.i, (unsigned long)pos.obj);
  }
  // free the array's data to avoid memory leaks (doesn't free the objects)
  fio_ary_free(&ary);
}

Note that the Array container can be placed on the stack (as well as allocated using malloc), but the internal data must be allocated and deallocated using fio_ary_new and fio_ary_free.

Types

The Core Array uses the fio_ary_s type.

The data in in the fio_ary_s type shouldn’t be accessed directly. Functional access should be preferred.

typedef struct fio_ary_s {
  size_t start;
  size_t end;
  size_t capa;
  void **arry;
} fio_ary_s;

Functions

The fio_ary_new function

void fio_ary_new(fio_ary_s *ary, size_t capa)

Initializes the array and allocates memory for it’s internal data.

Note that capa indicates the initial (or minimal) capacity for the array, but the array can grow as long as memory allows.

This will assume that ary is uninitialized and overwrite any existing data.

the fio_ary_free function

void fio_ary_free(fio_ary_s *ary)

Frees the array’s internal data.

If the ary’s container (the fio_ary_s object) was allocated using malloc, a subsequent call to free(ary) must be made.

the fio_ary_count function

size_t fio_ary_count(fio_ary_s *ary)

Returns the number of elements in the Array.

the fio_ary_capa function

size_t fio_ary_capa(fio_ary_s *ary)

Returns the current, temporary, array capacity (it’s dynamic).

the fio_ary_index function

void *fio_ary_index(fio_ary_s *ary, int64_t pos)

Returns the object placed in the Array, if any. Returns NULL if no data or if the index is out of bounds.

Negative values are retrived from the end of the array. i.e., -1 is the last item.

fio_ary_entry is an alias for fiobj_ary_index.

the fio_ary_set function

void *fio_ary_set(fio_ary_s *ary, void *data, int64_t pos)

Sets an object at the requested position.

Returns the old value, if any.

If an error occurs, the same data passed to the function is returned (test using fiobj_ary_index).

the fio_ary_push function

int fio_ary_push(fio_ary_s *ary, void *data)

Pushes an object to the end of the Array. Returns -1 on error.

the fio_ary_pop function

void *fio_ary_pop(fio_ary_s *ary)

Pops an object from the end of the Array

Returns NULL if the object was NULL or the Array was empty.

the fio_ary_unshift function

int fio_ary_unshift(fio_ary_s *ary, void *data)

Unshifts an object to the beginning of the Array. Returns -1 on error.

This could be expensive, causing memmove.

the fio_ary_shift function

void *fio_ary_shift(fio_ary_s *ary)

Shifts an object from the beginning of the Array.

Returns NULL if the object was NULL or the Array was empty.

the fio_ary_compact function

void fio_ary_compact(fio_ary_s *ary)

Removes any NULL pointers from an Array, keeping all other data in the array.

This action is O(n) where n in the length of the array.

the FIO_ARY_FOR macro

FIO_ARY_FOR(ary, pos)

Iterates through the list using a for loop.

Access the data with pos.obj and it’s index with pos.i.

The pos variable can be named however you please (i.e. FIO_ARY_FOR(&bar, foo) for foo.i and foo.obj).

the fio_ary_each function

size_t fio_ary_each(fio_ary_s *ary, size_t start_at,
                                    int (*task)(void *pt, void *arg),
                                    void *arg);

Iteration using a callback for each entry in the array.

The callback task function must accept an the entry data as well as an opaque user pointer.

If the callback returns -1, the loop is broken. Any other value is ignored.

Returns the relative “stop” position, i.e., the number of items processed + the starting point.