Simple data structures / objects in plain C Snapshot
array.h
Go to the documentation of this file.
00001 /* Copyright (c) Michael Moser (2011) . 3-clause BSD License applies */
00002 
00003 #ifndef __ARRAY_H__
00004 #define __ARRAY_H__
00005 
00006 #ifdef  __cplusplus
00007 extern "C" {
00008 #endif
00009 
00010 
00011 #include <cutils/base.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 
00015 /**
00016  * @defgroup ARRAY
00017  * @brief Dynamic array, all elements contained in this structure are of the same size.
00018  *
00019  * A dynamic array, growable array, resizable array, dynamic table,
00020  * or array list is a data structure, an array which is automatically expanded to 
00021  * accommodate new objects if filled beyond its current size. 
00022  * In most ways the dynamic array has performance similar to an array, with the addition 
00023  * of new operations to add and remove elements from the end:
00024  *
00025  *   - Getting or setting the value at a particular index (constant time)
00026  *   - Iterating over the elements in order (linear time, good cache performance)
00027  *   - Add an element to the end (constant amortized time)
00028  *
00029  * From http://en.wikipedia.org/wiki/Dynamic_array
00030  *
00031  *
00032  * @{
00033  */
00034 typedef struct  {
00035 
00036         size_t   elmmaxcount;
00037         size_t   elmsize;
00038         size_t   elmcount;
00039 
00040         uint8_t  *buffer;
00041 
00042 } ARRAY;
00043 
00044 
00045 M_INLINE int ARRAY_init( ARRAY *arr, size_t elmsize, size_t numofelem)
00046 {
00047         
00048         arr->elmsize    = elmsize;
00049         arr->elmcount   = 0;
00050         arr->elmmaxcount= numofelem;
00051         arr->buffer     = 0;
00052 
00053 
00054         if (numofelem) {
00055                 if ((arr->buffer = (uint8_t *) malloc( elmsize * numofelem)) == 0) {
00056                         return -1;
00057                 }
00058         }
00059         return 0;
00060 }
00061 
00062 
00063 /**
00064  * @brief Allocates a dynamic array from already allocated memory area; 
00065  *
00066  * The memory is not owned by this object, meaning that this dynamic array cannot be resized 
00067  * (does not grow as maximum size is exceed); data are is not freed in object destructor.
00068  * 
00069  * @param arr           (out) the object
00070  * @param elmsize       (in)  size of one element
00071  * @param ptr           (in)  memory area that will contain
00072  * @param busize        (in)  size of memory area pointed to by ptr (size of Data area passed has to be greater or equal to the size of one element elmsize).
00073  * @return 0 if ok -1 on failure.
00074  */
00075 M_INLINE  int ARRAY_init_fixed( ARRAY * arr, size_t elmsize, void *ptr, size_t bufsize)
00076 {
00077         if (bufsize < elmsize) {
00078                 return -1;
00079         }
00080 
00081         arr->elmsize = elmsize;
00082 
00083         arr->elmcount = 0;
00084         arr->elmmaxcount = bufsize / elmsize;
00085         arr->buffer = ptr;
00086 
00087         return 0;
00088 }
00089 
00090 /** 
00091  * @brief Macro: Allocate dynamic array on stack
00092  *
00093  * Warning! this macro uses alloca standard library function - this is not always portable, 
00094  * and it bombs out when it causes stack overflow.
00095  *
00096  * @param arr           (out) (type ARRAY *) the object.
00097  * @param elmsize       (in)  (type size_t) size of one element
00098  * @param numofelem (in)  (type size_t) maximum number of elements.
00099  */
00100 #define ARRAY_init_stack( arr, elmsize, numofelem ) \
00101 do { \
00102         (arr)->ctx = 0; \
00103         (arr)->elmcount = 0; \
00104         (arr)->elmsize = (elmsize); \
00105         (arr)->elmmaxcount = (elmsize) * (numofelem); \
00106         (arr)->buffer = (char *) alloca( (str)->elmmaxcount ); \
00107 } while(0);
00108 
00109 
00110 /** 
00111  * @brief free all memory held by dynamic array (destructor).
00112  * @param buf (in out) the object
00113  */
00114 M_INLINE void ARRAY_free( ARRAY *arr) 
00115 {
00116         if (arr->buffer) {
00117                 free( arr->buffer );
00118                 arr->buffer = 0;
00119         }
00120 }
00121 
00122 M_INLINE  void ARRAY_reset( ARRAY * arr)
00123 {
00124         arr->elmcount = 0;
00125 }
00126 
00127 /**
00128  * @brief returns number of objects that are currently held by this collection.
00129  * @param  arr (in) the object
00130  * @return 
00131  */
00132 M_INLINE size_t ARRAY_size( ARRAY *arr) 
00133 {
00134         return arr->elmcount;
00135 }
00136 
00137 /** 
00138  * @brief returns maximum number of elements that can currently be held by this collection.
00139  * @param  arr (in) the object
00140  * @return 
00141  */
00142 M_INLINE size_t ARRAY_maxsize( ARRAY *arr )
00143 {
00144         return arr->elmmaxcount;
00145 }
00146 
00147 /**
00148  * @brief change size of dynamic array (i.e. change size of memory allocated for array)
00149  * If requested size is smaller then the current size, then all skipping elements are discarded.
00150  *
00151  * @param arr (in out) the object
00152  * @param num_elem (in) change maximum number of element to this number. 
00153  */
00154 M_INLINE int ARRAY_resize( ARRAY *arr, size_t num_elem) 
00155 {
00156         uint8_t * ptr;
00157 
00158         if (num_elem > arr->elmmaxcount) {
00159                 ptr = realloc( arr->buffer, num_elem * arr->elmsize);
00160                 if (!ptr) {
00161                         return -1;
00162                 }
00163                 arr->buffer = ptr;
00164                 arr->elmmaxcount = num_elem;
00165                 if (num_elem < arr->elmcount) {
00166                         arr->elmcount = num_elem;
00167                 }
00168         } else {
00169                 arr->elmcount = num_elem;
00170         }
00171         return 0;
00172 }
00173 
00174 M_INLINE uint8_t * ARRAY_at( ARRAY * arr, size_t index)                
00175 {
00176         if (index >= arr->elmcount) {
00177                 return 0;
00178         }
00179 
00180         return arr->buffer + (index * arr->elmsize);
00181 }
00182 
00183 M_INLINE int ARRAY_copy_at( ARRAY * arr, size_t index, void *elm, size_t elmsize) 
00184 {
00185         if (index >= arr->elmcount) {
00186                 return -1;
00187         }
00188         
00189         if (elmsize != arr->elmsize) {
00190                 return -1;
00191         }
00192 
00193         memcpy( elm, arr->buffer + (index * arr->elmsize), elmsize );
00194         return 0;
00195 }
00196 
00197 int ARRAY_insert_at( ARRAY *arr, size_t index, void *elm, size_t elmsize);
00198 
00199 int ARRAY_set_at( ARRAY *arr, size_t index, void *elm, size_t elmsize);
00200 
00201 
00202 M_INLINE int ARRAY_delete_at( ARRAY *arr, size_t index)
00203 {
00204         if (index >= arr->elmcount) {
00205                 return -1;
00206         }
00207         
00208         if (index < (arr->elmcount - 1)) {
00209                 size_t elmsize = arr->elmsize;
00210 
00211                 memmove( arr->buffer + index * elmsize,
00212                                  arr->buffer + (index + 1) * elmsize, 
00213                                  (arr->elmcount - index - 1) * elmsize);
00214                 
00215         } 
00216         --arr->elmcount;
00217         return 0;
00218 }
00219 
00220 
00221 M_INLINE int ARRAY_push_back( ARRAY *arr, void *elm, size_t elmsize)
00222 {       
00223         return ARRAY_insert_at(arr,arr->elmcount,elm, elmsize);         
00224 }
00225 
00226 
00227 M_INLINE int ARRAY_pop_back( ARRAY *arr, void *ptr, size_t elmsize )
00228 {
00229         if (arr->elmcount <=0) {
00230                 return -1;
00231         }
00232 
00233         if (ptr) {
00234                 if (elmsize != arr->elmsize) {
00235                         return -1;
00236                 }
00237 
00238                 memcpy( ptr, arr->buffer + (--arr->elmcount) * arr->elmsize, elmsize);
00239         }
00240         return 0;
00241 }
00242 
00243 M_INLINE int ARRAY_stack_top( ARRAY *arr, void *ptr, size_t elmsize )
00244 {
00245         if (arr->elmcount <=0) {
00246                 return -1;
00247         }
00248 
00249         if (ptr) {
00250                 if (elmsize != arr->elmsize) {
00251                         return -1;
00252                 }
00253 
00254                 memcpy( ptr, arr->buffer + arr->elmcount * arr->elmsize, elmsize);
00255         }
00256         return 0;
00257 }
00258 
00259 #if 0
00260 
00261 #define ARRAY_FOREACH( loopvarname, array )
00262   
00263 #define ARRAY_FOREACH_RANGE( loopvarname, from_idx, to_idx, array )
00264 
00265 #define ARRAY_FOREACH_REVERSE( loopvarname, array )
00266 
00267 #define ARRAY_FOREACH_REVERSE_RANGE( loopvarname, from_idx, to_idx, array )
00268 
00269 #endif
00270 
00271 /* Ups: can do this only with gcc typeof, very bad, not portable
00272 
00273 #define ARRAY_FOREACH( loopvarname, array )     {\
00274         char *ARRAY_FOREACH_##loopvarname_eof = (array)->buffer + ((array)->elmcount * (array)->elmsize); \
00275         char *ARRAY_FOREACH_##loopvarname_ptr = (array)->buffer; \
00276         for(;ARRAY_FOREACH_##loopvarname_ptr < ARRAY_FOREACH_##loopvarname_eof; ARRAY_FOREACH_##loopvarname_ptr += (array)->elmsize) { \
00277                 loopvarname = (cast-to-type-of-loopvarname) ARRAY_FOREACH_##loopvarname_ptr
00278 */
00279 
00280 
00281 typedef int  (*ARRAY_VISITOR)   (int index, void *elm, size_t elmsize, void *context);
00282 
00283 M_INLINE void ARRAY_foreach( ARRAY *arr, ARRAY_VISITOR eval, void *context)
00284 {
00285         size_t i;
00286         size_t sz = arr->elmcount;
00287         size_t elmsz = arr->elmsize;
00288         uint8_t *pos;
00289 
00290         for(pos = arr->buffer, i = 0; i < sz; i++, pos += elmsz) {
00291                 eval( i, pos, elmsz, context ); 
00292         }
00293 }
00294 
00295 M_INLINE int ARRAY_foreach_range( ARRAY *arr, ARRAY_VISITOR eval, void *context, int from_idx, int to_idx)
00296 {
00297         size_t i;
00298         size_t sz = arr->elmcount;
00299         size_t elmsz = arr->elmsize;
00300         uint8_t *pos;
00301 
00302         if (!(from_idx > 0 && from_idx < to_idx && (size_t) to_idx <  sz)) {
00303                 return -1;
00304         }
00305 
00306         for(pos = arr->buffer + (from_idx * elmsz), i = from_idx; i < (size_t) to_idx; i++, pos += elmsz) {
00307                 eval( i, pos, elmsz, context ); 
00308         }
00309 
00310         return 0;
00311 }
00312 
00313 
00314 
00315 M_INLINE void ARRAY_foreach_reverse( ARRAY *arr, ARRAY_VISITOR eval, void *context)
00316 {
00317         size_t i;
00318         size_t sz = arr->elmcount;
00319         size_t elmsz = arr->elmsize;
00320         uint8_t *pos;
00321 
00322         for(pos = arr->buffer + (elmsz * (sz-1)), i = sz-1; ; i--, pos -= elmsz) {
00323                 eval( i, pos, elmsz, context ); 
00324                 if (i == 0) {
00325                         break;
00326                 }
00327         }
00328 }
00329 
00330 
00331 M_INLINE int ARRAY_foreach_reverse_range( ARRAY *arr, ARRAY_VISITOR eval, void *context, int from_idx, int to_idx)
00332 {
00333         int i;
00334         size_t sz = arr->elmcount;
00335         size_t elmsz = arr->elmsize;
00336         uint8_t *pos;
00337 
00338         if (!(from_idx > 0 && from_idx < to_idx && (size_t) to_idx < sz)) {
00339                 return -1;
00340         }
00341 
00342         for(i = (to_idx - 1), pos = arr->buffer + (elmsz * i); ; i--, pos -= elmsz) {
00343                 eval( i, pos, elmsz, context ); 
00344                 if (i == from_idx) {
00345                         break;
00346                 }
00347         }
00348 
00349         return 0;
00350 }
00351 
00352 
00353 M_INLINE int ARRAY_findif( ARRAY *arr, ARRAY_VISITOR eval, void *context, uint32_t *retval)
00354 {
00355         size_t i;
00356         size_t sz = arr->elmcount;
00357         size_t elmsz = arr->elmsize;
00358         uint32_t ret;
00359         uint8_t *pos;
00360 
00361         if (!retval) {
00362           *retval = 0;
00363         }
00364 
00365         for(i = 0, pos = arr->buffer; i < sz; i++, pos += elmsz) {
00366                 if ( (ret = eval( i, pos, elmsz, context )) != 0) {
00367                         if (retval) {
00368                                 *retval = ret;
00369                         }
00370                         return i;
00371                 }
00372         }
00373         return -1;
00374 }
00375 
00376 M_INLINE int ARRAY_findif_range( ARRAY *arr, ARRAY_VISITOR eval, void *context,  
00377                                                             int from_idx, int to_idx, uint32_t *retval)
00378 {
00379         int  i;
00380         size_t sz = arr->elmcount;
00381         size_t elmsz = arr->elmsize;
00382         uint32_t ret;
00383         uint8_t *pos;
00384 
00385         if (!retval) {
00386           *retval = 0;
00387         }
00388 
00389         if (!(from_idx > 0 && from_idx < to_idx && (size_t) to_idx < sz)) {
00390                 return -1;
00391         }
00392 
00393         for(i = from_idx, pos = arr->buffer + (from_idx * elmsz); i < to_idx; i++, pos += elmsz) {
00394                 if ((ret = eval( i, pos, elmsz, context )) != 0) {
00395                         if (retval) {
00396                                 *retval = ret;
00397                         }                       
00398                         return i;
00399                 }
00400         }
00401 
00402         return -1;
00403 }
00404 
00405 
00406 
00407 M_INLINE int ARRAY_findif_reverse( ARRAY *arr, ARRAY_VISITOR eval, void *context, uint32_t *retval)
00408 {
00409         size_t i;
00410         size_t sz = arr->elmcount;
00411         size_t elmsz = arr->elmsize;
00412         uint32_t ret;
00413         uint8_t *pos;
00414 
00415         if (!retval) {
00416           *retval = 0;
00417         }
00418 
00419         for(i = sz-1, pos = arr->buffer + (elmsz * (sz-1)); ; i--, pos -= elmsz) {
00420                 if ((ret = eval( i, pos, elmsz, context )) != 0) {
00421                         if (retval) {
00422                                 *retval = ret;
00423                         }                       
00424                         return i;
00425                 }
00426                 if (i == 0) {
00427                         break;
00428                 }
00429         }
00430         return -1;
00431 }
00432 
00433 
00434 M_INLINE int ARRAY_findif_reverse_range( ARRAY *arr, ARRAY_VISITOR eval, void *context, 
00435                                                                           int from_idx, int to_idx, uint32_t *retval)
00436 {
00437         int i;
00438         size_t sz = arr->elmcount;
00439         size_t elmsz = arr->elmsize;
00440         uint32_t ret;
00441         uint8_t *pos;
00442 
00443         if (!retval) {
00444           *retval = 0;
00445         }
00446 
00447         if (!(from_idx > 0 && from_idx < to_idx && (size_t) to_idx < sz)) {
00448                 return -1;
00449         }
00450 
00451         for(i = to_idx - 1, pos = arr->buffer + (elmsz * i); ; i--, pos -= elmsz) {
00452                 if ((ret = eval( i, pos, elmsz, context )) != 0) {
00453                         if (retval) {
00454                                 *retval = ret;
00455                         }                       
00456                         return i;
00457                 }
00458                 if (i == from_idx) {
00459                         break;
00460                 }
00461         }
00462 
00463         return -1;
00464 }
00465 
00466 
00467 /** 
00468  * @brief iterate over all entries of the array and delete entries that match predicate from the array.
00469  * @param list (in) the object.
00470  * @param check_if (in) predicate function; the function returns 1 then inspected argument element will be deleted; if argument pointer is NULL then all entries will be deleted. 
00471  * @param context (in) data pointer passed to every invocation of check_if
00472  */
00473 #if 0
00474 M_INLINE void ARRAY_deleteif( ARRAY *list, VDLIST_VISITOR check_if, void *context)
00475 {
00476     VDLIST_entry *cur,*next,*del;
00477 
00478     VDLIST_FOREACH_SAVE(cur,next,list) {
00479                 if (!check_if || check_if( list, cur, context))  {
00480                         del = VDLIST_unlink( list, cur );
00481                         if (free_ctx) {
00482                                 free_ctx->free( M_MEMBEROF(del,offset_of_link) );
00483                         }
00484                 }
00485         }
00486 }
00487 #endif
00488 
00489 /**
00490  * @}
00491  */
00492 
00493 #ifdef  __cplusplus
00494 }
00495 #endif
00496 
00497 #endif