prioq.c revision b5efdb8af40ea759a1ea584c1bc44ecc81dd00ce
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* Priority Queue
* The prioq object implements a priority queue. That is, it orders objects by
* their priority and allows O(1) access to the object with the highest
* priority. Insertion and removal are Θ(log n). Optionally, the caller can
* provide a pointer to an index which will be kept up-to-date by the prioq.
*
* The underlying algorithm used in this implementation is a Heap.
*/
#include "alloc-util.h"
#include "prioq.h"
#include "util.h"
struct prioq_item {
void *data;
unsigned *idx;
};
struct Prioq {
unsigned n_items, n_allocated;
struct prioq_item *items;
};
Prioq *q;
if (!q)
return q;
q->compare_func = compare_func;
return q;
}
if (!q)
return NULL;
free(q);
return NULL;
}
assert(q);
if (*q)
return 0;
*q = prioq_new(compare_func);
if (!*q)
return -ENOMEM;
return 0;
}
void *saved_data;
unsigned *saved_idx;
assert(q);
}
assert(q);
while (idx > 0) {
unsigned k;
break;
idx = k;
}
return idx;
}
assert(q);
for (;;) {
unsigned j, k, s;
j = k-1; /* left child */
if (j >= q->n_items)
break;
/* So our left child is smaller than we are, let's
* remember this fact */
s = j;
else
s = idx;
if (k < q->n_items &&
/* So our right child is smaller than we are, let's
* remember this fact */
s = k;
/* s now points to the smallest of the three items */
if (s == idx)
/* No swap necessary, we're done */
break;
idx = s;
}
return idx;
}
struct prioq_item *i;
unsigned k;
assert(q);
if (q->n_items >= q->n_allocated) {
unsigned n;
struct prioq_item *j;
if (!j)
return -ENOMEM;
q->items = j;
q->n_allocated = n;
}
k = q->n_items++;
i = q->items + k;
if (idx)
*idx = k;
shuffle_up(q, k);
return 0;
}
struct prioq_item *l;
assert(q);
assert(i);
if (i == l)
/* Last entry, let's just remove it */
q->n_items--;
else {
unsigned k;
/* Not last entry, let's replace the last entry with
* this one, and reshuffle */
k = i - q->items;
if (i->idx)
*i->idx = k;
q->n_items--;
k = shuffle_down(q, k);
shuffle_up(q, k);
}
}
struct prioq_item *i;
assert(q);
if (idx) {
if (*idx == PRIOQ_IDX_NULL ||
return NULL;
return NULL;
return i;
} else {
return i;
return NULL;
}
}
struct prioq_item *i;
if (!q)
return 0;
if (!i)
return 0;
remove_item(q, i);
return 1;
}
struct prioq_item *i;
unsigned k;
assert(q);
if (!i)
return 0;
k = i - q->items;
k = shuffle_down(q, k);
shuffle_up(q, k);
return 1;
}
void *prioq_peek(Prioq *q) {
if (!q)
return NULL;
if (q->n_items <= 0)
return NULL;
}
void *data;
if (!q)
return NULL;
if (q->n_items <= 0)
return NULL;
remove_item(q, q->items);
return data;
}
unsigned prioq_size(Prioq *q) {
if (!q)
return 0;
return q->n_items;
}
bool prioq_isempty(Prioq *q) {
if (!q)
return true;
return q->n_items <= 0;
}