src/linked_list.c

changeset 468
75ae1dccd101
parent 467
95e42a963520
child 469
0458bff0b1cd
     1.1 --- a/src/linked_list.c	Tue Oct 05 13:04:20 2021 +0200
     1.2 +++ b/src/linked_list.c	Tue Oct 05 16:33:11 2021 +0200
     1.3 @@ -33,13 +33,13 @@
     1.4  
     1.5  /* LOW LEVEL LINKED LIST FUNCTIONS */
     1.6  
     1.7 -#define CX_LL_PTR(cur, off) ((void**)(((char*)cur)+off))
     1.8 +#define CX_LL_PTR(cur, off) (*(void**)(((char*)cur)+off))
     1.9  
    1.10  void *cx_linked_list_at(void *start, size_t start_index, ptrdiff_t loc_advance, size_t index) {
    1.11      size_t i = start_index;
    1.12      void *cur = start;
    1.13      while (i != index && cur != NULL) {
    1.14 -        cur = *CX_LL_PTR(cur, loc_advance);
    1.15 +        cur = CX_LL_PTR(cur, loc_advance);
    1.16          i < index ? i++ : i--;
    1.17      }
    1.18      return cur;
    1.19 @@ -53,7 +53,7 @@
    1.20      void *last;
    1.21      do {
    1.22          last = cur;
    1.23 -    } while ((cur = *CX_LL_PTR(cur, loc_next)) != NULL);
    1.24 +    } while ((cur = CX_LL_PTR(cur, loc_next)) != NULL);
    1.25  
    1.26      return last;
    1.27  }
    1.28 @@ -71,8 +71,7 @@
    1.29          *begin = new_node;
    1.30      } else {
    1.31          // if there is a last node, update its next pointer
    1.32 -        void **next = CX_LL_PTR(last, loc_next);
    1.33 -        *next = new_node;
    1.34 +        CX_LL_PTR(last, loc_next) = new_node;
    1.35      }
    1.36  
    1.37      // if there is an end pointer, update it
    1.38 @@ -82,11 +81,126 @@
    1.39  
    1.40      // if the nodes use a prev pointer, update it
    1.41      if (loc_prev >= 0) {
    1.42 -        void **prev = CX_LL_PTR(new_node, loc_prev);
    1.43 -        *prev = last;
    1.44 +        CX_LL_PTR(new_node, loc_prev) = last;
    1.45      }
    1.46  }
    1.47  
    1.48 +size_t cx_linked_list_size(void *node, ptrdiff_t loc_next) {
    1.49 +    size_t size = 0;
    1.50 +    while (node != NULL) {
    1.51 +        node = CX_LL_PTR(node, loc_next);
    1.52 +        size++;
    1.53 +    }
    1.54 +    return size;
    1.55 +}
    1.56 +
    1.57 +#define ll_prev(node) CX_LL_PTR(node, loc_prev)
    1.58 +#define ll_next(node) CX_LL_PTR(node, loc_next)
    1.59 +#define ll_data(node) (follow_ptr?CX_LL_PTR(node, loc_data):(((char*)node)+loc_data))
    1.60 +
    1.61 +static void *cx_linked_list_sort_merge(ptrdiff_t loc_prev, ptrdiff_t loc_next,
    1.62 +                                       ptrdiff_t loc_data, int follow_ptr,
    1.63 +                                       size_t length, void *ls, void *le, void *re,
    1.64 +                                       CxListComparator cmp_func) {
    1.65 +    const size_t sbo_len = 1024;
    1.66 +    void *sbo[sbo_len];
    1.67 +    void **sorted = (length >= sbo_len) ? malloc(sizeof(void *) * length) : sbo;
    1.68 +    void *rc, *lc;
    1.69 +
    1.70 +    lc = ls;
    1.71 +    rc = le;
    1.72 +    size_t n = 0;
    1.73 +    while (lc && lc != le && rc != re) {
    1.74 +        if (cmp_func(ll_data(lc), ll_data(rc)) <= 0) {
    1.75 +            sorted[n] = lc;
    1.76 +            lc = ll_next(lc);
    1.77 +        } else {
    1.78 +            sorted[n] = rc;
    1.79 +            rc = ll_next(rc);
    1.80 +        }
    1.81 +        n++;
    1.82 +    }
    1.83 +    while (lc && lc != le) {
    1.84 +        sorted[n] = lc;
    1.85 +        lc = ll_next(lc);
    1.86 +        n++;
    1.87 +    }
    1.88 +    while (rc && rc != re) {
    1.89 +        sorted[n] = rc;
    1.90 +        rc = ll_next(rc);
    1.91 +        n++;
    1.92 +    }
    1.93 +
    1.94 +    // Update pointer
    1.95 +    if (loc_prev >= 0) ll_prev(sorted[0]) = NULL;
    1.96 +    for (size_t i = 0; i < length - 1; i++) {
    1.97 +        ll_next(sorted[i]) = sorted[i + 1];
    1.98 +        if (loc_prev >= 0) ll_prev(sorted[i + 1]) = sorted[i];
    1.99 +    }
   1.100 +    ll_next(sorted[length - 1]) = NULL;
   1.101 +
   1.102 +    void *ret = sorted[0];
   1.103 +    if (sorted != sbo) {
   1.104 +        free(sorted);
   1.105 +    }
   1.106 +    return ret;
   1.107 +}
   1.108 +
   1.109 +void cx_linked_list_sort(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next,
   1.110 +                         ptrdiff_t loc_data, int follow_ptr, CxListComparator cmp_func) {
   1.111 +    assert(begin != NULL);
   1.112 +
   1.113 +    void *lc, *ls, *le, *re;
   1.114 +
   1.115 +    // set start node
   1.116 +    ls = *begin;
   1.117 +
   1.118 +    // check how many elements are already sorted
   1.119 +    lc = ls;
   1.120 +    size_t ln = 1;
   1.121 +    while (ll_next(lc) != NULL && cmp_func(ll_data(ll_next(lc)), ll_data(lc)) > 0) {
   1.122 +        lc = ll_next(lc);
   1.123 +        ln++;
   1.124 +    }
   1.125 +    le = ll_next(lc);
   1.126 +
   1.127 +    // if first unsorted node is NULL, the list is already completely sorted
   1.128 +    if (le != NULL) {
   1.129 +        void *rc;
   1.130 +        size_t rn = 1;
   1.131 +        rc = le;
   1.132 +        // skip already sorted elements
   1.133 +        while (ll_next(rc) != NULL && cmp_func(ll_data(ll_next(rc)), ll_data(rc)) > 0) {
   1.134 +            rc = ll_next(rc);
   1.135 +            rn++;
   1.136 +        }
   1.137 +        re = ll_next(rc);
   1.138 +
   1.139 +        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
   1.140 +        void *sorted = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, follow_ptr,
   1.141 +                                                 ln + rn, ls, le, re, cmp_func);
   1.142 +
   1.143 +        // Something left? Sort it!
   1.144 +        size_t remainder_length = cx_linked_list_size(re, loc_next);
   1.145 +        if (remainder_length > 0) {
   1.146 +            void *remainder = re;
   1.147 +            cx_linked_list_sort(&remainder, NULL, loc_prev, loc_next, loc_data, follow_ptr, cmp_func);
   1.148 +
   1.149 +            // merge sorted list with (also sorted) remainder
   1.150 +            *begin = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, follow_ptr,
   1.151 +                                               ln + rn + remainder_length,
   1.152 +                                               sorted, remainder, NULL, cmp_func);
   1.153 +        } else {
   1.154 +            // no remainder - we've got our sorted list
   1.155 +            *begin = sorted;
   1.156 +        }
   1.157 +        if (end) *end = cx_linked_list_last(sorted, loc_next);
   1.158 +    }
   1.159 +}
   1.160 +
   1.161 +#undef ll_next
   1.162 +#undef ll_data
   1.163 +
   1.164  /* HIGH LEVEL LINKED LIST IMPLEMENTATION */
   1.165  
   1.166  typedef struct cx_linked_list_node cx_linked_list_node;
   1.167 @@ -109,7 +223,7 @@
   1.168      if (index >= list->base.size) {
   1.169          return NULL;
   1.170      } else if (index > list->base.size / 2) {
   1.171 -        return cx_linked_list_at(list->end, list->base.size-1, CX_LL_LOC_PREV, index);
   1.172 +        return cx_linked_list_at(list->end, list->base.size - 1, CX_LL_LOC_PREV, index);
   1.173      } else {
   1.174          return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index);
   1.175      }
   1.176 @@ -144,7 +258,7 @@
   1.177              node->next = NULL;
   1.178              ll->end = node;
   1.179          }
   1.180 -        // check if this shall be the new start node
   1.181 +            // check if this shall be the new start node
   1.182          else if (index == 0) {
   1.183              ll->begin->prev = node;
   1.184              node->next = ll->begin;
   1.185 @@ -219,7 +333,7 @@
   1.186  static void *cx_pll_at(cx_list_s *list, size_t index) {
   1.187      cx_linked_list *ll = (cx_linked_list *) list;
   1.188      cx_linked_list_node *node = cx_ll_node_at(ll, index);
   1.189 -    return node == NULL ? NULL : *(void**)node->payload;
   1.190 +    return node == NULL ? NULL : *(void **) node->payload;
   1.191  }
   1.192  
   1.193  static size_t cx_ll_find(cx_list_s *list, void *elem) {
   1.194 @@ -245,7 +359,7 @@
   1.195      size_t index;
   1.196      cx_linked_list_node *node = ll->begin;
   1.197      for (index = 0; index < list->size; index++) {
   1.198 -        void *current = *(void**)node->payload;
   1.199 +        void *current = *(void **) node->payload;
   1.200          if (cmp(current, elem) == 0) {
   1.201              return index;
   1.202          }
   1.203 @@ -263,7 +377,7 @@
   1.204  static void *cx_pll_last(cx_list_s *list) {
   1.205      cx_linked_list *ll = (cx_linked_list *) list;
   1.206      cx_linked_list_node *last = ll->end;
   1.207 -    return last == NULL ? NULL : *(void**)last->payload;
   1.208 +    return last == NULL ? NULL : *(void **) last->payload;
   1.209  }
   1.210  
   1.211  static cx_list_class cx_linked_list_class = {
   1.212 @@ -310,7 +424,7 @@
   1.213      list->base.cl = &cx_pointer_linked_list_class;
   1.214      list->base.allocator = allocator;
   1.215      list->base.cmpfunc = comparator;
   1.216 -    list->base.itemsize = sizeof(void*);
   1.217 +    list->base.itemsize = sizeof(void *);
   1.218      list->base.capacity = SIZE_MAX;
   1.219      list->base.size = 0;
   1.220  

mercurial