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/double.h" 00027 00028 bool drl_check_list_(const struct drl_list *const list) 00029 { 00030 /* is the list a valid object? */ 00031 assert(list); 00032 /* if either head or tail is NULL, the other one has to be NULL, too */ 00033 assert((list->head && list->tail) || (!list->head && !list->tail)); 00034 00035 /* if node_count is 0, then the head and tail pointers must be NULL */ 00036 assert(list->node_count != 0 || (!list->head && !list->tail)); 00037 /* if head and tail are NULL, node_count must be 0 */ 00038 assert((list->head && list->tail) || list->node_count == 0); 00039 00040 /* if node_count is > 0, then the head and tail pointers must not be NULL */ 00041 assert(list->node_count == 0 || (list->head && list->tail)); 00042 /* if head and tail are not NULL, then node_count must be > 0 */ 00043 assert((!list->head && !list->tail) || list->node_count > 0); 00044 00045 /* if there is a head element, its prev pointer must be NULL */ 00046 assert(!list->head || !list->head->prev); 00047 /* if there is a tail element, its next pointer must be NULL */ 00048 assert(!list->tail || !list->tail->next); 00049 00050 /* if node_count is 1, then head and tail must point to the same element and their next and prev pointers must match up */ 00051 assert(list->node_count != 1 || (list->head == list->tail && !list->head->next && !list->tail->prev)); 00052 /* only if there is exactly one node in the list, node_count must be 1 */ 00053 assert(!list->head || !list->tail || list->head != list->tail || list->head->next || list->tail->prev || list->node_count == 1); 00054 00055 /* if node_count is > 1, then head->next and tail->prev must not be NULL */ 00056 assert(list->node_count <= 1 || (list->head->next && list->tail->prev)); 00057 /* if head->next and tail->prev are not NULL, then node_count must be > 1 */ 00058 assert(!list->head || !list->tail || (!list->head->next && !list->tail->prev) || list->node_count > 1); 00059 00060 /* if node_count is 2, then head->next must be tail and tail->prev must be head */ 00061 assert(list->node_count != 2 || (list->head->next == list->tail && list->tail->prev == list->head)); 00062 /* if head->next is tail and tail->prev is head, then node_count must be 2 */ 00063 assert(!list->head || !list->tail || !list->head->next || !list->tail->prev || list->head->next != list->tail || list->tail->prev != list->head || list->node_count == 2); 00064 00065 /* if node_count is 3, then head->next must be equal to tail->prev */ 00066 assert(list->node_count != 3 || (list->head->next == list->tail->prev)); 00067 /* if head->next is equal to tail->prev, then node_count must be 3 */ 00068 assert(!list->head || !list->tail || !list->head->next || !list->tail->prev || list->head->next != list->tail->prev || list->node_count == 3); 00069 00070 /* if node_count is > 3, then head->next must not be equal to tail->prev */ 00071 assert(list->node_count <= 3 || (list->head->next != list->tail->prev)); 00072 /* if head->next is not equal to tail->prev, then node_count must be > 3 */ 00073 assert(!list->head || !list->tail || !list->head->next || !list->tail->prev || list->head->next == list->tail || list->tail->prev == list->head || list->head->next == list->tail->prev || list->node_count > 3); 00074 00075 return list != NULL; 00076 } 00077 00078 bool drl_check_iter_in_list_(const struct drl_iterator *const iter) 00079 { 00080 /* is the iterator a valid object? */ 00081 assert(iter); 00082 /* is the iterator's list consistent? */ 00083 drl_check_list_(iter->list); 00084 /* is the iterator in the correct state? */ 00085 assert(iter->state == RL_ISTATE_IN_LIST_); 00086 /* is the current node a valid object? */ 00087 assert(iter->node); 00088 /* is the list non-empty so that this iterator can, in fact, be 'in the list'? */ 00089 assert(iter->list->node_count > 0); 00090 00091 return iter != NULL; 00092 } 00093 00094 bool drl_check_iter_post_delete_(const struct drl_iterator *const iter) 00095 { 00096 /* is the iterator a valid object? */ 00097 assert(iter != NULL); 00098 /* is the iterator's list consistent? */ 00099 drl_check_list_(iter->list); 00100 /* is the iterator in the correct state? */ 00101 assert(iter->state == RL_ISTATE_POST_DELETE_); 00102 00103 return iter != NULL; 00104 } 00105 00106 bool drl_check_iter_end_of_list_(const struct drl_iterator *const iter) 00107 { 00108 /* is the iterator a valid object? */ 00109 assert(iter != NULL); 00110 /* is the iterator's list consistent? */ 00111 drl_check_list_(iter->list); 00112 /* is the iterator in the correct state? */ 00113 assert(iter->state == RL_ISTATE_END_OF_LIST_); 00114 /* is the current node NULL to indicate EOL? */ 00115 assert(iter->node == NULL); 00116 00117 return iter != NULL; 00118 } 00119 00120 bool drl_check_iter_in_list_or_end_of_list_(const struct drl_iterator *const iter) 00121 { 00122 assert(iter); 00123 assert((iter->state == RL_ISTATE_IN_LIST_ && drl_check_iter_in_list_(iter)) || 00124 (iter->state == RL_ISTATE_END_OF_LIST_ && drl_check_iter_end_of_list_(iter))); 00125 00126 return iter != NULL; 00127 } 00128 00129 bool drl_insert_before(struct drl_iterator *const iter, 00130 void *const payload) 00131 { 00132 assert(drl_check_iter_in_list_or_end_of_list_(iter)); 00133 00134 struct drl_node_ *const new_node = malloc(sizeof(*new_node)); 00135 if (new_node) { 00136 struct drl_node_ *const prev = iter->node ? iter->node->prev : iter->list->tail; 00137 struct drl_node_ *const next = iter->node; 00138 00139 *new_node = (struct drl_node_) { payload, next, prev }; 00140 00141 if (prev) { 00142 prev->next = new_node; 00143 } 00144 if (next) { 00145 next->prev = new_node; 00146 } 00147 00148 if (iter->list->head == iter->node) { 00149 iter->list->head = new_node; 00150 } 00151 if (iter->node == NULL) { 00152 iter->list->tail = new_node; 00153 } 00154 iter->list->node_count += 1; 00155 00156 assert(drl_check_iter_in_list_or_end_of_list_(iter)); 00157 00158 return true; 00159 } 00160 00161 return false; 00162 } 00163 00164 void *drl_del(struct drl_iterator *const iter) 00165 { 00166 void *ret = NULL; 00167 assert(drl_check_iter_in_list_(iter)); 00168 00169 struct drl_node_ *const victim = iter->node; 00170 assert(victim); 00171 00172 /* the following pointers may refer to the victim node: 00173 * 1) list->head 00174 * 2) list->tail 00175 * 3) victim->prev->next 00176 * 4) victim->next->prev 00177 * 5) iter->node */ 00178 00179 /* 1 of 5 */ 00180 if (iter->list->head == victim) { 00181 iter->list->head = victim->next; 00182 } 00183 /* 2 of 5 */ 00184 if (iter->list->tail == victim) { 00185 iter->list->tail = victim->prev; 00186 } 00187 /* 3 of 5 */ 00188 if (victim->prev) { 00189 victim->prev->next = victim->next; 00190 } 00191 /* 4 of 5 */ 00192 if (victim->next) { 00193 victim->next->prev = victim->prev; 00194 } 00195 /* 5 of 5 */ 00196 /* Update the iterator's node pointer and set its state so that drl_next() or drl_prev() fixes it up */ 00197 iter->node = victim->next; 00198 iter->state = RL_ISTATE_POST_DELETE_; 00199 00200 iter->list->node_count -= 1; 00201 00202 /* free payload and node memory */ 00203 if (iter->list->free_fn) { 00204 iter->list->free_fn(victim->payload); 00205 } else { 00206 ret = victim->payload; 00207 } 00208 free(victim); 00209 00210 assert(drl_check_iter_post_delete_(iter)); 00211 00212 return ret; 00213 } 00214 00215 void drl_del_all(struct drl_list *const list) 00216 { 00217 struct drl_iterator i; 00218 00219 assert(drl_check_list_(list)); 00220 00221 while (!drl_is_eol(drl_first(list, &i))) { 00222 drl_del(&i); 00223 } 00224 00225 assert(drl_check_list_(list)); 00226 } 00227 00237 static int rl_map_return_first_match_(__attribute__ ((unused)) struct drl_iterator *const iter, 00238 __attribute__ ((unused)) void *const context) 00239 { 00240 return 1; 00241 } 00242 00243 struct drl_iterator *drl_find(struct drl_iterator *const iter, 00244 rl_match_fn match_fn, 00245 void *const match_context) 00246 { 00247 assert(drl_check_iter_in_list_or_end_of_list_(iter)); 00248 assert(match_fn); 00249 00250 drl_map(iter, rl_map_return_first_match_, NULL, match_fn, match_context); 00251 00252 assert(drl_check_iter_in_list_or_end_of_list_(iter)); 00253 00254 return iter; 00255 } 00256 00265 static bool rl_match_payload_(void *const payload, 00266 void *const context) 00267 { 00268 return payload == context; 00269 } 00270 00271 struct drl_iterator *drl_find_payload(struct drl_iterator *const iter, 00272 void *const payload) 00273 { 00274 return drl_find(iter, rl_match_payload_, payload); 00275 } 00276 00277 int drl_map(struct drl_iterator *const iter, 00278 drl_map_fn map_fn, 00279 void *const map_context, 00280 rl_match_fn match_fn, 00281 void *const match_context) 00282 { 00283 int ret = 0; 00284 00285 assert(drl_check_iter_in_list_or_end_of_list_(iter)); 00286 assert(map_fn); 00287 00288 for (; !drl_is_eol(iter); drl_next(iter)) { 00289 if (!match_fn || match_fn(drl_payload(iter), match_context)) { 00290 ret = map_fn(iter, map_context); 00291 if (ret != 0) { 00292 break; 00293 } 00294 } 00295 } 00296 00297 assert(drl_check_iter_in_list_or_end_of_list_(iter)); 00298 00299 return ret; 00300 }