Simple data structures / objects in plain C Snapshot
|
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