Dynamic arrays


Detailed Description

Generic implementation of dynamic arrays. Here is a set of macros for mamaging dynamic arrays of arbitrary types. To declare a new dynamic array type, use fid_DYNARRAY_DECLARE(). Then use fid_DYNARRAY_INIT() or fid_DYNARRAY_INIT_PREALLOC() for initialization, and one of the various macros described in here to add or remove elements to/from your array. When running out of space, the array will grow automatically (depending on the macro used). Free up the space occupied by your array with fid_DYNARRAY_FREE().

Macro fid_DYNARRAY_DECLARE() declares a new dynamic array type of a given name, storing elements of given type. This new type has several members, where the "public" ones are

The actual data is stored in memory pointed to by dyndata. This is a pointer of the type passed to fid_DYNARRAY_DECLARE(). The number of allocated elements is stored in allocated. This is the total number of elements of the stored type that the array can store, not the size of the memory block in bytes. If the total size needs to be known in bytes, then this can be obtained by multiplying allocated with the size of the stored type. The number of elements currently in use is stored in occupied. The dynamic arrays implemented here do not maintain a free-list, but assume a stack-like organization. That is, the value occupied is always interpreted in a way that elements 0, 1, ..., occupied-1 are in use, and that elements occupied, occupied+1, ..., allocated-1 are free. This makes the element at index occupied-1 the last used element in the array, which can be accessed easily using macro fid_DYNARRAY_TOPELEM().

Note:
When compiled for debugging (i.e., with preprocessor symbol DEBUG defined), then the array structures are augmented with one extra member that is used for additional checks. These checks are only performed in debug mode. An implication is that array structure sizes are different in debug and non-debug modes, so that applications compiled with DEBUG are binary incompatible with a version of libfid compiled without DEBUG (and vice versa). Please keep this in mind when observing strange things happening.

Data Structures

struct  fid_Arraychar
 Dynamic array of char values. More...
struct  fid_Arrayuchar
 Dynamic array of unsigned char values. More...
struct  fid_ArrayUint32
 Dynamic array of fid_Uint32 values. More...
struct  fid_ArrayUint64
 Dynamic array of fid_Uint64 values. More...
struct  fid_ArraySint32
 Dynamic array of fid_Sint32 values. More...
struct  fid_ArraySint64
 Dynamic array of fid_Sint64 values. More...

Defines

#define fid_DYNARRAY_SIZECHECK(ARRAY, TYPE)
 Debugging.
#define fid_DYNARRAY_DECLARE(NAME, TYPE)
 Declare a dynamic array.
#define fid_DYNARRAY_INIT(ARRAY, TYPE)
 Initialize a dynamic array.
#define fid_DYNARRAY_FREE(ARRAY, TYPE)
 Free space occupied by a dynamic array.
#define fid_DYNARRAY_PUSH_UNSAFE(ARRAY, TYPE)   ++(ARRAY)->occupied
 Append element to dynamic array, without size check.
#define fid_DYNARRAY_POP_ELEM(ARRAY, TYPE, VAL)   (VAL)=(ARRAY)->dyndata[--(ARRAY)->occupied]
 Assign last element of dynamic array to some variable, and remove it from the array.
#define fid_DYNARRAY_POP(ARRAY, TYPE)   --(ARRAY)->occupied
 Remove last element from dynamic array.
#define fid_DYNARRAY_ENSURE_NFREE(ARRAY, TYPE, N, FAILCODE)
 Make sure that there are at least n free elements in dynamic array.
#define fid_DYNARRAY_ENSURE_NEXT(ARRAY, TYPE, N, FAILCODE)
 Make sure that the next element in a dynamic array can be written to.
#define fid_DYNARRAY_INIT_PREALLOC(ARRAY, TYPE, N, FAILCODE)
 Initialize a dynamic array, pre-allocate some elements.
#define fid_DYNARRAY_APPEND(ARRAY, TYPE, N, VAL, FAILCODE)
 Append a value to a dynamic array.
#define fid_DYNARRAY_APPEND_UNSAFE(ARRAY, TYPE, VAL)
 Append a value to a dynamic array, without size check.
#define fid_DYNARRAY_PUSH(ARRAY, TYPE, N, FAILCODE)
 Append element to dynamic array.
#define fid_DYNARRAY_TOPELEM(ARRAY, TYPE)   ((ARRAY)->dyndata[(ARRAY)->occupied-1])
 Access last/top element in dynamic array.
