#include "git-compat-util.h" #include "prio-queue.h" static inline int compare(struct prio_queue *queue, size_t i, size_t j) { int cmp = queue->compare(queue->array[i].data, queue->array[j].data, queue->cb_data); if (!cmp) cmp = (queue->array[i].ctr > queue->array[j].ctr) - (queue->array[i].ctr < queue->array[j].ctr); return cmp; } static inline void swap(struct prio_queue *queue, size_t i, size_t j) { SWAP(queue->array[i], queue->array[j]); } void prio_queue_reverse(struct prio_queue *queue) { size_t i, j; if (queue->compare) BUG("prio_queue_reverse() on non-LIFO queue"); if (!queue->nr_) return; for (i = 0; i < (j = (queue->nr_ - 1) - i); i++) swap(queue, i, j); } void clear_prio_queue(struct prio_queue *queue) { FREE_AND_NULL(queue->array); queue->nr_ = 0; queue->alloc = 0; queue->insertion_ctr = 0; queue->get_pending = 0; } static void sift_down_root(struct prio_queue *queue) { size_t ix, child; /* Push down the one at the root */ for (ix = 0; ix * 2 + 1 < queue->nr_; ix = child) { child = ix * 2 + 1; /* left */ if (child + 1 < queue->nr_ && compare(queue, child, child + 1) >= 0) child++; /* use right child */ if (compare(queue, ix, child) <= 0) break; swap(queue, child, ix); } } static inline void flush_get(struct prio_queue *queue) { if (!queue->get_pending) return; queue->get_pending = 0; queue->array[0] = queue->array[--queue->nr_]; sift_down_root(queue); } void prio_queue_put(struct prio_queue *queue, void *thing) { size_t ix, parent; if (queue->get_pending) { queue->get_pending = 0; queue->array[0].ctr = queue->insertion_ctr++; queue->array[0].data = thing; sift_down_root(queue); return; } /* Append at the end */ ALLOC_GROW(queue->array, queue->nr_ + 1, queue->alloc); queue->array[queue->nr_].ctr = queue->insertion_ctr++; queue->array[queue->nr_].data = thing; queue->nr_++; if (!queue->compare) return; /* LIFO */ /* Bubble up the new one */ for (ix = queue->nr_ - 1; ix; ix = parent) { parent = (ix - 1) / 2; if (compare(queue, parent, ix) <= 0) break; swap(queue, parent, ix); } } void *prio_queue_get(struct prio_queue *queue) { if (queue->nr_ <= queue->get_pending) { queue->nr_ = 0; queue->get_pending = 0; return NULL; } if (!queue->compare) return queue->array[--queue->nr_].data; /* LIFO */ flush_get(queue); queue->get_pending = 1; return queue->array[0].data; } void *prio_queue_peek(struct prio_queue *queue) { if (queue->nr_ <= queue->get_pending) { queue->nr_ = 0; queue->get_pending = 0; return NULL; } if (!queue->compare) return queue->array[queue->nr_ - 1].data; flush_get(queue); return queue->array[0].data; }