LCOV - code coverage report
Current view: top level - dev/pci/drm - linux_list_sort.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 41 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $NetBSD: linux_list_sort.c,v 1.2 2014/03/18 18:20:43 riastradh Exp $    */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2013 The NetBSD Foundation, Inc.
       5             :  * All rights reserved.
       6             :  *
       7             :  * This code is derived from software contributed to The NetBSD Foundation
       8             :  * by Taylor R. Campbell.
       9             :  *
      10             :  * Redistribution and use in source and binary forms, with or without
      11             :  * modification, are permitted provided that the following conditions
      12             :  * are met:
      13             :  * 1. Redistributions of source code must retain the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer.
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      20             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      21             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      22             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      23             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      24             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      25             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      26             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      27             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      28             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      29             :  * POSSIBILITY OF SUCH DAMAGE.
      30             :  */
      31             : 
      32             : #include <sys/param.h>
      33             : #include <sys/systm.h>
      34             : 
      35             : #include <machine/limits.h>
      36             : 
      37             : #include <dev/pci/drm/drm_linux_list.h>
      38             : 
      39             : static struct list_head *
      40             : list_sort_merge(struct list_head *, struct list_head *,
      41             :                 int (*)(void *, struct list_head *,
      42             :                 struct list_head *), void *);
      43             : static void
      44             : list_sort_merge_into(struct list_head *,
      45             :                      struct list_head *, struct list_head *,
      46             :                      int (*)(void *, struct list_head *,
      47             :                      struct list_head *), void *);
      48             : 
      49             : void
      50           0 : list_sort(void *arg, struct list_head *list,
      51             :           int (*compare)(void *, struct list_head *, struct list_head *))
      52             : {
      53             :         /*
      54             :          * Array of sorted sublists, counting in binary: accum[i]
      55             :          * is sorted, and either is NULL or has length 2^i.
      56             :          */
      57           0 :         struct list_head *accum[64];
      58             : 
      59             :         /* Indices into accum.  */
      60             :         unsigned int logn, max_logn = 0;
      61             : 
      62             :         /* The sorted list we're currently working on.  */
      63             :         struct list_head *sorted;
      64             : 
      65             :         /* The remainder of the unsorted list.  */
      66             :         struct list_head *next;
      67             : 
      68             :         /* Make sure we can't possibly have more than 2^64-element lists.  */
      69             :         CTASSERT((CHAR_BIT * sizeof(struct list_head *)) <= 64);
      70             : 
      71           0 :         for (logn = 0; logn < nitems(accum); logn++)
      72           0 :                 accum[logn] = NULL;
      73             : 
      74           0 :         list_for_each_safe(sorted, next, list) {
      75             :                 /* Pick off a single element, always sorted.  */
      76           0 :                 sorted->next = NULL;
      77             : 
      78             :                 /* Add one and propagate the carry.  */
      79           0 :                 for (logn = 0; accum[logn] != NULL; logn++) {
      80             :                         /*
      81             :                          * Merge, preferring previously accumulated
      82             :                          * elements to make the sort stable.
      83             :                          */
      84           0 :                         sorted = list_sort_merge(accum[logn], sorted, compare, arg);
      85           0 :                         accum[logn] = NULL;
      86           0 :                         KASSERT((logn + 1) < nitems(accum));
      87             :                 }
      88             : 
      89             :                 /* Remember the highest index seen so far.  */
      90           0 :                 if (logn > max_logn)
      91           0 :                         max_logn = logn;
      92             : 
      93             :                 /*
      94             :                  * logn = log_2(length(sorted)), and accum[logn]
      95             :                  * is now empty, so save the sorted sublist there.
      96             :                  */
      97           0 :                 accum[logn] = sorted;
      98             :         }
      99             : 
     100             :         /*
     101             :          * Merge ~half of everything we have accumulated.
     102             :          */
     103             :         sorted = NULL;
     104           0 :         for (logn = 0; logn < max_logn; logn++)
     105           0 :                 sorted = list_sort_merge(accum[logn], sorted, compare, arg);
     106             : 
     107             :         /*
     108             :          * Merge the last ~halves back into the list, and fix the back
     109             :          * pointers.
     110             :          */
     111           0 :         list_sort_merge_into(list, accum[max_logn], sorted, compare, arg);
     112           0 : }
     113             : 
     114             : /*
     115             :  * Merge the NULL-terminated lists starting at nodes `a' and `b',
     116             :  * breaking ties by choosing nodes in `a' first, and returning
     117             :  * whichever node has the least element.
     118             :  */
     119             : static struct list_head *
     120           0 : list_sort_merge(struct list_head *a, struct list_head *b,
     121             :                 int (*compare)(void *, struct list_head *,
     122             :                 struct list_head *), void *arg)
     123             : {
     124           0 :         struct list_head head, *tail = &head;
     125             : 
     126             :         /*
     127             :          * Merge while elements in both remain.
     128             :          */
     129           0 :         while ((a != NULL) && (b != NULL)) {
     130           0 :                 struct list_head **const first = ((*compare)(arg, a, b) <= 0?
     131             :                     &a : &b);
     132             : 
     133           0 :                 tail = tail->next = *first;
     134           0 :                 *first = (*first)->next;
     135             :         }
     136             : 
     137             :         /*
     138             :          * Attach whatever remains.
     139             :          */
     140           0 :         tail->next = (a != NULL? a : b);
     141           0 :         return head.next;
     142           0 : }
     143             : 
     144             : /*
     145             :  * Merge the NULL-terminated lists starting at nodes `a' and `b' into
     146             :  * the (uninitialized) list head `list', breaking ties by choosing
     147             :  * nodes in `a' first, and setting the `prev' pointers as we go.
     148             :  */
     149             : static void
     150           0 : list_sort_merge_into(struct list_head *list,
     151             :                      struct list_head *a, struct list_head *b,
     152             :                      int (*compare)(void *, struct list_head *,
     153             :                      struct list_head *), void *arg)
     154             : {
     155             :         struct list_head *prev = list;
     156             : 
     157             :         /*
     158             :          * Merge while elements in both remain.
     159             :          */
     160           0 :         while ((a != NULL) && (b != NULL)) {
     161             :                 struct list_head **const first = (
     162           0 :                         (*compare)(arg, a, b) <= 0 ? &a : &b);
     163             : 
     164           0 :                 (*first)->prev = prev;
     165           0 :                 prev = prev->next = *first;
     166           0 :                 *first = (*first)->next;
     167             :         }
     168             : 
     169             :         /*
     170             :          * Attach whichever of a and b remains, and fix up the prev
     171             :          * pointers all the way down the rest of the list.
     172             :          */
     173           0 :         struct list_head *tail = (a == NULL? b : a);
     174           0 :         while (tail != NULL) {
     175           0 :                 prev->next = tail;
     176           0 :                 tail->prev = prev;
     177           0 :                 prev = prev->next;
     178           0 :                 tail = tail->next;
     179             :         }
     180             : 
     181             :         /*
     182             :          * Finally, finish the cycle.
     183             :          */
     184           0 :         prev->next = list;
     185           0 :         list->prev = prev;
     186           0 : }

Generated by: LCOV version 1.13