#define fid_DYNARRAY_SHRINK(ARRAY, TYPE, FAILCODE)
 Reallocate array so that it does not use up more space than necessary.

Define Documentation

#define fid_DYNARRAY_SIZECHECK ( ARRAY,
TYPE   ) 

Debugging.

Only defined to something meaningful in debug mode (i.e., when DEBUG is defined). Please ignore this.

Definition at line 206 of file arrays.h.

#define fid_DYNARRAY_DECLARE ( NAME,
TYPE   ) 

Value:

typedef struct\
  {\
    size_t occupied;     /*!<\brief Number of elements in use. */\
    size_t allocated;    /*!<\brief Number of elements for which space has
                          * been allocated. */\
    TYPE *dyndata;       /*!<\brief Pointer to array data. */\
    TYPE *prev_dyndata;  /*!<\brief Temporary used before calling\
                          * \c realloc() to prevent leaking memory. */\
  } NAME
Declare a dynamic array.

Parameters:
NAME The name of the new structure.
TYPE The type of elements to be stored inside the dynamic array.

Definition at line 208 of file arrays.h.

#define fid_DYNARRAY_INIT ( ARRAY,
TYPE   ) 

Value:

(ARRAY)->occupied=(ARRAY)->allocated=0;\
  (ARRAY)->dyndata=(TYPE *)NULL;\
  (ARRAY)->prev_dyndata=(TYPE *)NULL
Initialize a dynamic array.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.

Definition at line 217 of file arrays.h.

Referenced by fid_projectfile_init().

#define fid_DYNARRAY_FREE ( ARRAY,
TYPE   ) 

Value:

fid_DYNARRAY_SIZECHECK(ARRAY,TYPE);\
  if(((ARRAY)->dyndata) != NULL)\
  {\
    free((ARRAY)->dyndata);\
  }
Free space occupied by a dynamic array.

This macro does attempt not iterate over the array's elements and free them. If the array elements need to be freed, maybe because they contain pointers to allocated memory, then you must free them by yourself before calling this macro.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.

Definition at line 222 of file arrays.h.

Referenced by fid_suffixarray_traverse().

#define fid_DYNARRAY_PUSH_UNSAFE ( ARRAY,
TYPE   )     ++(ARRAY)->occupied

Append element to dynamic array, without size check.

This macro, like fid_DYNARRAY_PUSH(), does not store anything to the array. It is just a convenience macro that increases the occupied member of the array. After that, the element at index occupied is considered free and can be written to. This macro is used to be make the code more readable, and also to emphasize that a simple increment of the occupied variable is not safe in general.

Use fid_DYNARRAY_PUSH() if the dynamic array may need to be resized. Also check if fid_DYNARRAY_APPEND() or fid_DYNARRAY_APPEND_UNSAFE() are more appropriate for your application.

Never use this macro unless you are absolutely sure that there is enough free space in the array. The debug version may catch an attempt to write beyond array bounds, but the non-debug version will not.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.

Definition at line 229 of file arrays.h.

#define fid_DYNARRAY_POP_ELEM ( ARRAY,
TYPE,
VAL   )     (VAL)=(ARRAY)->dyndata[--(ARRAY)->occupied]

Assign last element of dynamic array to some variable, and remove it from the array.

This macro is unsafe. If the array is empty, your program will not do the correct thing since it will try to read the non-existent element beyond the lower array boundary. The debug version might catch such a mistake, the non-debug version will not.

Also think if the assignment performed by this macro is correct for your application, or if the use of some copy function would be more approriate, or if you could simply use the array element directly.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
VAL A variable of type TYPE that the last element of the dynamic array is assigned to.

Definition at line 232 of file arrays.h.

#define fid_DYNARRAY_POP ( ARRAY,
TYPE   )     --(ARRAY)->occupied

Remove last element from dynamic array.

Like fid_DYNARRAY_PUSH_UNSAFE(), this macro is a convenience macro that simply decrements the occupied member of the passed dynamic array. And like fid_DYNARRAY_POP_ELEM(), it is also unsafe to use it on empty arrays.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.

Definition at line 235 of file arrays.h.

Referenced by fid_suffixarray_traverse().

#define fid_DYNARRAY_ENSURE_NFREE ( ARRAY,
TYPE,
N,
FAILCODE   ) 

Value:

