Simple data structures / objects in plain C Snapshot
dlistunr.h
Go to the documentation of this file.
00001 #ifndef _DLISTUNR_H_
00002 #define _DLISTUNR_H_
00003 
00004 #ifdef  __cplusplus
00005 extern "C" {
00006 #endif
00007 
00008 #include <cutils/base.h>
00009 #include <cutils/dring.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 
00013 
00014 typedef struct tagDLISTUNR_entry {
00015   DRING  ring;  
00016   size_t elmcount;
00017   uint8_t buffer[];
00018 } DLISTUNR_entry;
00019 
00020 
00021 
00022 /**
00023  * @defgroup DLISTUNR
00024  * @brief unrolled list where each list node contains an array of nodes.
00025  * Unlike other lists here, each element in a list is of the same size.
00026 
00027  * an unrolled linked list is a variation on the linked list which stores multiple 
00028  * elements in each node. It can drastically increase cache performance, 
00029  * while decreasing the memory overhead associated with storing links to other list elements.. 
00030  *
00031  * Each node holds up to a certain maximum number of elements, typically just large 
00032  * enough so that the node fills a single cache line or a small multiple thereof. 
00033  * A position in the list is indicated by both a reference to the node and a position 
00034  * in the elements array. It's also possible to include a previous pointer for an unrolled 
00035  * doubly-linked linked list.
00036  * Quoted from http://en.wikipedia.org/wiki/Unrolled_linked_list
00037  *
00038  * @{
00039  */
00040 typedef struct {
00041 
00042         size_t elmsize;                 /* size of element */
00043         size_t elmmaxcount;             /* number of elements in one entry */
00044 
00045         size_t elmcount;                /* size of elements in list (global) */
00046         size_t entrycount;              /* number of entries */
00047 
00048         DLISTUNR_entry root;
00049 
00050 }
00051         DLISTUNR;
00052 
00053 typedef void (*DLISTUNR_VISITOR_V)(DLISTUNR *list, void *entry, void *context);
00054 typedef int  (*DLISTUNR_VISITOR)  (DLISTUNR *list, void *entry, void *context);
00055 
00056 /**
00057  * Current position of iteration through an unrolled linked list structure.
00058  */
00059 typedef struct {
00060         DLISTUNR_entry *entry;
00061         size_t                            index;
00062 } DLISTUNR_position;
00063 
00064 
00065 /**
00066  * @brief initialises a new unrolled list. List entries are all of a fixed size.
00067  * @param ctx (in) allocator interface. (if null we are using the default allocator)
00068  * @param list (in) object that is initialised
00069  * @param elmsize (in) size of one element in list.
00070  * @param elmmaxcount (in) number of element stored in one list entry
00071  */
00072 M_INLINE int    DLISTUNR_init(  DLISTUNR *list, size_t elmsize, size_t elmmaxcount)
00073 {       
00074         list->elmmaxcount = elmmaxcount;
00075         list->elmsize = elmsize;
00076 
00077         list->elmcount = list->entrycount = 0;
00078 
00079         DRING_init( &list->root.ring );
00080         list->root.elmcount = (size_t) -1;
00081 
00082         return 0;
00083 }
00084 
00085 /**
00086  * @brief check validity of unrolled list instance
00087  * @param list the object
00088  * @return 0 if list is invalid.
00089  */
00090 M_INLINE int DLISTUNR_check(DLISTUNR *list)
00091 {
00092         size_t elmcount, size = 0;
00093         size_t cursize = 0;
00094         DRING *cur,*next;
00095 
00096         if (list->root.elmcount != (size_t) -1) {
00097                 return 0;
00098         }
00099 
00100         DRING_FOREACH( cur, &list->root.ring)   {
00101 
00102                 next = cur->next;
00103                 if (!next || next->prev != cur) {               
00104                         return 0;
00105                 }
00106                 elmcount = ((DLISTUNR_entry *) cur)->elmcount;
00107                 if ( elmcount > list->elmmaxcount) {
00108                         return 0;
00109                 }
00110                 if (elmcount == 0) {
00111                         return 0;
00112                 }
00113                 size++;
00114                 cursize += elmcount;
00115         }
00116 
00117         if (size != list->entrycount) {
00118                 return 0;
00119         }
00120         if (cursize != list->elmcount) {
00121                 return 0;
00122         }
00123 
00124         return 1;
00125 }
00126 
00127 
00128 /**
00129  * @brief checks if argument list is empty
00130  * @param list pointer to list.
00131  * @returns not zero for non empty list.
00132  */
00133 M_INLINE int DLISTUNR_isempty( DLISTUNR *list )
00134 {
00135         return list->elmcount == 0;
00136 }
00137 
00138 
00139 M_INLINE size_t DLISTUNR_size( DLISTUNR *list) 
00140 {
00141         return list->elmcount;
00142 }
00143 
00144 
00145 M_INLINE size_t DLISTUNR_maxsize( DLISTUNR  *list )
00146 {
00147         return list->elmmaxcount;
00148 }
00149 
00150 /**
00151  * @brief Returns position structure of first element in unrolled linked list.
00152  * @param list (in) the object
00153  * @return position structure of first element
00154  */
00155 M_INLINE DLISTUNR_position DLISTUNR_get_first( DLISTUNR *list )
00156 {
00157         DLISTUNR_position ret;
00158 
00159         ret.entry = (DLISTUNR_entry *) list->root.ring.next;
00160         ret.index = 0;
00161 
00162         return ret;
00163 }
00164 
00165 
00166 /**
00167  * @brief Returns position structure of last element in unrolled linked list.
00168  * @param list (in) the object
00169  * @return position structure of first element
00170  */
00171 M_INLINE DLISTUNR_position DLISTUNR_get_last( DLISTUNR *list )
00172 {
00173         DLISTUNR_position ret;
00174 
00175         if (list->elmcount) {
00176                 ret.entry = (DLISTUNR_entry *) list->root.ring.prev;
00177                 ret.index = ret.entry->elmcount - 1;            
00178         } else  {
00179                 ret = DLISTUNR_get_first( list);
00180         }
00181         
00182         return ret;
00183 }
00184 
00185 /**
00186  * @brief Returns position to the next element in unrolled linked list.
00187  * @param list (in) the object
00188  * @param pos (in) iteration position in list.
00189  * @return position structure of the element that follows the element identified by pos structure.
00190  */
00191 M_INLINE DLISTUNR_position DLISTUNR_next(DLISTUNR_position pos)
00192 {
00193         DLISTUNR_position ret;
00194         DLISTUNR_entry *entry;
00195 
00196         ret = pos;
00197         entry = pos.entry;
00198 
00199         ret.index++;
00200         if (ret.index >= entry->elmcount) {
00201                 ret.entry = (DLISTUNR_entry *) entry->ring.next;
00202                 ret.index = 0;
00203         }
00204         return ret;
00205 }
00206 
00207 M_INLINE int DLISTUNR_is_eof(DLISTUNR *list, DLISTUNR_position pos)
00208 {
00209     return pos.entry == (DLISTUNR_entry *) &list->root; 
00210 }
00211 
00212 
00213 /**
00214  * @brief Returns position to the previous element in unrolled linked list.
00215  * @param list (in) the object
00216  * @param pos (in) iteration position in list.
00217  * @return position structure of the element that precedes the element identified by pos structure.
00218  */
00219 M_INLINE DLISTUNR_position DLISTUNR_prev(DLISTUNR_position pos)
00220 {
00221         DLISTUNR_position ret;
00222         DLISTUNR_entry *entry;
00223 
00224         ret = pos;
00225         entry = pos.entry;
00226         if (ret.index) {
00227                 ret.index--;
00228         } else {
00229                 ret.entry = (DLISTUNR_entry *) entry->ring.prev;
00230                 ret.index = 0;
00231                 if (ret.entry && ret.entry->elmcount != (size_t) -1) {
00232                         ret.index = ret.entry->elmcount - 1;
00233                 } 
00234         }
00235         return ret;
00236 }
00237 
00238 
00239 /**
00240  * @brief verify a position structure.
00241  */
00242 M_INLINE int DLISTUNR_check_position( DLISTUNR_position pos)
00243 {
00244         if (!pos.entry) {
00245                 return -1;
00246         }
00247         if (pos.index >= pos.entry->elmcount) {
00248                 return -1;
00249         }
00250         return 0;
00251 }
00252 
00253 /** 
00254  * @brief copy list entry identified by position structure (pos) into  user supplied memory area
00255  * @param list (in) the object
00256  * @param pos  (in) position pointer
00257  * @param data (in|out) user supplied buffer
00258  * @param size (in) size of user supplied buffer (must be equal to the size of one element).
00259  * @return 0 on success -1 on failure
00260  */
00261 M_INLINE int DLISTUNR_copy_at(DLISTUNR *list, DLISTUNR_position pos, void *data, size_t size)
00262 {
00263         void *ptr;
00264         if (size != list->elmsize) {
00265                 return -1;
00266         }
00267         if (DLISTUNR_check_position(pos)) {
00268                 return -1;
00269         }
00270 
00271         ptr = pos.entry->buffer + pos.index * size;
00272         memcpy(data, ptr, size);
00273 
00274         return 0;
00275 }
00276 
00277 /** 
00278  * @brief return pointer to list entry identified by position structure (pos).
00279  * @param list (in) the object
00280  * @param pos  (in) position pointer
00281  * @return pointer to data entry in linked list.
00282  */
00283 
00284 M_INLINE uint8_t * DLISTUNR_at(DLISTUNR *list, DLISTUNR_position pos)
00285 {
00286         if (DLISTUNR_check_position(pos)) {
00287                 return 0;
00288         }
00289 
00290         return pos.entry->buffer + pos.index * list->elmsize;
00291 }
00292 
00293 /**
00294  * @brief insert new entry after a given entry into this unrolled linked list 
00295  * @param list (in) pointer to list head
00296  * @param pos  (in) current position (newentry inserted after this one).
00297  * @param data (in) pointer to element that is to be inserted into this list.
00298  * @param size (in) size of area identified by data pointer.
00299  */
00300 int DLISTUNR_insert_after(DLISTUNR *list, DLISTUNR_position pos, void *data, size_t size);
00301 
00302 /**
00303  * @brief insert new entry before a given entry into this unrolled linked list 
00304  * @param list (in) pointer to list head
00305  * @param pos  (in) current position (newentry inserted before this one).
00306  * @param data (in) pointer to element that is to be inserted into this list.
00307  * @param size (in) size of area identified by data pointer.
00308  */
00309 M_INLINE int DLISTUNR_insert_before(DLISTUNR *list, DLISTUNR_position pos, void *data, size_t size)
00310 {
00311         DLISTUNR_position insert_pos = DLISTUNR_prev(pos);
00312         
00313         return DLISTUNR_insert_after( list, insert_pos, data, size);
00314 }
00315 
00316 
00317 /**
00318  * @brief delete an element from a unrolled list.
00319  * @param list (in) the object
00320  * @param pos (in)  deletes element identified by this position structure
00321  * return -1 on failure 0 on success.
00322  */
00323  int DLISTUNR_unlink(DLISTUNR *list, DLISTUNR_position pos);
00324 
00325 
00326 /**
00327  * @brief insert element as last in list (used to maintain queue)
00328  * @param list (in) the object
00329  * @param data (in) pointer to element that is to be inserted into this list.
00330  * @param size (in) size of area identified by data pointer.
00331  */
00332 M_INLINE int DLISTUNR_push_back(DLISTUNR *list, void *data, size_t size)
00333 {
00334         DLISTUNR_position last = DLISTUNR_get_last( list );
00335         return DLISTUNR_insert_after(list, last, data, size);
00336                 
00337 }
00338 
00339 /**
00340  * @brief insert element as last in list (used to maintain queue)
00341  * @param list (in) the object
00342  * @param data (in) pointer to element that is to be inserted into this list.
00343  * @param size (in) size of area identified by data pointer.
00344  */
00345 M_INLINE int DLISTUNR_push_front(DLISTUNR *list, void *data, size_t size)
00346 {
00347         DLISTUNR_position last = DLISTUNR_get_first( list );
00348         return DLISTUNR_insert_before(list, last, data, size);
00349 }
00350 
00351 
00352 /**
00353  * @brief copy data of last element into user supplied buffer and remove the last element from list (used to maintain double ended queue)
00354  * @param list (in) the object
00355  * @param data (in) pointer to element that is to receive data of list entry
00356  * @param size (in) size of area identified by data pointer.
00357  * @return return 0 on success.
00358  */
00359 M_INLINE int DLISTUNR_pop_back(DLISTUNR *list, void *data, size_t size)
00360 {
00361         DLISTUNR_position pos;
00362 
00363         
00364         if (DLISTUNR_isempty(list)) {
00365                 return -1;
00366         }
00367         
00368         pos = DLISTUNR_get_last( list );
00369         
00370         if (DLISTUNR_copy_at(list, pos, data, size)) {
00371                 return -1;
00372         }
00373 
00374         if (DLISTUNR_unlink(list,pos)) {
00375                 return -1;
00376         }
00377         return 0;
00378 }
00379 
00380 /**
00381  * @brief copy data of first element into user supplied buffer and remove the first element from list (used to maintain double ended queue)
00382  * @param list (in) the object
00383  * @param data (in) pointer to element that is to receive data of list entry
00384  * @param size (in) size of area identified by data pointer.
00385  * @return return 0 on success.
00386  */
00387 M_INLINE int DLISTUNR_pop_front(DLISTUNR *list, void *data, size_t size)
00388 {
00389         DLISTUNR_position pos;
00390 
00391         
00392         if (DLISTUNR_isempty(list)) {
00393                 return -1;
00394         }
00395         
00396         pos = DLISTUNR_get_first( list );
00397 
00398         if (DLISTUNR_copy_at(list, pos, data, size)) {
00399                 return -1;
00400         }
00401         if (DLISTUNR_unlink(list,pos)) {
00402                 return -1;
00403         }
00404         return 0;
00405 }
00406 
00407 /**
00408  * @brief Macro for iterate over all elements of a list, the list is traversed in forward direction from first element to the last element.
00409  * @param loopvarname (type DLISTUNR_position) struct that identifies current element
00410  * @param list (type DLISTUNR *) pointer to the list that is traversed
00411  */
00412 #define DLISTUNR_FOREACH( loopvarname, list )\
00413   for((loopvarname) = DLISTUNR_get_first( list );\
00414       (loopvarname).entry != (DLISTUNR_entry *) &(list)->root;\
00415       (loopvarname) = DLISTUNR_next( loopvarname ) )
00416 
00417 /**
00418  * @brief Macro for iterate over all elements of a list, the list is traversed in reverse direction from last element to the first element.
00419  * @param loopvarname (type DLISTUNR_position) pointer to the current element
00420  * @param list (type DLISTUNR *) pointer to the list that is traversed
00421  */
00422 #define DLISTUNR_FOREACH_REVERSE( loopvarname, list )\
00423   for((loopvarname) = DLISTUNR_get_last( list );\
00424       (loopvarname).entry != (DLISTUNR_entry *) &(list)->root;\
00425       (loopvarname) = DLISTUNR_prev( loopvarname ) )
00426 
00427 /**
00428  * @brief Macro for iterate over all elements of a list, You may delete the current element; the list is traversed in forward direction from first element to the last element.
00429  * @param loopvarname (type DLISTUNR_position) pointer to the current element
00430  * @param loopvarnamenext (type DLISTUNR_position) do not modify! pointer to next element after current element (used for iteration).
00431  * @param list (type DLISTUNR *) pointer to the list that is traversed
00432  */
00433 #define DLISTUNR_FOREACH_SAVE( loopvarname, loopvarnext, list )\
00434   for((loopvarname) = DLISTUNR_get_first( list ), (loopvarnext) = DLISTUNR_next( loopvarname );\
00435       (loopvarname).entry != (DLISTUNR_entry *) &(list)->root;\
00436       (loopvarname) = (loopvarnext), (loopvarnext) = DLISTUNR_next(loopvarname) )
00437 
00438 /**
00439  * @brief Macro for iterate over all elements of a list, You may delete the current element; the list is traversed in reverse direction from last element to the first element.
00440  * @param loopvarname (type DLISTUNR_position) pointer to the current element
00441  * @param loopvarnamenext (type DLISTUNR_position) do not modify! pointer to next element after current element (used for iteration).
00442  * @param list (type DLISTUNR *) pointer to the list that is traversed
00443  */
00444 #define DLISTUNR_FOREACH_REVERSE_SAVE( loopvarname, loopvarnext, list )\
00445   for((loopvarname) = DLISTUNR_get_last(list);\
00446       (loopvarname).entry != (DLISTUNR_entry *) &(list)->root;\
00447       (loopvarname) = (loopvarnext), (loopvarnext) = DLISTUNR_prev(loopvarname) )
00448 
00449 
00450 /**
00451  * @brief list free all entries of the list. The list will then be an empty list.
00452  */
00453 M_INLINE void DLISTUNR_free( DLISTUNR *list, DLISTUNR_VISITOR_V free_func, void *context)
00454 {
00455         DRING *next,*cur;
00456         DLISTUNR_entry *curr;
00457         size_t pos,elmsize,i;
00458         
00459         elmsize = list->elmsize;
00460 
00461         DRING_FOREACH_SAVE( cur, next, &list->root.ring) {
00462         
00463                 curr = (DLISTUNR_entry *) cur;
00464                 if (free_func) {
00465                         for(pos = 0,i=0;i<curr->elmcount;i++) {
00466                                 free_func(list,  (void *) (curr->buffer +pos), context);
00467                                 pos += elmsize;
00468                         }
00469                 }
00470                 /*list->ctx->free( DRING_unlink(cur) );*/
00471                 free( cur );
00472                 
00473         }       
00474         DRING_init( &list->root.ring );
00475         list->entrycount = 0;
00476         list->elmcount = 0;
00477 }       
00478 
00479 #if 0
00480 M_INLINE void DLISTUNR_deleteif( DLISTUNR *list, DLISTUNR_VISITOR free_func, void *context)
00481 {
00482         DRING *next,*cur;
00483         DLISTUNR_entry *curr;
00484         size_t pos,elmsize,i;
00485         
00486         elmsize = list->elmsize;
00487 
00488         DRING_FOREACH_SAVE( cur, next, &list->root.ring) {
00489         
00490                 curr = (DLISTUNR_entry *) cur;
00491                 if (free_func) {
00492                         for(pos = 0,i=0;i<curr->elmcount;i++) {
00493                                 free_func(list,  (void *) curr->buffer[ pos ], context);
00494                                 pos += elmsize;
00495                         }
00496                 }
00497                 /*list->ctx->free( DRING_unlink(cur) );*/
00498                 list->ctx->free( cur );
00499                 
00500         }       
00501         DRING_init( &list->root.ring );
00502         list->entrycount = 0;
00503         list->elmcount = 0;
00504 }       
00505 #endif
00506 
00507 /*
00508  * @}
00509  */
00510 #ifdef  __cplusplus
00511 }
00512 #endif
00513 
00514 #endif