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