fid_DYNARRAY_SIZECHECK(ARRAY,TYPE);\
  if((ARRAY)->occupied+(N) > (ARRAY)->allocated)\
  {\
    (ARRAY)->allocated=(ARRAY)->occupied+(N);\
    (ARRAY)->prev_dyndata=(ARRAY)->dyndata;\
    (ARRAY)->dyndata=(TYPE *)realloc((ARRAY)->dyndata,sizeof(TYPE)*(ARRAY)->allocated);\
    if((ARRAY)->dyndata == NULL)\
    {\
      (ARRAY)->dyndata=(ARRAY)->prev_dyndata;\
      FAILCODE\
    }\
  }\
  assert((ARRAY)->dyndata != NULL)
Make sure that there are at least n free elements in dynamic array.

If you know that you will store a certain number of elements inside a dynamic array, then this macro can be used to pre-allocate this number of elements. After a successful call of this macro, the next N elements, starting at index occupied, can be used safely. This means that macros like fid_DYNARRAY_PUSH_UNSAFE() or fid_DYNARRAY_APPEND_UNSAFE() can be used safely up to N times in order to access the next N elements of the array.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
N The number of elements needed.
FAILCODE When there is not enough memory left, then this code is executed.
Note:
In case of failure, the dyndata pointer will still point to the old memory block, which is left intact.

Definition at line 259 of file arrays.h.

#define fid_DYNARRAY_ENSURE_NEXT ( ARRAY,
TYPE,
N,
FAILCODE   ) 

Value:

fid_DYNARRAY_SIZECHECK(ARRAY,TYPE);\
  if((ARRAY)->occupied >= (ARRAY)->allocated)\
  {\
    (ARRAY)->allocated=(ARRAY)->occupied+(N);\
    (ARRAY)->prev_dyndata=(ARRAY)->dyndata;\
    (ARRAY)->dyndata=(TYPE *)realloc((ARRAY)->dyndata,sizeof(TYPE)*(ARRAY)->allocated);\
    if((ARRAY)->dyndata == NULL)\
    {\
      (ARRAY)->dyndata=(ARRAY)->prev_dyndata;\
      FAILCODE\
    }\
  }\
  assert((ARRAY)->dyndata != NULL)
Make sure that the next element in a dynamic array can be written to.

Before writing to the next element in a dynamic array, use this macro to make sure that this next element can actually be used. When running out of space, the macro resizes the dynamic array so that N more elements can be stored. After a successful call of this macro, the element at index occupied can safely be written to, and unsafe macros like fid_DYNARRAY_PUSH_UNSAFE() may be used once (in that case, however, you may use fid_DYNARRAY_PUSH() as well).

Use fid_DYNARRAY_ENSURE_NFREE() to pre-allocate a specific number of free elements.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
N The number of elements to add to the array when running out of space. This value should be an estimate on how many elements are likely to be added while the application is running. The greater this value, the fewer reallocations will happen, which is good for performance, but the more space is likely to be wasted.
FAILCODE When there is not enough memory left, then this code is executed.
Note:
In case of failure, the dyndata pointer will still point to the old memory block, which is left intact.

Definition at line 301 of file arrays.h.

#define fid_DYNARRAY_INIT_PREALLOC ( ARRAY,
TYPE,
N,
FAILCODE   ) 

Value:

fid_DYNARRAY_INIT(ARRAY,TYPE);\
  fid_DYNARRAY_ENSURE_NFREE(ARRAY,TYPE,N,FAILCODE);\
  (ARRAY)->occupied=(ARRAY)->allocated
Initialize a dynamic array, pre-allocate some elements.

Like fid_DYNARRAY_INIT(), but also make sure that the first N elements can be written to. The occupied member is initialized to point beyond the last free element (i.e., set to the same value as allocated) so as to mark all elements used.

This macro makes using dynamic arrays convenient to use as fixed-size arrays (that may, of course, be enlarged later), when the number of elements, or initial number of elements, is known in advance.

Note:
Unsafe macros that rely on the value of occupied being smaller than allocated, like fid_DYNARRAY_APPEND_UNSAFE(), must not be used on pre-allocated arrays initialized by this macro. Using macros like fid_DYNARRAY_APPEND() may not work as expected since they will write after the pre-allocated elements.
Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
N The number of elements to allocate.
FAILCODE When there is not enough memory left, then this code is executed.

Definition at line 340 of file arrays.h.

#define fid_DYNARRAY_APPEND ( ARRAY,
TYPE,
N,
VAL,
FAILCODE   ) 

Value:

fid_DYNARRAY_ENSURE_NEXT(ARRAY,TYPE,N,FAILCODE);\
  (ARRAY)->dyndata[(ARRAY)->occupied++]=(VAL)
Append a value to a dynamic array.

