Simple data structures / objects in plain C Snapshot
|
00001 /* Copyright (c) Michael Moser (2011) . 3-clause BSD License applies */ 00002 00003 #ifndef _VBASE_SLIST_H_ 00004 #define _VBASE_SLIST_H_ 00005 00006 #ifdef __cplusplus 00007 extern "C" { 00008 #endif 00009 00010 #include <cutils/base.h> 00011 00012 00013 /** 00014 * @defgroup SLIST_entry 00015 * @brief an entry in single linked list, add to structure as member in order to make structure storable in hash table. 00016 * If the user wants to link his struct(ure) into a SLIST linked list, then he must embed a DLIST_entry into his structure. 00017 * Access to user defined structure is via embedded SLIST_entry. 00018 * @{ 00019 */ 00020 typedef struct tagSLIST_entry 00021 { 00022 struct tagSLIST_entry *next; 00023 } 00024 SLIST_entry; 00025 00026 /** 00027 * @} 00028 */ 00029 00030 00031 /** 00032 * @defgroup SLIST 00033 * @brief Single linked list data structure; where each list element can be of different length. 00034 * 00035 * This single linked list has a list header (SLIST). 00036 * The list header points to the first and last element in the list. 00037 * last elements next pointer is NULL. 00038 * 00039 * Usage: If the user wants to link his struct(ure) into a list, then he must embed a SLIST_entry into his structure. 00040 * Access to user defined structure is via embedded SLIST_entry. 00041 * 00042 * The list header contains a counter of elements (feature can be surpressed by defining #define SLIST_NO_ELMCOUNT 00043 * @{ 00044 */ 00045 typedef struct { 00046 #ifndef SLIST_NO_ELMCOUNT 00047 size_t elmcount; /** number of elements in list */ 00048 #endif 00049 SLIST_entry *prev, *next; /** root.prev - pointer to first element, root.next - pointer to last element */ 00050 } SLIST; 00051 00052 00053 00054 typedef void (*SLIST_VISITOR_V)(SLIST *list, SLIST_entry *entry, void *context); 00055 typedef int32_t (*SLIST_VISITOR) (SLIST *list, SLIST_entry *entry, void *context); 00056 typedef int32_t (*SLIST_COMPARE) (SLIST_entry *, SLIST_entry * ); 00057 00058 00059 /** 00060 * @brief initialises an empty list head 00061 * @param head list head 00062 */ 00063 M_INLINE void SLIST_init( SLIST *head ) 00064 { 00065 head->next = head->prev = 0; 00066 #ifndef SLIST_NO_ELMCOUNT 00067 head->elmcount = 0; 00068 #endif 00069 } 00070 00071 /** 00072 * @brief checks if argument list is empty 00073 * @param list pointer to list. 00074 * @returns not zero for non empty list. 00075 */ 00076 M_INLINE int SLIST_isempty( SLIST *head ) 00077 { 00078 return head->next == 0; 00079 } 00080 00081 00082 /** 00083 * @brief insert new entry after a given entry. 00084 * @param list pointer to list head 00085 * @param pos current posision (newentry inserted after this one). 00086 * @param newentry pointer to new list entry (to be inserted). 00087 */ 00088 M_INLINE void SLIST_insert_after( SLIST *list, SLIST_entry *pos, SLIST_entry *newentry) 00089 { 00090 if (list->next) { 00091 00092 if (pos){ 00093 00094 newentry->next = pos->next; 00095 pos->next = newentry; 00096 00097 if (!newentry->next) { 00098 list->next = newentry; 00099 } 00100 00101 } else { 00102 newentry->next = list->prev; 00103 list->prev = newentry; 00104 } 00105 00106 00107 } else { 00108 00109 list->next = list->prev = newentry; 00110 newentry->next = 0; 00111 00112 } 00113 00114 00115 #ifndef SLIST_NO_ELMCOUNT 00116 list->elmcount ++; 00117 #endif 00118 } 00119 00120 00121 /** 00122 * @brief delete an element from a list. 00123 * @param list deletes this list element 00124 */ 00125 M_INLINE SLIST_entry *SLIST_unlink_after( SLIST *list, SLIST_entry *link ) 00126 { 00127 SLIST_entry *ret; 00128 00129 if (!link) { 00130 ret = list->prev; 00131 list->prev = ret->next; 00132 if (!list->prev) { 00133 list->next = 0; 00134 } 00135 00136 } else { 00137 ret = link->next; 00138 if (!ret) { 00139 return 0; 00140 } 00141 00142 link->next = ret ? ret->next : 0; 00143 00144 if (link->next == 0) { 00145 list->next = link; 00146 } 00147 00148 } 00149 #ifndef SLIST_NO_ELMCOUNT 00150 list->elmcount --; 00151 #endif 00152 00153 return ret; 00154 } 00155 00156 00157 /** 00158 * @brief insert element as last in list. 00159 * @param list list head. 00160 * @param newentry entry to be inserted into list 00161 */ 00162 M_INLINE void SLIST_push_back( SLIST *list, SLIST_entry *newentry) 00163 { 00164 SLIST_insert_after( list, list->next, newentry ); 00165 } 00166 00167 /** 00168 * @brief insert element as first in list (used to maintain queue) 00169 * @param list list head 00170 * @param newentry entry to be inserted into list 00171 */ 00172 M_INLINE void SLIST_push_front( SLIST *list, SLIST_entry *newentry) 00173 { 00174 SLIST_insert_after( list, 0, newentry ); 00175 } 00176 00177 /** 00178 * @brief append contents of one list onto the other 00179 * @param dest 00180 * @param src content of this list is appended onto dest list. postcondition: src list is empty 00181 */ 00182 00183 M_INLINE void SLIST_append( SLIST *dest, SLIST *src) 00184 { 00185 if (SLIST_isempty(dest)) { 00186 00187 if (!SLIST_isempty(src)) { 00188 00189 dest->prev = src->prev; 00190 dest->next = src->next; 00191 #ifndef SLIST_NO_ELMCOUNT 00192 dest->elmcount = src->elmcount; 00193 #endif 00194 00195 //SLIST_init(src); 00196 } 00197 00198 } else { 00199 00200 if (!SLIST_isempty(src)) { 00201 dest->next->next = src->prev; 00202 dest->next = src->next; 00203 #ifndef SLIST_NO_ELMCOUNT 00204 dest->elmcount += src->elmcount; 00205 #endif 00206 //SLIST_init(src); 00207 00208 } 00209 } 00210 00211 00212 } 00213 00214 00215 /** 00216 * @brief remove the first element from list (used to maintain queue) 00217 * @param list (in) the object 00218 * @return the first element of list, NULL if list empty 00219 */ 00220 M_INLINE SLIST_entry * SLIST_pop_front( SLIST *list ) 00221 { 00222 return SLIST_unlink_after(list, 0); 00223 } 00224 00225 00226 M_INLINE SLIST_entry *SLIST_get_first(SLIST *list) 00227 { 00228 return list->prev; 00229 } 00230 00231 M_INLINE SLIST_entry *SLIST_get_last(SLIST *list) 00232 { 00233 return list->next; 00234 } 00235 00236 00237 M_INLINE SLIST_entry *SLIST_get_next( SLIST_entry *cur) 00238 { 00239 return cur->next; 00240 } 00241 00242 00243 00244 00245 /** 00246 * @brief Macro for iterate over all elements of a list, the list is traversed in forward direction from first element to the last element. 00247 * @param loopvarname (type SLIST_entry *) pointer to the current element 00248 * @param list (type SLIST *) pointer to the list that is traversed 00249 */ 00250 #define SLIST_FOREACH( loopvarname, list )\ 00251 for((loopvarname) = (list)->prev;\ 00252 (loopvarname) != 0;\ 00253 (loopvarname) = (loopvarname)->next ) 00254 00255 /** 00256 * @brief Macro for iterate over all elements of a list, the list is traversed in forward direction from first element to the last element. 00257 * @param loopvsarname (type SLIST_entry *) pointer to the current element 00258 * @param list (type SLIST *) pointer to the list that is traversed 00259 */ 00260 #define SLIST_FOREACH_SAVE( loopvarname, loopvarnamenext, list )\ 00261 for((loopvarname) = (list)->prev, (loopvarnamenext) = (loopvarname) ? (loopvarname)->next : 0;\ 00262 (loopvarname) != 0;\ 00263 (loopvarname) = (loopvarnamenext), (loopvarnamenext) = (loopvarname) ? (loopvarname)->next : 0 ) 00264 00265 00266 /** 00267 * @brief: return number of elements in list 00268 * if we don't have element count in list (SLIST_NO_ELMCOUNT defined), then the whole list structure is traversed. 00269 */ 00270 M_INLINE size_t SLIST_size( SLIST *list ) 00271 { 00272 #ifndef SLIST_NO_ELMCOUNT 00273 return list->elmcount; 00274 #else 00275 size_t sz; 00276 SLIST_entry * cur; 00277 00278 SLIST_FOREACH( cur, list ) { 00279 sz += 1; 00280 } 00281 return sz; 00282 #endif 00283 } 00284 00285 /* 00286 * @brief get the nth element of a list as counted from the beginning of the list. 00287 * @brief list (IN) the object 00288 * @brief nth (IN) index of element to retrieve (null based). 00289 */ 00290 M_INLINE SLIST_entry *SLIST_get_nth( SLIST *list, size_t nth) 00291 { 00292 00293 SLIST_entry *elm; 00294 00295 #ifndef SLIST_NO_ELMCOUNT 00296 if (nth >= list->elmcount) { 00297 return 0; 00298 } 00299 00300 for(elm = SLIST_get_first(list); nth > 0; nth -= 1, elm = SLIST_get_next(elm)); 00301 #else 00302 for(elm = SLIST_get_first(list); elm != 0 && nth > 0; nth -= 1, elm = SLIST_get_next(elm)); 00303 #endif 00304 00305 return elm; 00306 } 00307 00308 /** 00309 * @brief get the nth element of a list as counted from the end of the list. 00310 * @brief list (IN) the object 00311 * @brief nth (IN) index of element to retrieve (null based). 00312 */ 00313 M_INLINE SLIST_entry *SLIST_get_nth_reverse( SLIST *list, size_t nth) 00314 { 00315 return SLIST_get_nth( list, SLIST_size( list ) - nth ); 00316 } 00317 00318 00319 /** 00320 * @brief iterate over all elements of a list, callback is invoked for either element of the list. 00321 * 00322 * @param lst (in) the object. 00323 * @param eval (in) callback that is called to visit each set (or cleared) bit. 00324 * @param context (in) pointer that is passed as context on each invocation of callback. 00325 */ 00326 M_INLINE void SLIST_foreach( SLIST *lst, SLIST_VISITOR_V eval, void *context) 00327 { 00328 SLIST_entry *cur; 00329 00330 if (!eval) { 00331 return; 00332 } 00333 00334 SLIST_FOREACH( cur, lst) { 00335 eval( lst, cur, context); 00336 } 00337 00338 } 00339 00340 /** 00341 * @brief find an element within the linked list. callback is invoked for each element of the list, in forward direction from first element to last element; when the callback returns non zero value the iteration stops as we have found what we searched for. 00342 * 00343 * @param lst (in) the object. 00344 * @param eval (in) callback that is called to visit each set (or cleared) bit. 00345 * @param context (in) pointer that is passed as context on each invocation of callback. 00346 * @param retval (out) optional - the first non zero value returned by eval callback, if NULL then ignored. 00347 * @return the list element that has matched (i.e. element that has been found). 00348 */ 00349 M_INLINE SLIST_entry *SLIST_findif( SLIST *lst, SLIST_VISITOR eval, void *context, int32_t *retval) 00350 { 00351 int ret; 00352 SLIST_entry *cur; 00353 00354 if (retval) { 00355 *retval = 0; 00356 } 00357 00358 if (!eval) { 00359 return 0; 00360 } 00361 00362 SLIST_FOREACH( cur, lst ) { 00363 ret = eval( lst, cur, context); 00364 if (ret) { 00365 if (retval) { 00366 *retval = ret; 00367 } 00368 00369 return cur; 00370 } 00371 00372 } 00373 00374 return 0; 00375 } 00376 00377 00378 /** 00379 * @brief insert new element into sorted list; Maintains ordering relationship between elements of linked list (sort by ascending order) 00380 * A sorting algorithm based on this function is not very efficient; it is of complexity O(n^2); nevertheless usefull if a list is modified and has to be always maintained in sorted order. 00381 * @param list (in) the object 00382 * @param compare (in) comparison function. 00383 * @param newentry (in) element that is to be inserted into list. 00384 */ 00385 M_INLINE void SLIST_insert_sorted( SLIST *list, SLIST_COMPARE compare, SLIST_entry *newentry) 00386 { 00387 SLIST_entry *cur,*prev; 00388 00389 prev = 0; 00390 SLIST_FOREACH( cur, list ) { 00391 if (compare(cur,newentry) > 0) { 00392 00393 SLIST_insert_after(list, prev,newentry); 00394 return; 00395 } 00396 prev = cur; 00397 } 00398 00399 SLIST_push_back( list, newentry ); 00400 } 00401 00402 /** 00403 * @brief iterate over all entries of the list and delete entries that match predicate from the list, and frees the memory (optionally) 00404 * @param list (in) the object. 00405 * @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. 00406 * @param context (in) data pointer passed to every invocation of check_if 00407 * @param free_ctx (in) interface used to free data of entry, is argument pointer is NULL then nothing is freed. 00408 * @param offset_of_link (in) offset of DLIST_entry in embedded structure. 00409 */ 00410 M_INLINE void SLIST_deleteif( SLIST *list, SLIST_VISITOR check_if, void *context, int offset_of_link) 00411 { 00412 SLIST_entry *cur,*prev,*del; 00413 00414 prev = 0; 00415 00416 for(cur = list->prev; cur;) { 00417 00418 if (!check_if || check_if( list, cur, context)) { 00419 00420 cur = cur->next; 00421 del = SLIST_unlink_after( list, prev ); 00422 if (offset_of_link != -1) { 00423 free( _MEMBEROF(del, offset_of_link) ); 00424 } 00425 00426 00427 } else { 00428 00429 prev = cur; 00430 cur = cur->next; 00431 } 00432 } 00433 } 00434 00435 /** 00436 * @brief iterate over all entries of the list and delete them. 00437 * @param list (in) the object 00438 00439 * @param on_delete(in) if not NULL then this callback is called prior to deleting each list element. 00440 * @param context (in) if on_delete is not NULL then this pointer is passed as argument to on_delete. 00441 00442 * @param free_ctx (in) allocation interface used to free data of entry. 00443 * @param offset_of_link (in) offset of SRING in embedded structure. 00444 */ 00445 M_INLINE void SLIST_deleteall( SLIST *list, SLIST_VISITOR_V on_delete, void *context, int offset_of_link) 00446 { 00447 SLIST_entry *cur,*del; 00448 00449 00450 for(cur = list->prev; cur;) { 00451 00452 if (on_delete) { 00453 on_delete( list, cur, context ); 00454 } 00455 00456 cur = cur->next; 00457 del = SLIST_unlink_after( list, 0 ); 00458 if (offset_of_link != -1) { 00459 free( _MEMBEROF(del, offset_of_link) ); 00460 } 00461 } 00462 } 00463 00464 00465 /** 00466 * @brief Reverse a list 00467 * This function turns the first element into the last element, the second element 00468 * into the one before the last, and so on and on. 00469 * @param header (in) the object 00470 */ 00471 M_INLINE void SLIST_reverse( SLIST *lst ) 00472 { 00473 SLIST_entry *cur = lst->prev, *next; 00474 SLIST_entry *tmp; 00475 if (cur) { 00476 next = cur->next; 00477 cur->next = 0; 00478 00479 while(next) { 00480 tmp = next->next; 00481 00482 next->next = cur; 00483 cur = next; 00484 next = tmp; 00485 } 00486 00487 tmp = lst->prev; 00488 lst->prev = lst->next; 00489 lst->next = tmp; 00490 } 00491 } 00492 00493 /** 00494 * @brief check consistency of list 00495 * This function checks for loops in the list, and if count of elements in list is the same as counter of elements in list header. 00496 * @param header (in) the object 00497 * @return zero if list contains errors. 00498 */ 00499 M_INLINE int SLIST_check(SLIST *header) 00500 { 00501 SLIST_entry *cur,*prev = 0,*fast= 0; 00502 #ifndef SLIST_NO_ELMCOUNT 00503 size_t count = 0; 00504 #endif 00505 00506 if (!header->prev || !header->next) { 00507 if (header->prev || header->next) { 00508 return 0; 00509 } 00510 return 1; 00511 } 00512 00513 fast = header->prev; 00514 SLIST_FOREACH( cur, header ) { 00515 00516 #ifndef SLIST_NO_ELMCOUNT 00517 count += 1; 00518 #endif 00519 prev = fast; 00520 fast = fast->next; 00521 if (!fast) { 00522 break; 00523 } 00524 if (fast == cur) { 00525 return 0; 00526 } 00527 00528 #ifndef SLIST_NO_ELMCOUNT 00529 count += 1; 00530 #endif 00531 prev = fast; 00532 fast = fast->next; 00533 if (!fast) { 00534 break; 00535 } 00536 if (fast == cur) { 00537 return 0; 00538 } 00539 } 00540 00541 if (header->next != prev) { 00542 return 0; 00543 } 00544 00545 00546 #ifndef SLIST_NO_ELMCOUNT 00547 if (header->elmcount != count) { 00548 return 0; 00549 } 00550 #endif 00551 return 1; 00552 } 00553 00554 /** 00555 * @} 00556 */ 00557 00558 #ifdef __cplusplus 00559 } 00560 #endif 00561 00562 #endif