RList
src/double.c
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 }