#include <usual/event.h>
#include <usual/fileutil.h>
#include <usual/hashtab-impl.h>
-#include <usual/heap-impl.h>
+#include <usual/heap.h>
#include <usual/list.h>
#include <usual/logging.h>
#include <usual/lookup3.h>
-#include <usual/base.h>
+#include <usual/heap.h>
#include <stdio.h>
#include <stdlib.h>
#include "test_common.h"
-static void my_save_pos(void *p, unsigned i);
-
-#define SAVE_POS(p, i) my_save_pos(p, i)
-
-#include <usual/heap-impl.h>
+#include <usual/heap.c>
struct MyNode {
int value;
};
/* min-heap */
-static inline bool heap_is_better(const void *a, const void *b)
+static bool heap_is_better(const void *a, const void *b)
{
const struct MyNode *aa = a, *bb = b;
return (aa->value < bb->value);
static const char *my_insert(struct Heap *heap, int value)
{
struct MyNode *my = make_node(value);
- if (!heap_insert(heap, my))
+ if (!heap_push(heap, my))
return "FAIL";
return check(heap, value);
}
if (idx >= heap->used)
return "NEXIST";
n = heap->data[idx];
- heap_delete_pos(heap, idx);
+ heap_remove(heap, idx);
free(n);
return check(heap, 0);
}
static void test_heap_basic(void *p)
{
- struct Heap heap[1];
+ struct Heap *heap;
int i;
- heap_init(heap);
+ heap = heap_create(heap_is_better, my_save_pos, USUAL_ALLOC);
str_check(my_remove(heap, 0), "NEXIST");
str_check(my_insert(heap, 0), "OK");
#include <usual/statlist.h>
#include <usual/socket.h>
#include <usual/signal.h>
+#include <usual/heap.h>
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
/* extra event flag to track if event is added */
#define EV_ACTIVE 0x80
-/* load heap code */
-static inline void ev_save_pos(struct event *ev, int pos);
-#define SAVE_POS(ev, pos) ev_save_pos(ev, pos)
-#include <usual/heap-impl.h>
-
struct event_base {
/* pending timeouts */
- struct Heap timeout_heap;
+ struct Heap *timeout_heap;
/* fd events */
struct StatList fd_list;
return val;
}
-static inline bool heap_is_better(const void *a, const void *b)
+static bool ev_is_better(const void *a, const void *b)
{
const struct event *ev1 = a, *ev2 = b;
return ev1->timeout_val < ev2->timeout_val;
}
-static inline void ev_save_pos(struct event *ev, int pos)
+static void ev_save_pos(void *obj, unsigned pos)
{
+ struct event *ev = obj;
ev->timeout_idx = pos;
}
return NULL;
/* initialize timeout and fd areas */
- heap_init(&base->timeout_heap);
+ base->timeout_heap = heap_create(ev_is_better, ev_save_pos, USUAL_ALLOC);
+ if (!base->timeout_heap) {
+ free(base);
+ return NULL;
+ }
statlist_init(&base->fd_list, "fd_list");
/* initialize signal areas */
}
if (base == current_base)
current_base = NULL;
- heap_destroy(&base->timeout_heap);
+ heap_destroy(base->timeout_heap);
free(base->pfd_event);
free(base->pfd_list);
sig_close(base);
/* remove from timeout tree */
if (ev->flags & EV_TIMEOUT) {
- heap_delete_pos(&ev->base->timeout_heap, ev->timeout_idx);
+ heap_remove(ev->base->timeout_heap, ev->timeout_idx);
ev->flags &= ~EV_TIMEOUT;
}
if (timeout) {
if (ev->flags & EV_PERSIST)
goto err_inval;
- if (!heap_reserve(&base->timeout_heap, 1))
+ if (!heap_reserve(base->timeout_heap, 1))
return -1;
} else {
if (ev->flags & EV_TIMEOUT)
if (timeout) {
ev->timeout_val = convert_timeout(base, timeout);
ev->flags |= EV_TIMEOUT;
- heap_insert(&base->timeout_heap, ev);
+ heap_push(base->timeout_heap, ev);
}
ev->ev_idx = -1;
ev->flags |= EV_ACTIVE;
static inline struct event *get_smallest_timeout(struct event_base *base)
{
- return heap_get_top(&base->timeout_heap);
+ return heap_top(base->timeout_heap);
}
/* decide how long poll() should sleep */
+++ /dev/null
-/*
- * Binary Heap.
- *
- * Copyright (c) 2009 Marko Kreen, Skype Technologies OÜ
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/** @file
- * Binary heap.
- *
- * Summary - binary heap is sort of binary tree held inside array,
- * with following 2 properties:
- * - heap property: each node is "better" than it's childs.
- * - shape property: binary tree is complete, meaning all levels
- * except the last one are fully filled.
- *
- * Instead of "min"- or "max"-heap, this is "best"-heap,
- * as it operates with user-defined heap_is_better() functions,
- * which is used to bubble elements on top. Main reason
- * for such design is to make the comparisions inline.
- */
-
-/*
- * If user wants to delete elements from the middle of heap,
- * this macro should be used to keep track where the element
- * is located.
- */
-#ifndef SAVE_POS
-#define SAVE_POS(ptr, pos)
-#endif
-
-#include <usual/base.h>
-
-struct Heap {
- void **data;
- unsigned allocated;
- unsigned used;
-};
-
-/*
- * For user to be defined.
- *
- * Should return true if a needs to reach top before b,
- * false if not or equal.
- */
-static inline bool heap_is_better(const void *a, const void *b);
-
-
-/*
- * Low-level operations.
- */
-
-static inline unsigned _heap_get_parent(unsigned i)
-{
- return (i - 1) / 2;
-}
-
-static inline unsigned _heap_get_child(unsigned i, unsigned child_nr)
-{
- return 2*i + 1 + child_nr;
-}
-
-static inline bool _heap_is_better(struct Heap *h, unsigned i1, unsigned i2)
-{
- return heap_is_better(h->data[i1], h->data[i2]);
-}
-
-static inline void _heap_set(struct Heap *h, unsigned i, void *ptr)
-{
- h->data[i] = ptr;
- SAVE_POS(ptr, i);
-}
-
-static inline void _heap_swap(struct Heap *h, unsigned i1, unsigned i2)
-{
- void *tmp = h->data[i1];
- _heap_set(h, i1, h->data[i2]);
- _heap_set(h, i2, tmp);
-}
-
-static void _heap_bubble_up(struct Heap *h, unsigned i)
-{
- unsigned p;
- while (i > 0) {
- p = _heap_get_parent(i);
- if (!_heap_is_better(h, i, p))
- break;
- _heap_swap(h, i, p);
- i = p;
- }
-}
-
-static void _heap_bubble_down(struct Heap *h, unsigned i)
-{
- unsigned c = _heap_get_child(i, 0);
- while (c < h->used) {
- if (c + 1 < h->used) {
- if (_heap_is_better(h, c + 1, c))
- c = c + 1;
- }
- if (!_heap_is_better(h, c, i))
- break;
- _heap_swap(h, i, c);
- i = c;
- c = _heap_get_child(i, 0);
- }
-}
-
-static bool _heap_make_room(struct Heap *h, unsigned extra)
-{
- void *tmp;
- unsigned newalloc;
-
- if (h->used + extra < h->allocated)
- return true;
-
- newalloc = h->allocated * 2;
- if (newalloc < 32)
- newalloc = 32;
- if (newalloc < h->used + extra)
- newalloc = h->used + extra;
-
- tmp = realloc(h->data, newalloc * sizeof(void *));
- if (!tmp)
- return false;
- h->data = tmp;
- h->allocated = newalloc;
- return true;
-}
-
-
-/*
- * Actual API.
- */
-
-
-static void heap_init(struct Heap *h)
-{
- h->data = NULL;
- h->allocated = 0;
- h->used = 0;
-}
-
-static void heap_destroy(struct Heap *h)
-{
- free(h->data);
- heap_init(h);
-}
-
-static inline void *heap_get_top(struct Heap *h)
-{
- return (h->used > 0) ? h->data[0] : NULL;
-}
-
-static inline bool heap_reserve(struct Heap *h, unsigned extra)
-{
- if (h->used + extra < h->allocated)
- return true;
-
- return _heap_make_room(h, extra);
-}
-
-static bool heap_insert(struct Heap *h, void *ptr)
-{
- unsigned i;
-
- if (!heap_reserve(h, 1))
- return false;
-
- i = h->used++;
- _heap_set(h, i, ptr);
- _heap_bubble_up(h, i);
- return true;
-}
-
-static void heap_delete_pos(struct Heap *h, unsigned pos)
-{
- unsigned last;
-
- if (pos >= h->used)
- return;
-
- last = --h->used;
- if (pos == last) {
- h->data[last] = NULL;
- return;
- }
-
- _heap_set(h, pos, h->data[last]);
- h->data[last] = NULL;
-
- if (pos > 0 && _heap_is_better(h, pos, _heap_get_parent(pos)))
- _heap_bubble_up(h, pos);
- else
- _heap_bubble_down(h, pos);
-}
-
-static void heap_delete_top(struct Heap *h)
-{
- heap_delete_pos(h, 0);
-}
-
-/* example and avoid 'unused' warnings */
-static inline void _heap_example(void *el)
-{
- struct Heap h;
- void *top;
- heap_init(&h);
- heap_insert(&h, el);
- top = heap_get_top(&h);
- heap_delete_top(&h);
- heap_destroy(&h);
-}
-
--- /dev/null
+/*
+ * Binary Heap.
+ *
+ * Copyright (c) 2009 Marko Kreen, Skype Technologies OÜ
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <usual/heap.h>
+
+struct Heap {
+ void **data;
+
+ unsigned allocated;
+ unsigned used;
+
+ heap_is_better_f is_better;
+ heap_save_pos_f save_pos;
+
+ CxMem *cx;
+};
+
+/*
+ * Low-level operations.
+ */
+
+#define inline __attribute__((always_inline))
+
+static unsigned _heap_get_parent(unsigned i)
+{
+ return (i - 1) / 2;
+}
+
+static unsigned _heap_get_child(unsigned i, unsigned child_nr)
+{
+ return 2*i + 1 + child_nr;
+}
+
+static bool _heap_is_better(struct Heap *h, unsigned i1, unsigned i2)
+{
+ return h->is_better(h->data[i1], h->data[i2]);
+}
+
+static void _heap_set(struct Heap *h, unsigned i, void *ptr)
+{
+ h->data[i] = ptr;
+ if (h->save_pos)
+ h->save_pos(ptr, i);
+}
+
+static void _heap_swap(struct Heap *h, unsigned i1, unsigned i2)
+{
+ void *tmp = h->data[i1];
+ _heap_set(h, i1, h->data[i2]);
+ _heap_set(h, i2, tmp);
+}
+
+static void _heap_bubble_up(struct Heap *h, unsigned i)
+{
+ unsigned p;
+ while (i > 0) {
+ p = _heap_get_parent(i);
+ if (!_heap_is_better(h, i, p))
+ break;
+ _heap_swap(h, i, p);
+ i = p;
+ }
+}
+
+static void _heap_bubble_down(struct Heap *h, unsigned i)
+{
+ unsigned c = _heap_get_child(i, 0);
+ while (c < h->used) {
+ if (c + 1 < h->used) {
+ if (_heap_is_better(h, c + 1, c))
+ c = c + 1;
+ }
+ if (!_heap_is_better(h, c, i))
+ break;
+ _heap_swap(h, i, c);
+ i = c;
+ c = _heap_get_child(i, 0);
+ }
+}
+
+static void rebalance(struct Heap *h, unsigned pos)
+{
+ if (pos == 0) {
+ _heap_bubble_down(h, pos);
+ } else if (pos == h->used - 1) {
+ _heap_bubble_up(h, pos);
+ } else if (_heap_is_better(h, pos, _heap_get_parent(pos))) {
+ _heap_bubble_up(h, pos);
+ } else {
+ _heap_bubble_down(h, pos);
+ }
+}
+
+/*
+ * Actual API.
+ */
+
+
+struct Heap *heap_create(heap_is_better_f is_better_cb, heap_save_pos_f save_pos_cb, CxMem *cx)
+{
+ struct Heap *h;
+
+ h = cx_alloc0(cx, sizeof(*cx));
+ if (!h)
+ return NULL;
+
+ h->save_pos = save_pos_cb;
+ h->is_better = is_better_cb;
+ h->cx = cx;
+
+ return h;
+}
+
+void heap_destroy(struct Heap *h)
+{
+ cx_free(h->cx, h->data);
+ cx_free(h->cx, h);
+}
+
+bool heap_reserve(struct Heap *h, unsigned extra)
+{
+ void *tmp;
+ unsigned newalloc;
+
+ if (h->used + extra < h->allocated)
+ return true;
+
+ newalloc = h->allocated * 2;
+ if (newalloc < 32)
+ newalloc = 32;
+ if (newalloc < h->used + extra)
+ newalloc = h->used + extra;
+
+ tmp = realloc(h->data, newalloc * sizeof(void *));
+ if (!tmp)
+ return false;
+ h->data = tmp;
+ h->allocated = newalloc;
+ return true;
+}
+
+void *heap_top(struct Heap *h)
+{
+ return (h->used > 0) ? h->data[0] : NULL;
+}
+
+bool heap_push(struct Heap *h, void *ptr)
+{
+ unsigned pos;
+
+ if (h->used >= h->allocated) {
+ if (!heap_reserve(h, 1))
+ return false;
+ }
+
+ pos = h->used++;
+ _heap_set(h, pos, ptr);
+ _heap_bubble_up(h, pos);
+ return true;
+}
+
+void *heap_remove(struct Heap *h, unsigned pos)
+{
+ unsigned last;
+ void *obj;
+
+ if (pos >= h->used)
+ return NULL;
+
+ obj = h->data[pos];
+
+ last = --h->used;
+ _heap_set(h, pos, h->data[last]);
+ h->data[last] = NULL;
+
+ rebalance(h, pos);
+
+ return obj;
+}
+
+void *heap_pop(struct Heap *h)
+{
+ return heap_remove(h, 0);
+}
+
--- /dev/null
+/*
+ * Binary Heap.
+ *
+ * Copyright (c) 2009 Marko Kreen, Skype Technologies OÜ
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/** @file
+ * Binary heap.
+ *
+ * Binary heap is sort of binary tree held inside array,
+ * with following 2 properties:
+ * - heap property: each node is "better" than it's childs.
+ * - shape property: binary tree is complete, meaning all levels
+ * except the last one are fully filled.
+ *
+ * Instead of "min"- or "max"-heap, this is "best"-heap,
+ * as it operates with user-defined heap_is_better() functions,
+ * which is used to bubble elements on top.
+ */
+
+#ifndef _USUAL_HEAP_H_
+#define _USUAL_HEAP_H_
+
+#include <usual/cxalloc.h>
+
+/**
+ * Object comparision function.
+ *
+ * Should return true if a needs to reach top before b,
+ * false if not or equal.
+ */
+typedef bool (*heap_is_better_f)(const void *a, const void *b);
+
+/**
+ * Heap position storage.
+ *
+ * If user wants to delete elements from the middle of heap,
+ * this function should be used to keep track where the element
+ * is located.
+ */
+typedef void (*heap_save_pos_f)(void *a, unsigned pos);
+
+/**
+ * Heap object.
+ */
+struct Heap;
+
+
+/**
+ * Create new heap object.
+ *
+ * @param is_better_cb Callback to decide priority.
+ * @param save_pos_cb Callback to store current index.
+ * @param cx Allocation context.
+ */
+struct Heap *heap_create(
+ heap_is_better_f is_better_cb,
+ heap_save_pos_f save_pos_cb,
+ CxMem *cx);
+
+/** Release memory allocated by heap */
+void heap_destroy(struct Heap *h);
+
+/** Put new object into heap */
+bool heap_push(struct Heap *h, void *ptr);
+
+/** Remove and return topmost object from heap */
+void *heap_pop(struct Heap *h);
+
+/** Return topmost object in heap */
+void *heap_top(struct Heap *h);
+
+/** Remove and return any object from heap by index */
+void *heap_remove(struct Heap *h, unsigned pos);
+
+/**
+ * Reserve room for more elements.
+ *
+ * Returns false if allocation failed.
+ */
+bool heap_reserve(struct Heap *h, unsigned extra);
+
+#endif
+