RList
|
00001 /* 00002 * Copyright (c) 2011, Stefan Götz <stefan.goetz@web.de> 00003 * 00004 * Permission to use, copy, modify, and/or distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 00009 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00010 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 00011 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00012 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 00013 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00014 * PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00023 #include <stdlib.h> 00024 #include <assert.h> 00025 00026 #include "rlist/common.h" 00027 #include "rlist/single.h" 00028 00037 /* This check is fairly unintuitive. 00038 * This is a classic memory/computation trade-off: either store the state explicitely in an iterator or derive it from the node/prev/list state indirectly as done here. 00039 * We go for computation so as not to bloat iterator objects. */ 00040 static inline enum rl_iterator_state_ srl_get_state_(const struct srl_iterator *const iter) 00041 { 00042 assert(iter); 00043 assert(iter->list); 00044 00045 if (iter->node) { 00046 if (iter->node != iter->prev) { 00047 return RL_ISTATE_IN_LIST_; 00048 } else { 00049 return RL_ISTATE_POST_DELETE_; 00050 } 00051 } else { 00052 if (iter->prev || !iter->list->head) { 00053 return RL_ISTATE_END_OF_LIST_; 00054 } else { 00055 return RL_ISTATE_POST_DELETE_; 00056 } 00057 } 00058 } 00059 00060 bool srl_check_list_(const struct srl_list *const list) 00061 { 00062 assert(list); 00063 assert(list->node_count != 0 || !list->head); 00064 assert(list->node_count == 0 || list->head); 00065 assert(list->node_count != 1 || (list->head && !list->head->next)); 00066 assert(list->node_count == 1 || !(list->head && !list->head->next)); 00067 assert(list->node_count <= 1 || (list->head && list->head->next)); 00068 assert(list->node_count > 1 || !(list->head && list->head->next)); 00069 00070 return list != NULL; 00071 } 00072 00073 bool srl_check_iter_in_list_(const struct srl_iterator *const iter) 00074 { 00075 /* is the iterator a valid object? */ 00076 assert(iter != NULL); 00077 /* is the iterator's list consistent? */ 00078 srl_check_list_(iter->list); 00079 /* is the current node a valid object? */ 00080 assert(iter->node != NULL); 00081 /* the current and the previous node must not be the same */ 00082 assert(iter->node != iter->prev); 00083 00084 /* if prev is NULL, then node must be the first node in the list */ 00085 assert(iter->prev != NULL || iter->node == iter->list->head); 00086 /* if node is the first node in the list, then prev must be NULL */ 00087 assert(iter->node != iter->list->head || iter->prev == NULL); 00088 00089 /* if prev is not NULL, then node must not be the first node in the list */ 00090 assert(iter->prev == NULL || iter->node != iter->list->head); 00091 /* if node is not the first node in the list, then prev must not be NULL */ 00092 assert(iter->node == iter->list->head || iter->prev != NULL); 00093 00094 /* if prev is not NULL, then prev->next must be equal to node */ 00095 assert(iter->prev == NULL || iter->prev->next == iter->node); 00096 00097 return iter != NULL; 00098 } 00099 00100 bool srl_check_iter_post_delete_(const struct srl_iterator *const iter) 00101 { 00102 /* is the iterator a valid object? */ 00103 assert(iter != NULL); 00104 /* is the iterator's list consistent? */ 00105 srl_check_list_(iter->list); 00106 /* is node == prev to indicate post-delete? */ 00107 assert(iter->node == iter->prev); 00108 00109 return iter != NULL; 00110 } 00111 00112 bool srl_check_iter_end_of_list_(const struct srl_iterator *const iter) 00113 { 00114 /* is the iterator a valid object? */ 00115 assert(iter != NULL); 00116 /* is the iterator's list consistent? */ 00117 srl_check_list_(iter->list); 00118 /* is the current node NULL to indicate EOL? */ 00119 assert(iter->node == NULL); 00120 00121 /* if prev is NULL, then the list must be empty */ 00122 assert(iter->prev != NULL || iter->list->head == NULL); 00123 /* if the list is empty, then prev must be NULL */ 00124 assert(iter->list->head != NULL || iter->prev == NULL); 00125 00126 /* if prev is not NULL, then it must be the last node in the list */ 00127 assert(iter->prev == NULL || iter->prev->next == NULL); 00128 00129 return iter != NULL; 00130 } 00131 00132 bool srl_check_iter_in_list_or_end_of_list_(const struct srl_iterator *const iter) 00133 { 00134 assert((srl_get_state_(iter) == RL_ISTATE_IN_LIST_ && srl_check_iter_in_list_(iter)) || 00135 (srl_get_state_(iter) == RL_ISTATE_END_OF_LIST_ && srl_check_iter_end_of_list_(iter))); 00136 00137 return iter != NULL; 00138 } 00139 00140 struct srl_iterator *srl_next(struct srl_iterator *const iter) 00141 { 00142 const enum rl_iterator_state_ state = srl_get_state_(iter); 00143 00144 switch (state) { 00145 case RL_ISTATE_IN_LIST_: 00146 assert(srl_check_iter_in_list_(iter)); 00147 /* advance iterator normally */ 00148 iter->prev = iter->node; 00149 iter->node = iter->prev->next; 00150 break; 00151 case RL_ISTATE_POST_DELETE_: 00152 assert(srl_check_iter_post_delete_(iter)); 00153 /* this branch implies iter->node == iter->prev */ 00154 if (iter->prev) { 00155 /* with a good prev pointer, take its next pointer */ 00156 iter->node = iter->prev->next; 00157 } else { 00158 /* with node and prev both NULL, take the first list node */ 00159 /* srl_get_state_() should make sure that if the list was empty, the 00160 * iterator state is reported as EOL instead of PD */ 00161 assert(iter->list->head); 00162 /* prev shall remain NULL because node is the first list node and 00163 * thus has no predecessor */ 00164 iter->node = iter->list->head; 00165 } 00166 break; 00167 case RL_ISTATE_END_OF_LIST_: 00168 break; 00169 } 00170 00171 if (srl_is_eol(iter)) { 00172 assert(srl_check_iter_end_of_list_(iter)); 00173 } else { 00174 assert(srl_check_iter_in_list_(iter)); 00175 } 00176 00177 return iter; 00178 } 00179 00180 bool srl_insert_before(struct srl_iterator *const iter, 00181 void *const payload) 00182 { 00183 assert(srl_check_iter_in_list_or_end_of_list_(iter)); 00184 00185 struct srl_node_ *const new_node = malloc(sizeof(*new_node)); 00186 if (new_node) { 00187 *new_node = (struct srl_node_) { payload, iter->node }; 00188 /* pointers that need to be updated: 00189 * list head, next pointer of previous node, prev pointer of iterator */ 00190 if (iter->list->head == iter->node) { 00191 iter->list->head = new_node; 00192 } 00193 if (iter->prev) { 00194 iter->prev->next = new_node; 00195 } 00196 iter->prev = new_node; 00197 iter->list->node_count += 1; 00198 00199 assert(srl_check_iter_in_list_or_end_of_list_(iter)); 00200 00201 return true; 00202 } 00203 00204 return false; 00205 } 00206 00207 void *srl_del(struct srl_iterator *const iter) 00208 { 00209 void *ret = NULL; 00210 struct srl_node_ *next; 00211 00212 assert(srl_check_iter_in_list_(iter)); 00213 00214 /* free or return the payload data */ 00215 if (iter->list->free_fn) { 00216 iter->list->free_fn(iter->node->payload); 00217 } else { 00218 ret = iter->node->payload; 00219 } 00220 00221 /* there are three pointers in our datastructures that may refer to 00222 * iter->node: 1) the list head pointer, 2) the previous node's next 00223 * pointer, and 3) the iterator's node pointer. 00224 * All three need to be set to a new value because iter->node is going to be 00225 * de-allocated. */ 00226 next = iter->node->next; 00227 00228 /* 1 of 3 */ 00229 if (iter->list->head == iter->node) { 00230 iter->list->head = next; 00231 } 00232 /* 2 of 3 */ 00233 if (iter->prev) { 00234 iter->prev->next = next; 00235 } 00236 free(iter->node); 00237 /* 3 of 3 */ 00238 /* Set the iterator state to post-delete and let srl_next() fix it up */ 00239 iter->node = iter->prev; 00240 00241 iter->list->node_count -= 1; 00242 00243 if (iter->list->head) { 00244 assert(srl_check_iter_post_delete_(iter)); 00245 } else { 00246 assert(srl_check_iter_end_of_list_(iter)); 00247 } 00248 00249 return ret; 00250 } 00251 00252 void srl_del_all(struct srl_list *const list) 00253 { 00254 struct srl_iterator i; 00255 00256 assert(srl_check_list_(list)); 00257 00258 while (!srl_is_eol(srl_first(list, &i))) { 00259 srl_del(&i); 00260 } 00261 00262 assert(srl_check_list_(list)); 00263 } 00264 00274 static int rl_map_return_first_match_(__attribute__ ((unused)) struct srl_iterator *const iter, 00275 __attribute__ ((unused)) void *const context) 00276 { 00277 return 1; 00278 } 00279 00280 struct srl_iterator *srl_find(struct srl_iterator *const iter, 00281 rl_match_fn match_fn, 00282 void *const match_context) 00283 { 00284 assert(srl_check_iter_in_list_or_end_of_list_(iter)); 00285 assert(match_fn); 00286 00287 srl_map(iter, rl_map_return_first_match_, NULL, match_fn, match_context); 00288 00289 assert(srl_check_iter_in_list_or_end_of_list_(iter)); 00290 00291 return iter; 00292 } 00293 00302 static bool rl_match_payload_(void *const payload, 00303 void *const context) 00304 { 00305 return payload == context; 00306 } 00307 00308 struct srl_iterator *srl_find_payload(struct srl_iterator *const iter, 00309 void *const payload) 00310 { 00311 return srl_find(iter, rl_match_payload_, payload); 00312 } 00313 00314 int srl_map(struct srl_iterator *const iter, 00315 srl_map_fn map_fn, 00316 void *const map_context, 00317 rl_match_fn match_fn, 00318 void *const match_context) 00319 { 00320 int ret = 0; 00321 00322 assert(srl_check_iter_in_list_or_end_of_list_(iter)); 00323 assert(map_fn); 00324 00325 for (; !srl_is_eol(iter); srl_next(iter)) { 00326 if (!match_fn || match_fn(srl_payload(iter), match_context)) { 00327 ret = map_fn(iter, map_context); 00328 if (ret != 0) { 00329 break; 00330 } 00331 } 00332 } 00333 00334 assert(srl_check_iter_in_list_or_end_of_list_(iter)); 00335 00336 return ret; 00337 }