LCOV - code coverage report
Current view: top level - basic - prioq.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 135 149 90.6 %
Date: 2015-07-29 18:47:03 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include "util.h"
      23             : #include "prioq.h"
      24             : 
      25             : struct prioq_item {
      26             :         void *data;
      27             :         unsigned *idx;
      28             : };
      29             : 
      30             : struct Prioq {
      31             :         compare_func_t compare_func;
      32             :         unsigned n_items, n_allocated;
      33             : 
      34             :         struct prioq_item *items;
      35             : };
      36             : 
      37        2071 : Prioq *prioq_new(compare_func_t compare_func) {
      38             :         Prioq *q;
      39             : 
      40        2071 :         q = new0(Prioq, 1);
      41        2071 :         if (!q)
      42           0 :                 return q;
      43             : 
      44        2071 :         q->compare_func = compare_func;
      45        2071 :         return q;
      46             : }
      47             : 
      48       13389 : Prioq* prioq_free(Prioq *q) {
      49       13389 :         if (!q)
      50       11318 :                 return NULL;
      51             : 
      52        2071 :         free(q->items);
      53        2071 :         free(q);
      54             : 
      55        2071 :         return NULL;
      56             : }
      57             : 
      58        1224 : int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
      59        1224 :         assert(q);
      60             : 
      61        1224 :         if (*q)
      62         205 :                 return 0;
      63             : 
      64        1019 :         *q = prioq_new(compare_func);
      65        1019 :         if (!*q)
      66           0 :                 return -ENOMEM;
      67             : 
      68        1019 :         return 0;
      69             : }
      70             : 
      71       78274 : static void swap(Prioq *q, unsigned j, unsigned k) {
      72             :         void *saved_data;
      73             :         unsigned *saved_idx;
      74             : 
      75       78274 :         assert(q);
      76       78274 :         assert(j < q->n_items);
      77       78274 :         assert(k < q->n_items);
      78             : 
      79       78274 :         assert(!q->items[j].idx || *(q->items[j].idx) == j);
      80       78274 :         assert(!q->items[k].idx || *(q->items[k].idx) == k);
      81             : 
      82       78274 :         saved_data = q->items[j].data;
      83       78274 :         saved_idx = q->items[j].idx;
      84       78274 :         q->items[j].data = q->items[k].data;
      85       78274 :         q->items[j].idx = q->items[k].idx;
      86       78274 :         q->items[k].data = saved_data;
      87       78274 :         q->items[k].idx = saved_idx;
      88             : 
      89       78274 :         if (q->items[j].idx)
      90       33966 :                 *q->items[j].idx = j;
      91             : 
      92       78274 :         if (q->items[k].idx)
      93       33966 :                 *q->items[k].idx = k;
      94       78274 : }
      95             : 
      96       28536 : static unsigned shuffle_up(Prioq *q, unsigned idx) {
      97       28536 :         assert(q);
      98             : 
      99       68031 :         while (idx > 0) {
     100             :                 unsigned k;
     101             : 
     102       28617 :                 k = (idx-1)/2;
     103             : 
     104       28617 :                 if (q->compare_func(q->items[k].data, q->items[idx].data) < 0)
     105       17658 :                         break;
     106             : 
     107       10959 :                 swap(q, idx, k);
     108       10959 :                 idx = k;
     109             :         }
     110             : 
     111       28536 :         return idx;
     112             : }
     113             : 
     114       13803 : static unsigned shuffle_down(Prioq *q, unsigned idx) {
     115       13803 :         assert(q);
     116             : 
     117             :         for (;;) {
     118             :                 unsigned j, k, s;
     119             : 
     120       81118 :                 k = (idx+1)*2; /* right child */
     121       81118 :                 j = k-1;       /* left child */
     122             : 
     123       81118 :                 if (j >= q->n_items)
     124       12606 :                         break;
     125             : 
     126       68512 :                 if (q->compare_func(q->items[j].data, q->items[idx].data) < 0)
     127             : 
     128             :                         /* So our left child is smaller than we are, let's
     129             :                          * remember this fact */
     130       65674 :                         s = j;
     131             :                 else
     132        2838 :                         s = idx;
     133             : 
     134      136922 :                 if (k < q->n_items &&
     135       68410 :                     q->compare_func(q->items[k].data, q->items[s].data) < 0)
     136             : 
     137             :                         /* So our right child is smaller than we are, let's
     138             :                          * remember this fact */
     139       33475 :                         s = k;
     140             : 
     141             :                 /* s now points to the smallest of the three items */
     142             : 
     143       68512 :                 if (s == idx)
     144             :                         /* No swap necessary, we're done */
     145        1197 :                         break;
     146             : 
     147       67315 :                 swap(q, idx, s);
     148       67315 :                 idx = s;
     149       67315 :         }
     150             : 
     151       13803 :         return idx;
     152             : }
     153             : 
     154       14733 : int prioq_put(Prioq *q, void *data, unsigned *idx) {
     155             :         struct prioq_item *i;
     156             :         unsigned k;
     157             : 
     158       14733 :         assert(q);
     159             : 
     160       14733 :         if (q->n_items >= q->n_allocated) {
     161             :                 unsigned n;
     162             :                 struct prioq_item *j;
     163             : 
     164        2094 :                 n = MAX((q->n_items+1) * 2, 16u);
     165        2094 :                 j = realloc(q->items, sizeof(struct prioq_item) * n);
     166        2094 :                 if (!j)
     167           0 :                         return -ENOMEM;
     168             : 
     169        2094 :                 q->items = j;
     170        2094 :                 q->n_allocated = n;
     171             :         }
     172             : 
     173       14733 :         k = q->n_items++;
     174       14733 :         i = q->items + k;
     175       14733 :         i->data = data;
     176       14733 :         i->idx = idx;
     177             : 
     178       14733 :         if (idx)
     179       10427 :                 *idx = k;
     180             : 
     181       14733 :         shuffle_up(q, k);
     182             : 
     183       14733 :         return 0;
     184             : }
     185             : 
     186       14729 : static void remove_item(Prioq *q, struct prioq_item *i) {
     187             :         struct prioq_item *l;
     188             : 
     189       14729 :         assert(q);
     190       14729 :         assert(i);
     191             : 
     192       14729 :         l = q->items + q->n_items - 1;
     193             : 
     194       14729 :         if (i == l)
     195             :                 /* Last entry, let's just remove it */
     196        5456 :                 q->n_items--;
     197             :         else {
     198             :                 unsigned k;
     199             : 
     200             :                 /* Not last entry, let's replace the last entry with
     201             :                  * this one, and reshuffle */
     202             : 
     203        9273 :                 k = i - q->items;
     204             : 
     205        9273 :                 i->data = l->data;
     206        9273 :                 i->idx = l->idx;
     207        9273 :                 if (i->idx)
     208        4978 :                         *i->idx = k;
     209        9273 :                 q->n_items--;
     210             : 
     211        9273 :                 k = shuffle_down(q, k);
     212        9273 :                 shuffle_up(q, k);
     213             :         }
     214       14729 : }
     215             : 
     216       11881 : _pure_ static struct prioq_item* find_item(Prioq *q, void *data, unsigned *idx) {
     217             :         struct prioq_item *i;
     218             : 
     219       11881 :         assert(q);
     220             : 
     221       11881 :         if (idx) {
     222       23762 :                 if (*idx == PRIOQ_IDX_NULL ||
     223       11881 :                     *idx > q->n_items)
     224           0 :                         return NULL;
     225             : 
     226       11881 :                 i = q->items + *idx;
     227       11881 :                 if (i->data != data)
     228           0 :                         return NULL;
     229             : 
     230       11881 :                 return i;
     231             :         } else {
     232           0 :                 for (i = q->items; i < q->items + q->n_items; i++)
     233           0 :                         if (i->data == data)
     234           0 :                                 return i;
     235           0 :                 return NULL;
     236             :         }
     237             : }
     238             : 
     239        7351 : int prioq_remove(Prioq *q, void *data, unsigned *idx) {
     240             :         struct prioq_item *i;
     241             : 
     242        7351 :         if (!q)
     243           0 :                 return 0;
     244             : 
     245        7351 :         i = find_item(q, data, idx);
     246        7351 :         if (!i)
     247           0 :                 return 0;
     248             : 
     249        7351 :         remove_item(q, i);
     250        7351 :         return 1;
     251             : }
     252             : 
     253        4530 : int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
     254             :         struct prioq_item *i;
     255             :         unsigned k;
     256             : 
     257        4530 :         assert(q);
     258             : 
     259        4530 :         i = find_item(q, data, idx);
     260        4530 :         if (!i)
     261           0 :                 return 0;
     262             : 
     263        4530 :         k = i - q->items;
     264        4530 :         k = shuffle_down(q, k);
     265        4530 :         shuffle_up(q, k);
     266        4530 :         return 1;
     267             : }
     268             : 
     269       99253 : void *prioq_peek(Prioq *q) {
     270             : 
     271       99253 :         if (!q)
     272       73711 :                 return NULL;
     273             : 
     274       25542 :         if (q->n_items <= 0)
     275        5189 :                 return NULL;
     276             : 
     277       20353 :         return q->items[0].data;
     278             : }
     279             : 
     280        7398 : void *prioq_pop(Prioq *q) {
     281             :         void *data;
     282             : 
     283        7398 :         if (!q)
     284          10 :                 return NULL;
     285             : 
     286        7388 :         if (q->n_items <= 0)
     287          10 :                 return NULL;
     288             : 
     289        7378 :         data = q->items[0].data;
     290        7378 :         remove_item(q, q->items);
     291        7378 :         return data;
     292             : }
     293             : 
     294        7168 : unsigned prioq_size(Prioq *q) {
     295             : 
     296        7168 :         if (!q)
     297           0 :                 return 0;
     298             : 
     299        7168 :         return q->n_items;
     300             : }
     301             : 
     302           2 : bool prioq_isempty(Prioq *q) {
     303             : 
     304           2 :         if (!q)
     305           0 :                 return true;
     306             : 
     307           2 :         return q->n_items <= 0;
     308             : }

Generated by: LCOV version 1.11