Will be replaces by the "binaryheap.[ch]" from Abhijit once its been reviewed.
---
 src/backend/lib/Makefile     |   3 +-
 src/backend/lib/simpleheap.c | 255 +++++++++++++++++++++++++++++++++++++++++++
 src/include/lib/simpleheap.h |  91 +++++++++++++++
 3 files changed, 348 insertions(+), 1 deletion(-)
 create mode 100644 src/backend/lib/simpleheap.c
 create mode 100644 src/include/lib/simpleheap.h

diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile
index 98ce3d7..c2bc5ba 100644
--- a/src/backend/lib/Makefile
+++ b/src/backend/lib/Makefile
@@ -12,6 +12,7 @@ subdir = src/backend/lib
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = ilist.o stringinfo.o
+
+OBJS = ilist.o simpleheap.o stringinfo.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/lib/simpleheap.c b/src/backend/lib/simpleheap.c
new file mode 100644
index 0000000..825d0a8
--- /dev/null
+++ b/src/backend/lib/simpleheap.c
@@ -0,0 +1,255 @@
+/*-------------------------------------------------------------------------
+ *
+ * simpleheap.c
+ *	  A simple binary heap implementaion
+ *
+ * Portions Copyright (c) 2012, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/lib/simpleheap.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <math.h>
+
+#include "lib/simpleheap.h"
+
+static inline int
+simpleheap_left_off(size_t i)
+{
+	return 2 * i + 1;
+}
+
+static inline int
+simpleheap_right_off(size_t i)
+{
+	return 2 * i + 2;
+}
+
+static inline int
+simpleheap_parent_off(size_t i)
+{
+	return floor((i - 1) / 2);
+}
+
+/* sift up */
+static void
+simpleheap_sift_up(simpleheap *heap, size_t node_off);
+
+/* sift down */
+static void
+simpleheap_sift_down(simpleheap *heap, size_t node_off);
+
+static inline void
+simpleheap_swap(simpleheap *heap, size_t a, size_t b)
+{
+	simpleheap_kv swap;
+	swap.value = heap->values[a].value;
+	swap.key = heap->values[a].key;
+
+	heap->values[a].value = heap->values[b].value;
+	heap->values[a].key = heap->values[b].key;
+
+	heap->values[b].key = swap.key;
+	heap->values[b].value = swap.value;
+}
+
+/* sift down */
+static void
+simpleheap_sift_down(simpleheap *heap, size_t node_off)
+{
+	/* manually unrolled tail recursion */
+	while (true)
+	{
+		size_t left_off = simpleheap_left_off(node_off);
+		size_t right_off = simpleheap_right_off(node_off);
+		size_t swap_off = 0;
+
+		/* only one child can violate the heap property after a change */
+
+		/* check left child */
+		if (left_off < heap->size &&
+		    heap->compare(&heap->values[left_off],
+		                  &heap->values[node_off]) < 0)
+		{
+			/* heap condition violated */
+			swap_off = left_off;
+		}
+
+		/* check right child */
+		if (right_off < heap->size &&
+		    heap->compare(&heap->values[right_off],
+		                  &heap->values[node_off]) < 0)
+		{
+			/* heap condition violated */
+
+			/* swap with the smaller child */
+			if (!swap_off ||
+			    heap->compare(&heap->values[right_off],
+			                  &heap->values[left_off]) < 0)
+			{
+				swap_off = right_off;
+			}
+		}
+
+		if (!swap_off)
+		{
+			/* heap condition fullfilled, abort */
+			break;
+		}
+
+		/* swap node with the child violating the property */
+		simpleheap_swap(heap, swap_off, node_off);
+
+		/* recurse, check child subtree */
+		node_off = swap_off;
+	}
+}
+
+/* sift up */
+static void
+simpleheap_sift_up(simpleheap *heap, size_t node_off)
+{
+	/* manually unrolled tail recursion */
+	while (true)
+	{
+		size_t parent_off = simpleheap_parent_off(node_off);
+
+		if (heap->compare(&heap->values[parent_off],
+		                  &heap->values[node_off]) < 0)
+		{
+			/* heap property violated */
+			simpleheap_swap(heap, node_off, parent_off);
+
+			/* recurse */
+			node_off = parent_off;
+		}
+		else
+			break;
+	}
+}
+
+simpleheap*
+simpleheap_allocate(size_t allocate)
+{
+	simpleheap* heap = palloc(sizeof(simpleheap));
+	heap->values = palloc(sizeof(simpleheap_kv) * allocate);
+	heap->size = 0;
+	heap->space = allocate;
+	return heap;
+}
+
+void
+simpleheap_free(simpleheap* heap)
+{
+	pfree(heap->values);
+	pfree(heap);
+}
+
+/* initial building of a heap */
+void
+simpleheap_build(simpleheap *heap)
+{
+	int i;
+
+	for (i = simpleheap_parent_off(heap->size - 1); i >= 0; i--)
+	{
+		simpleheap_sift_down(heap, i);
+	}
+}
+
+/*
+ * Change the
+ */
+void
+simpleheap_change_key(simpleheap *heap, void* key)
+{
+	size_t next_off = 0;
+	int ret;
+	simpleheap_kv* kv;
+
+	heap->values[0].key = key;
+
+	/* no need to do anything if there is only one element */
+	if (heap->size == 1)
+	{
+		return;
+	}
+	else if (heap->size == 2)
+	{
+		next_off = 1;
+	}
+	else
+	{
+		ret = heap->compare(
+			&heap->values[simpleheap_left_off(0)],
+			&heap->values[simpleheap_right_off(0)]);
+
+		if (ret == -1)
+			next_off = simpleheap_left_off(0);
+		else
+			next_off = simpleheap_right_off(0);
+	}
+
+	/*
+	 * compare with the next key. If were still smaller we can skip
+	 * restructuring heap
+	 */
+	ret = heap->compare(
+		&heap->values[0],
+		&heap->values[next_off]);
+
+	if (ret == -1)
+		return;
+
+	kv = simpleheap_remove_first(heap);
+	simpleheap_add(heap, kv->key, kv->value);
+}
+
+void
+simpleheap_add_unordered(simpleheap* heap, void *key, void *value)
+{
+	if (heap->size + 1 == heap->space)
+		Assert("Cannot resize heaps");
+	heap->values[heap->size].key = key;
+	heap->values[heap->size++].value = value;
+}
+
+void
+simpleheap_add(simpleheap* heap, void *key, void *value)
+{
+	simpleheap_add_unordered(heap, key, value);
+	simpleheap_sift_up(heap, heap->size - 1);
+}
+
+simpleheap_kv*
+simpleheap_first(simpleheap* heap)
+{
+	if (!heap->size)
+		Assert("heap is empty");
+	return &heap->values[0];
+}
+
+
+simpleheap_kv*
+simpleheap_remove_first(simpleheap* heap)
+{
+	if (heap->size == 0)
+		Assert("heap is empty");
+
+	if (heap->size == 1)
+	{
+		heap->size--;
+		return &heap->values[0];
+	}
+
+	simpleheap_swap(heap, 0, heap->size - 1);
+	simpleheap_sift_down(heap, 0);
+
+	heap->size--;
+	return &heap->values[heap->size];
+}
diff --git a/src/include/lib/simpleheap.h b/src/include/lib/simpleheap.h
new file mode 100644
index 0000000..ab2d2ea
--- /dev/null
+++ b/src/include/lib/simpleheap.h
@@ -0,0 +1,91 @@
+/*
+ * simpleheap.h
+ *
+ * A simple binary heap implementation
+ *
+ * Portions Copyright (c) 2012, PostgreSQL Global Development Group
+ *
+ * src/include/lib/simpleheap.h
+ */
+
+#ifndef SIMPLEHEAP_H
+#define SIMPLEHEAP_H
+
+typedef struct simpleheap_kv
+{
+	void* key;
+	void* value;
+} simpleheap_kv;
+
+typedef struct simpleheap
+{
+	size_t size;
+	size_t space;
+	/*
+	 * Has to return:
+	 * -1 iff a < b
+	 * 0 iff a == b
+	 * +1 iff a > b
+	 */
+	int (*compare)(simpleheap_kv* a, simpleheap_kv* b);
+
+	simpleheap_kv *values;
+} simpleheap;
+
+simpleheap*
+simpleheap_allocate(size_t capacity);
+
+void
+simpleheap_free(simpleheap* heap);
+
+/*
+ * Add values without enforcing the heap property.
+ *
+ * simpleheap_build has to be called before relying on anything that needs a
+ * valid heap. This is mostly useful for initially filling a heap and staying
+ * in O(n) instead of O(n log n).
+ */
+void
+simpleheap_add_unordered(simpleheap* heap, void *key, void *value);
+
+/*
+ * Insert key/value pair
+ *
+ * O(log n)
+ */
+void
+simpleheap_add(simpleheap* heap, void *key, void *value);
+
+/*
+ * Returns the first element as indicated by comparisons of the ->compare()
+ * operator
+ *
+ * O(1)
+ */
+simpleheap_kv*
+simpleheap_first(simpleheap* heap);
+
+/*
+ * Returns and removes the first element as indicated by comparisons of the
+ * ->compare() operator
+ *
+ * O(log n)
+ */
+simpleheap_kv*
+simpleheap_remove_first(simpleheap* heap);
+
+void
+simpleheap_change_key(simpleheap *heap, void* newkey);
+
+
+/*
+ * make the heap fullfill the heap condition. Only needed if elements were
+ * added with simpleheap_add_unordered()
+ *
+ * O(n)
+ */
+void
+simpleheap_build(simpleheap *heap);
+
+
+#endif //SIMPLEHEAP_H
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to