This is a shortcut for a call of fid_DYNARRAY_ENSURE_NEXT(), followed by an assignment of a value to the last element of a dynamic array, followed by an increment of occupied.

The passed value VAL is stored via assigment. If this is not enough, i.e., you need to call some copy function to make a real copy, then may prefer to use fid_DYNARRAY_PUSH(), which does the same as this macro does, but omits the assigment.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
N The number of elements to add to the array when running out of space. See fid_DYNARRAY_ENSURE_NEXT().
VAL The value of type TYPE to be stored.
FAILCODE When there is not enough memory left, then this code is executed.
Note:
In case of failure, the dyndata pointer will still point to the old memory block, which is left intact.

Definition at line 368 of file arrays.h.

#define fid_DYNARRAY_APPEND_UNSAFE ( ARRAY,
TYPE,
VAL   ) 

Value:

fid_DYNARRAY_SIZECHECK(ARRAY,TYPE);\
  (ARRAY)->dyndata[(ARRAY)->occupied++]=(VAL)
Append a value to a dynamic array, without size check.

Just like fid_DYNARRAY_APPEND(), but omit the check if there is enough space left.

Never use this macro unless you are absolutely sure that there is enough free space in the array. The debug version may catch an attempt to write beyond array bounds, but the non-debug version will not.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array. space. See fid_DYNARRAY_ENSURE_NEXT().
VAL The value of type TYPE to be stored.

Definition at line 387 of file arrays.h.

#define fid_DYNARRAY_PUSH ( ARRAY,
TYPE,
N,
FAILCODE   ) 

Value:

fid_DYNARRAY_ENSURE_NEXT(ARRAY,TYPE,N,FAILCODE);\
  fid_DYNARRAY_PUSH_UNSAFE(ARRAY,TYPE)
Append element to dynamic array.

Simpler alternative for fid_DYNARRAY_APPEND() when assignment is not good enough. After a successful call of this macro, you may want to use fid_DYNARRAY_TOPELEM() to initialize the new element.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
N The number of elements to add to the array when running out of space. See fid_DYNARRAY_ENSURE_NEXT().
FAILCODE When there is not enough memory left, then this code is executed.
Note:
In case of failure, the dyndata pointer will still point to the old memory block, which is left intact.

Definition at line 408 of file arrays.h.

Referenced by fid_suffixarray_traverse().

#define fid_DYNARRAY_TOPELEM ( ARRAY,
TYPE   )     ((ARRAY)->dyndata[(ARRAY)->occupied-1])

Access last/top element in dynamic array.

Just a shortcut macro to make the code more readable. It is safe to put a & in front of this macro to obtain a pointer to the last element. (Bear in mind, however, that this pointer may quickly become invalid when the array needs to be reallocated.)

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.

Definition at line 423 of file arrays.h.

Referenced by fid_suffixarray_traverse().

#define fid_DYNARRAY_SHRINK ( ARRAY,
TYPE,
FAILCODE   ) 

Value:

if((ARRAY)->occupied > 0)\
  {\
    if((ARRAY)->allocated > (ARRAY)->occupied)\
    {\
      (ARRAY)->prev_dyndata=(ARRAY)->dyndata;\
      (ARRAY)->dyndata=(TYPE *)realloc((ARRAY)->dyndata,sizeof(TYPE)*(ARRAY)->occupied);\
      if((ARRAY)->dyndata != NULL)\
      {\
        (ARRAY)->allocated=(ARRAY)->occupied;\
      }\
      else\
      {\
        (ARRAY)->dyndata=(ARRAY)->prev_dyndata;\
        FAILCODE\
      }\
    }\
  }\
  else\
  {\
    fid_DYNARRAY_FREE(ARRAY,TYPE);\
    fid_DYNARRAY_INIT(ARRAY,TYPE);\
  }
Reallocate array so that it does not use up more space than necessary.

If the array is empty, i.e., occupied is zero, then the array will be freed and re-initialized.

Parameters:
ARRAY A pointer to a dynamic array.
TYPE Type of the elements stored inside the dynamic array.
FAILCODE When reallocation failed, then this code is executed.
Note:
In case of failure, the dyndata pointer will still point to the old memory block, which is left intact. This means, it might be safe to ignore a failure, and keep your program running even in case of failure since all data will still be there, and the rest of the dynamic array will remain unchanged.

Definition at line 442 of file arrays.h.


Generated on Wed Jul 8 17:21:16 2009 for Full-text Index Data structure library by  doxygen 1.5.9