LCOV - code coverage report
Current view: top level - aws-c-common/include/aws/common - linked_list.inl (source / functions) Hit Total Coverage
Test: all_fuzz.info Lines: 184 292 63.0 %
Date: 2021-04-23 16:28:21 Functions: 47 546 8.6 %

          Line data    Source code
       1             : #ifndef AWS_COMMON_LINKED_LIST_INL
       2             : #define AWS_COMMON_LINKED_LIST_INL
       3             : 
       4             : /**
       5             :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       6             :  * SPDX-License-Identifier: Apache-2.0.
       7             :  */
       8             : 
       9             : #include <aws/common/common.h>
      10             : #include <aws/common/linked_list.h>
      11             : #include <stddef.h>
      12             : 
      13             : AWS_EXTERN_C_BEGIN
      14             : 
      15             : /**
      16             :  * Set node's next and prev pointers to NULL.
      17             :  */
      18      164472 : AWS_STATIC_IMPL void aws_linked_list_node_reset(struct aws_linked_list_node *node) {
      19      164472 :     AWS_PRECONDITION(node != NULL);
      20      164472 :     AWS_ZERO_STRUCT(*node);
      21      164472 :     AWS_POSTCONDITION(AWS_IS_ZEROED(*node));
      22      164472 : }
      23             : 
      24             : /**
      25             :  * These functions need to be defined first as they are used in pre
      26             :  * and post conditions.
      27             :  */
      28             : 
      29             : /**
      30             :  * Tests if the list is empty.
      31             :  */
      32      110580 : AWS_STATIC_IMPL bool aws_linked_list_empty(const struct aws_linked_list *list) {
      33      110580 :     AWS_PRECONDITION(list);
      34      110580 :     return list->head.next == &list->tail;
      35      110580 : }
      36             : 
      37             : /**
      38             :  * Checks that a linked list is valid.
      39             :  */
      40       50000 : AWS_STATIC_IMPL bool aws_linked_list_is_valid(const struct aws_linked_list *list) {
      41       50000 :     if (list && list->head.next && list->head.prev == NULL && list->tail.prev && list->tail.next == NULL) {
      42           0 : #if (AWS_DEEP_CHECKS == 1)
      43           0 :         return aws_linked_list_is_valid_deep(list);
      44           0 : #else
      45           0 :         return true;
      46       50000 : #endif
      47       50000 :     }
      48           0 :     return false;
      49           0 : }
      50             : 
      51             : /**
      52             :  * Checks that the prev of the next pointer of a node points to the
      53             :  * node. As this checks whether the [next] connection of a node is
      54             :  * bidirectional, it returns false if used for the list tail.
      55             :  */
      56      356391 : AWS_STATIC_IMPL bool aws_linked_list_node_next_is_valid(const struct aws_linked_list_node *node) {
      57      356391 :     return node && node->next && node->next->prev == node;
      58      356391 : }
      59             : 
      60             : /**
      61             :  * Checks that the next of the prev pointer of a node points to the
      62             :  * node. Similarly to the above, this returns false if used for the
      63             :  * head of a list.
      64             :  */
      65      318051 : AWS_STATIC_IMPL bool aws_linked_list_node_prev_is_valid(const struct aws_linked_list_node *node) {
      66      318051 :     return node && node->prev && node->prev->next == node;
      67      318051 : }
      68             : 
      69             : /**
      70             :  * Checks that a linked list satisfies double linked list connectivity
      71             :  * constraints. This check is O(n) as it traverses the whole linked
      72             :  * list to ensure that tail is reachable from head (and vice versa)
      73             :  * and that every connection is bidirectional.
      74             :  *
      75             :  * Note: This check *cannot* go into an infinite loop, because we
      76             :  * ensure that the connection to the next node is
      77             :  * bidirectional. Therefore, if a node's [a] a.next is a previous node
      78             :  * [b] in the list, b.prev != &a and so this check would fail, thus
      79             :  * terminating the loop.
      80             :  */
      81           0 : AWS_STATIC_IMPL bool aws_linked_list_is_valid_deep(const struct aws_linked_list *list) {
      82           0 :     if (!list) {
      83           0 :         return false;
      84           0 :     }
      85           0 :     /* This could go into an infinite loop for a circular list */
      86           0 :     const struct aws_linked_list_node *temp = &list->head;
      87           0 :     /* Head must reach tail by following next pointers */
      88           0 :     bool head_reaches_tail = false;
      89           0 :     /* By satisfying the above and that edges are bidirectional, we
      90           0 :      * also guarantee that tail reaches head by following prev
      91           0 :      * pointers */
      92           0 :     while (temp) {
      93           0 :         if (temp == &list->tail) {
      94           0 :             head_reaches_tail = true;
      95           0 :             break;
      96           0 :         } else if (!aws_linked_list_node_next_is_valid(temp)) {
      97           0 :             /* Next and prev pointers should connect the same nodes */
      98           0 :             return false;
      99           0 :         }
     100           0 :         temp = temp->next;
     101           0 :     }
     102           0 :     return head_reaches_tail;
     103           0 : }
     104             : 
     105             : /**
     106             :  * Initializes the list. List will be empty after this call.
     107             :  */
     108       58582 : AWS_STATIC_IMPL void aws_linked_list_init(struct aws_linked_list *list) {
     109       58582 :     AWS_PRECONDITION(list);
     110       58582 :     list->head.next = &list->tail;
     111       58582 :     list->head.prev = NULL;
     112       58582 :     list->tail.prev = &list->head;
     113       58582 :     list->tail.next = NULL;
     114       58582 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     115       58582 :     AWS_POSTCONDITION(aws_linked_list_empty(list));
     116       58582 : }
     117             : 
     118             : /**
     119             :  * Returns an iteration pointer for the first element in the list.
     120             :  */
     121       39015 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_begin(const struct aws_linked_list *list) {
     122       39015 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     123       39015 :     struct aws_linked_list_node *rval = list->head.next;
     124       39015 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     125       39015 :     AWS_POSTCONDITION(rval == list->head.next);
     126       39015 :     return rval;
     127       39015 : }
     128             : 
     129             : /**
     130             :  * Returns an iteration pointer for one past the last element in the list.
     131             :  */
     132       37881 : AWS_STATIC_IMPL const struct aws_linked_list_node *aws_linked_list_end(const struct aws_linked_list *list) {
     133       37881 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     134       37881 :     const struct aws_linked_list_node *rval = &list->tail;
     135       37881 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     136       37881 :     AWS_POSTCONDITION(rval == &list->tail);
     137       37881 :     return rval;
     138       37881 : }
     139             : 
     140             : /**
     141             :  * Returns a pointer for the last element in the list.
     142             :  * Used to begin iterating the list in reverse. Ex:
     143             :  *   for (i = aws_linked_list_rbegin(list); i != aws_linked_list_rend(list); i = aws_linked_list_prev(i)) {...}
     144             :  */
     145       38027 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_rbegin(const struct aws_linked_list *list) {
     146       38027 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     147       38027 :     struct aws_linked_list_node *rval = list->tail.prev;
     148       38027 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     149       38027 :     AWS_POSTCONDITION(rval == list->tail.prev);
     150       38027 :     return rval;
     151       38027 : }
     152             : 
     153             : /**
     154             :  * Returns the pointer to one before the first element in the list.
     155             :  * Used to end iterating the list in reverse.
     156             :  */
     157       37977 : AWS_STATIC_IMPL const struct aws_linked_list_node *aws_linked_list_rend(const struct aws_linked_list *list) {
     158       37977 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     159       37977 :     const struct aws_linked_list_node *rval = &list->head;
     160       37977 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     161       37977 :     AWS_POSTCONDITION(rval == &list->head);
     162       37977 :     return rval;
     163       37977 : }
     164             : 
     165             : /**
     166             :  * Returns the next element in the list.
     167             :  */
     168       50000 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_next(const struct aws_linked_list_node *node) {
     169       50000 :     AWS_PRECONDITION(aws_linked_list_node_next_is_valid(node));
     170       50000 :     struct aws_linked_list_node *rval = node->next;
     171       50000 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(node));
     172       50000 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(rval));
     173       50000 :     AWS_POSTCONDITION(rval == node->next);
     174       50000 :     return rval;
     175       50000 : }
     176             : 
     177             : /**
     178             :  * Returns the previous element in the list.
     179             :  */
     180       50000 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_prev(const struct aws_linked_list_node *node) {
     181       50000 :     AWS_PRECONDITION(aws_linked_list_node_prev_is_valid(node));
     182       50000 :     struct aws_linked_list_node *rval = node->prev;
     183       50000 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(node));
     184       50000 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(rval));
     185       50000 :     AWS_POSTCONDITION(rval == node->prev);
     186       50000 :     return rval;
     187       50000 : }
     188             : 
     189             : /**
     190             :  * Inserts to_add immediately after after.
     191             :  */
     192             : AWS_STATIC_IMPL void aws_linked_list_insert_after(
     193             :     struct aws_linked_list_node *after,
     194       38748 :     struct aws_linked_list_node *to_add) {
     195       38748 :     AWS_PRECONDITION(aws_linked_list_node_next_is_valid(after));
     196       38748 :     AWS_PRECONDITION(to_add != NULL);
     197       38748 :     to_add->prev = after;
     198       38748 :     to_add->next = after->next;
     199       38748 :     after->next->prev = to_add;
     200       38748 :     after->next = to_add;
     201       38748 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(after));
     202       38748 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(to_add));
     203       38748 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(to_add));
     204       38748 :     AWS_POSTCONDITION(after->next == to_add);
     205       38748 : }
     206             : 
     207             : /**
     208             :  * Swaps the order two nodes in the linked list.
     209             :  */
     210           0 : AWS_STATIC_IMPL void aws_linked_list_swap_nodes(struct aws_linked_list_node *a, struct aws_linked_list_node *b) {
     211           0 :     AWS_PRECONDITION(aws_linked_list_node_prev_is_valid(a));
     212           0 :     AWS_PRECONDITION(aws_linked_list_node_next_is_valid(a));
     213           0 :     AWS_PRECONDITION(aws_linked_list_node_prev_is_valid(b));
     214           0 :     AWS_PRECONDITION(aws_linked_list_node_next_is_valid(b));
     215           0 : 
     216           0 :     if (a == b) {
     217           0 :         return;
     218           0 :     }
     219           0 : 
     220           0 :     /* snapshot b's value to avoid clobbering its next/prev pointers if a/b are adjacent */
     221           0 :     struct aws_linked_list_node tmp = *b;
     222           0 :     a->prev->next = b;
     223           0 :     a->next->prev = b;
     224           0 : 
     225           0 :     tmp.prev->next = a;
     226           0 :     tmp.next->prev = a;
     227           0 : 
     228           0 :     tmp = *a;
     229           0 :     *a = *b;
     230           0 :     *b = tmp;
     231           0 : 
     232           0 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(a));
     233           0 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(a));
     234           0 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(b));
     235           0 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(b));
     236           0 : }
     237             : 
     238             : /**
     239             :  * Inserts to_add immediately before before.
     240             :  */
     241             : AWS_STATIC_IMPL void aws_linked_list_insert_before(
     242             :     struct aws_linked_list_node *before,
     243      115175 :     struct aws_linked_list_node *to_add) {
     244      115175 :     AWS_PRECONDITION(aws_linked_list_node_prev_is_valid(before));
     245      115175 :     AWS_PRECONDITION(to_add != NULL);
     246      115175 :     to_add->next = before;
     247      115175 :     to_add->prev = before->prev;
     248      115175 :     before->prev->next = to_add;
     249      115175 :     before->prev = to_add;
     250      115175 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(before));
     251      115175 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(to_add));
     252      115175 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(to_add));
     253      115175 :     AWS_POSTCONDITION(before->prev == to_add);
     254      115175 : }
     255             : 
     256             : /**
     257             :  * Removes the specified node from the list (prev/next point to each other) and
     258             :  * returns the next node in the list.
     259             :  */
     260      114472 : AWS_STATIC_IMPL void aws_linked_list_remove(struct aws_linked_list_node *node) {
     261      114472 :     AWS_PRECONDITION(aws_linked_list_node_prev_is_valid(node));
     262      114472 :     AWS_PRECONDITION(aws_linked_list_node_next_is_valid(node));
     263      114472 :     node->prev->next = node->next;
     264      114472 :     node->next->prev = node->prev;
     265      114472 :     aws_linked_list_node_reset(node);
     266      114472 :     AWS_POSTCONDITION(node->next == NULL && node->prev == NULL);
     267      114472 : }
     268             : 
     269             : /**
     270             :  * Append new_node.
     271             :  */
     272       38132 : AWS_STATIC_IMPL void aws_linked_list_push_back(struct aws_linked_list *list, struct aws_linked_list_node *node) {
     273       38132 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     274       38132 :     AWS_PRECONDITION(node != NULL);
     275       38132 :     aws_linked_list_insert_before(&list->tail, node);
     276       38132 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     277       38132 :     AWS_POSTCONDITION(list->tail.prev == node, "[node] is the new last element of [list]");
     278       38132 : }
     279             : 
     280             : /**
     281             :  * Returns the element in the back of the list.
     282             :  */
     283       75517 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_back(const struct aws_linked_list *list) {
     284       75517 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     285       75517 :     AWS_PRECONDITION(!aws_linked_list_empty(list));
     286       75517 :     struct aws_linked_list_node *rval = list->tail.prev;
     287       75517 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     288       75517 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(rval));
     289       75517 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(rval));
     290       75517 :     return rval;
     291       75517 : }
     292             : 
     293             : /**
     294             :  * Returns the element in the back of the list and removes it
     295             :  */
     296       37382 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_pop_back(struct aws_linked_list *list) {
     297       37382 :     AWS_PRECONDITION(!aws_linked_list_empty(list));
     298       37382 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     299       37382 :     struct aws_linked_list_node *back = aws_linked_list_back(list);
     300       37382 :     aws_linked_list_remove(back);
     301       37382 :     AWS_POSTCONDITION(back->next == NULL && back->prev == NULL);
     302       37382 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     303       37382 :     return back;
     304       37382 : }
     305             : 
     306             : /**
     307             :  * Prepend new_node.
     308             :  */
     309       38527 : AWS_STATIC_IMPL void aws_linked_list_push_front(struct aws_linked_list *list, struct aws_linked_list_node *node) {
     310       38527 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     311       38527 :     AWS_PRECONDITION(node != NULL);
     312       38527 :     aws_linked_list_insert_before(list->head.next, node);
     313       38527 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     314       38527 :     AWS_POSTCONDITION(list->head.next == node, "[node] is the new first element of [list]");
     315       38527 : }
     316             : 
     317             : /**
     318             :  * Returns the element in the front of the list.
     319             :  */
     320       76863 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_front(const struct aws_linked_list *list) {
     321       76863 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     322       76863 :     AWS_PRECONDITION(!aws_linked_list_empty(list));
     323       76863 :     struct aws_linked_list_node *rval = list->head.next;
     324       76863 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     325       76863 :     AWS_POSTCONDITION(aws_linked_list_node_prev_is_valid(rval));
     326       76863 :     AWS_POSTCONDITION(aws_linked_list_node_next_is_valid(rval));
     327       76863 :     return rval;
     328       76863 : }
     329             : 
     330             : /**
     331             :  * Returns the element in the front of the list and removes it
     332             :  */
     333       39021 : AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_pop_front(struct aws_linked_list *list) {
     334       39021 :     AWS_PRECONDITION(!aws_linked_list_empty(list));
     335       39021 :     AWS_PRECONDITION(aws_linked_list_is_valid(list));
     336       39021 :     struct aws_linked_list_node *front = aws_linked_list_front(list);
     337       39021 :     aws_linked_list_remove(front);
     338       39021 :     AWS_POSTCONDITION(front->next == NULL && front->prev == NULL);
     339       39021 :     AWS_POSTCONDITION(aws_linked_list_is_valid(list));
     340       39021 :     return front;
     341       39021 : }
     342             : 
     343             : AWS_STATIC_IMPL void aws_linked_list_swap_contents(
     344             :     struct aws_linked_list *AWS_RESTRICT a,
     345       32943 :     struct aws_linked_list *AWS_RESTRICT b) {
     346       32943 : 
     347       32943 :     AWS_PRECONDITION(aws_linked_list_is_valid(a));
     348       32943 :     AWS_PRECONDITION(aws_linked_list_is_valid(b));
     349       32943 :     AWS_PRECONDITION(a != b);
     350       32943 :     struct aws_linked_list_node *a_first = a->head.next;
     351       32943 :     struct aws_linked_list_node *a_last = a->tail.prev;
     352       32943 : 
     353       32943 :     /* Move B's contents into A */
     354       32943 :     if (aws_linked_list_empty(b)) {
     355        3303 :         aws_linked_list_init(a);
     356       29640 :     } else {
     357       29640 :         a->head.next = b->head.next;
     358       29640 :         a->head.next->prev = &a->head;
     359       29640 :         a->tail.prev = b->tail.prev;
     360       29640 :         a->tail.prev->next = &a->tail;
     361       29640 :     }
     362       32943 : 
     363       32943 :     /* Move A's old contents into B */
     364       32943 :     if (a_first == &a->tail) {
     365        5279 :         aws_linked_list_init(b);
     366       27664 :     } else {
     367       27664 :         b->head.next = a_first;
     368       27664 :         b->head.next->prev = &b->head;
     369       27664 :         b->tail.prev = a_last;
     370       27664 :         b->tail.prev->next = &b->tail;
     371       27664 :     }
     372       32943 :     AWS_POSTCONDITION(aws_linked_list_is_valid(a));
     373       32943 :     AWS_POSTCONDITION(aws_linked_list_is_valid(b));
     374       32943 : }
     375             : 
     376             : AWS_STATIC_IMPL void aws_linked_list_move_all_back(
     377             :     struct aws_linked_list *AWS_RESTRICT dst,
     378           0 :     struct aws_linked_list *AWS_RESTRICT src) {
     379           0 : 
     380           0 :     AWS_PRECONDITION(aws_linked_list_is_valid(src));
     381           0 :     AWS_PRECONDITION(aws_linked_list_is_valid(dst));
     382           0 :     AWS_PRECONDITION(dst != src);
     383           0 : 
     384           0 :     if (!aws_linked_list_empty(src)) {
     385           0 :         /* splice src nodes into dst, between the back and tail nodes */
     386           0 :         struct aws_linked_list_node *dst_back = dst->tail.prev;
     387           0 :         struct aws_linked_list_node *src_front = src->head.next;
     388           0 :         struct aws_linked_list_node *src_back = src->tail.prev;
     389           0 : 
     390           0 :         dst_back->next = src_front;
     391           0 :         src_front->prev = dst_back;
     392           0 : 
     393           0 :         dst->tail.prev = src_back;
     394           0 :         src_back->next = &dst->tail;
     395           0 : 
     396           0 :         /* reset src */
     397           0 :         src->head.next = &src->tail;
     398           0 :         src->tail.prev = &src->head;
     399           0 :     }
     400           0 : 
     401           0 :     AWS_POSTCONDITION(aws_linked_list_is_valid(src));
     402           0 :     AWS_POSTCONDITION(aws_linked_list_is_valid(dst));
     403           0 : }
     404             : 
     405             : AWS_STATIC_IMPL void aws_linked_list_move_all_front(
     406             :     struct aws_linked_list *AWS_RESTRICT dst,
     407           0 :     struct aws_linked_list *AWS_RESTRICT src) {
     408           0 : 
     409           0 :     AWS_PRECONDITION(aws_linked_list_is_valid(src));
     410           0 :     AWS_PRECONDITION(aws_linked_list_is_valid(dst));
     411           0 :     AWS_PRECONDITION(dst != src);
     412           0 : 
     413           0 :     if (!aws_linked_list_empty(src)) {
     414           0 :         /* splice src nodes into dst, between the head and front nodes */
     415           0 :         struct aws_linked_list_node *dst_front = dst->head.next;
     416           0 :         struct aws_linked_list_node *src_front = src->head.next;
     417           0 :         struct aws_linked_list_node *src_back = src->tail.prev;
     418           0 : 
     419           0 :         dst->head.next = src_front;
     420           0 :         src_front->prev = &dst->head;
     421           0 : 
     422           0 :         src_back->next = dst_front;
     423           0 :         dst_front->prev = src_back;
     424           0 : 
     425           0 :         /* reset src */
     426           0 :         src->head.next = &src->tail;
     427           0 :         src->tail.prev = &src->head;
     428           0 :     }
     429           0 : 
     430           0 :     AWS_POSTCONDITION(aws_linked_list_is_valid(src));
     431           0 :     AWS_POSTCONDITION(aws_linked_list_is_valid(dst));
     432           0 : }
     433             : 
     434             : AWS_EXTERN_C_END
     435             : 
     436             : #endif /* AWS_COMMON_LINKED_LIST_INL */

Generated by: LCOV version 1.13