An APR like implementation of heap structure
A heap structure is a complete tree where every node has a key more extreme (greater or less) than or equal to the key of its parent. Usually understood to be a binary heap.
For me, its main purpose is to implement a priority queue.
I wrote this to train at using thread and pool mechanisms of the APR library.
Download napr_heap.h
Read napr_heap.h
- /*
- * Copyright (C) 2007 François Pesce : francois.pesce (at) gmail (dot) com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #ifndef NAPR_HEAP_H
- #define NAPR_HEAP_H
- typedef struct napr_heap_t napr_heap_t;
- typedef int (napr_heap_cmp_callback_fn_t) (const void *, const void *);
- typedef void (napr_heap_display_callback_fn_t) (const void *);
- typedef void (napr_heap_del_callback_fn_t) (void *);
- #ifdef HAVE_APR
- #include <apr_pools.h>
- /**
- * Return the allocator associated to the heap, thus you can allow elements
- * that will be automatically freed when the heap will be.
- * @param heap The heap you are working with.
- * @return Return a pointer to the allcator of type apr_pool_t.
- */
- apr_pool_t *napr_heap_get_allocator(const napr_heap_t *heap);
- /* APR_POOL_DECLARE_ACCESSOR(heap); */
- /**
- * Make a new heap structure, a heap is a structure that is able to return the
- * smallest (or highest, according to the way you compare data) element of its
- * set, in a complexity of O(lg n) the same as the complexity to insert a
- * random element.
- * @param pool The associated pool.
- * @param cmp The function that compare two elements to return the smallest.
- * @return Return a pointer to a newly allocated heap NULL if an error occured.
- */
- napr_heap_t *napr_heap_make(apr_pool_t *pool, napr_heap_cmp_callback_fn_t *cmp);
- /**
- * Re-entrant (Thread safe) version of napr_heap_make.
- * @param pool The associated pool.
- * @param cmp The function that compare two elements to return the smallest.
- * @return Return a pointer to a newly allocated heap NULL if an error occured.
- */
- napr_heap_t *napr_heap_make_r(apr_pool_t *pool, napr_heap_cmp_callback_fn_t *cmp);
- #else /* !HAVE_APR */
- /**
- * Make a new heap structure, a heap is a structure that is able to return the
- * smallest (or highest, according to the way you compare data) element of its
- * set, in a complexity of O(lg n) the same as the complexity to insert a
- * random element.
- * @param cmp The function that compare two elements to return the smallest.
- * @param del The function that destroy (de-allocate) an element.
- * @return Return a pointer to a newly allocated heap NULL if an error occured.
- */
- napr_heap_t *napr_heap_make(napr_heap_cmp_callback_fn_t *cmp, napr_heap_del_callback_fn_t *del);
- /**
- * Re-entrant (Thread safe) version of napr_heap_make.
- * @param cmp The function that compare two elements to return the smallest.
- * @param del The function that destroy (de-allocate) an element.
- * @return Return a pointer to a newly allocated heap NULL if an error occured.
- */
- napr_heap_t *napr_heap_make_r(napr_heap_cmp_callback_fn_t *cmp, napr_heap_del_callback_fn_t *del);
- #endif /* HAVE_APR */
- /**
- * Deallocate the heap;(NB: if the heap is using apr_pool_t (HAVE_APR macro
- * defined), then it will deallocate elements that have been allocated using
- * the heap allocator, otherwise the function del is used on each element.
- * @param heap The heap you are working with.
- * @return nothing.
- */
- void napr_heap_destroy(napr_heap_t *heap);
- /**
- * Insert an element in the heap.
- * @param heap The heap you are working with.
- * @param datum The datum you want to insert.
- * @return 0 if no error occured, -1 otherwise.
- */
- int napr_heap_insert(napr_heap_t *heap, void *datum);
- /**
- * Extract the highest (or the lowest using cmp function) element in the heap,
- * remove it and return it.
- * @param heap The heap you are working with.
- * @return The highest (or lowest according to cmp function) element of the
- * heap, NULL if the heap is empty.
- */
- void *napr_heap_extract(napr_heap_t *heap);
- /**
- * Get the nth element element in the heap.
- * @param heap The heap you are working with.
- * @param n The index of the tree (take the nth element you encounter in a
- * breadth first traversal of a binary tree)
- * @return A pointer on the nth element of the heap, NULL if there's no
- * such element.
- * @remark if you modify the part of this element that is used in the
- * comparation function, you're doing something really bad!
- */
- void *napr_heap_get_nth(const napr_heap_t *heap, unsigned int n);
- /**
- * Get the nth element (to a const pointer because you can't extract it until
- * it is the highest or the lowest using cmp function) element in the heap.
- * @param heap The heap you are working with.
- * @param datum The adress of the datum you want to set.
- * @param n The index of the tree (take the nth element you encounter in a
- * breadth first traversal of a binary tree)
- * @return 0 if no error occured, -1 otherwise.
- */
- unsigned int napr_heap_size(const napr_heap_t *heap);
- /**
- * Re-entrant (Thread safe) version of napr_heap_insert, heap must have been
- * initialized with napr_heap_make_r.
- * @param heap The heap you are working with.
- * @param datum The datum you want to insert.
- * @return 0 if no error occured, -1 otherwise.
- */
- int napr_heap_insert_r(napr_heap_t *heap, void *datum);
- /**
- * Re-entrant (Thread safe) version of napr_heap_extract, heap must have been
- * initialized with napr_heap_make_r.
- * @param heap The heap you are working with.
- * @return The highest (or lowest according to cmp function) element of the
- * heap, NULL if the heap is empty.
- */
- void *napr_heap_extract_r(napr_heap_t *heap);
- /**
- * Attach a callback to the heap in order to display the data stored.
- * @param heap The heap you are working with.
- * @param display A callback used to display content of a datum.
- */
- void napr_heap_set_display_cb(napr_heap_t *heap, napr_heap_display_callback_fn_t display);
- /**
- * Display the binary tree using the display callback.
- * @param heap The heap you are working with.
- */
- void napr_heap_display(const napr_heap_t *heap);
- #endif /* NAPR_HEAP_H */
Download napr_heap.c
Read napr_heap.c
- /*
- * Copyright (C) 2007 François Pesce : francois.pesce (at) gmail (dot) com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #ifndef HAVE_APR
- #include <stdlib.h>
- #include <pthread.h>
- #else
- #include <apr_thread_mutex.h>
- #endif
- #include <string.h>
- #include "napr_heap.h"
- #define INITIAL_MAX 256
- #define NAPR_HEAP_PARENT(position) (((position) - 1) >> 1)
- #define NAPR_HEAP_LEFT(position) (((position) << 1) + 1)
- #define NAPR_HEAP_RIGHT(position) (((position) + 1) << 1)
- struct napr_heap_t
- {
- #ifdef HAVE_APR
- apr_pool_t *pool;
- apr_thread_mutex_t *mutex;
- #else
- pthread_mutex_t mutex;
- #endif
- void **tree;
- napr_heap_cmp_callback_fn_t *cmp;
- napr_heap_display_callback_fn_t *display;
- #ifndef HAVE_APR /* !HAVE_APR */
- /* Then we may specify a function to deallocate data */
- napr_heap_del_callback_fn_t *del;
- #endif
- unsigned int count, max;
- int mutex_set; /* true (i.e. 1) if napr_heap_make_r has been
- called instead of non-reentrant function */
- };
- #ifdef HAVE_APR
- /* APR_POOL_IMPLEMENT_ACCESSOR(heap); */
- apr_pool_t *napr_heap_get_allocator(const napr_heap_t *heap)
- {
- return heap->pool;
- }
- #endif
- napr_heap_t *napr_heap_make(
- #ifdef HAVE_APR
- apr_pool_t *pool,
- #endif
- napr_heap_cmp_callback_fn_t *cmp
- #ifndef HAVE_APR /* !HAVE_APR */
- , napr_heap_del_callback_fn_t *del
- #endif
- )
- {
- napr_heap_t *heap = NULL;;
- #ifdef HAVE_APR
- apr_pool_t *local_pool;
- if (APR_SUCCESS == (apr_pool_create(&local_pool, pool))) {
- heap = apr_palloc(local_pool, sizeof(napr_heap_t));
- heap->pool = local_pool;
- heap->tree = apr_pcalloc(local_pool, sizeof(void *) * INITIAL_MAX);
- }
- #else /* !HAVE_APR */
- if (NULL != (heap = malloc(sizeof(napr_heap_t)))) {
- heap->del = del;
- if (NULL == (heap->tree = calloc(INITIAL_MAX, sizeof(void *)))) {
- free(heap);
- heap = NULL;
- }
- }
- #endif
- if (NULL != heap) {
- heap->max = INITIAL_MAX;
- heap->count = 0;
- heap->cmp = cmp;
- heap->mutex_set = 0;
- #ifdef HAVE_APR
- heap->mutex = NULL;
- #else
- memset(&(heap->mutex), 0, sizeof(pthread_mutex_t));
- #endif
- }
- return heap;
- }
- void napr_heap_destroy(napr_heap_t *heap)
- {
- #ifdef HAVE_APR
- apr_pool_destroy(heap->pool);
- #else /* !HAVE_APR */
- if (NULL != heap) {
- if (NULL != heap->del && NULL != heap->tree) {
- unsigned int i;
- for (i = 0; i < heap->count; i++) {
- heap->del(heap->tree[i]);
- }
- }
- free(heap->tree);
- free(heap);
- }
- #endif
- }
- int napr_heap_insert(napr_heap_t *heap, void *datum)
- {
- void **tmp;
- unsigned int ipos, ppos;
- if (heap->max <= heap->count) {
- /*
- * reallocation by power of 2:
- */
- unsigned int new_max;
- for (new_max = 1; new_max <= heap->max; new_max *= 2);
- #ifdef HAVE_APR
- tmp = apr_palloc(heap->pool, new_max * sizeof(void *));
- #else
- tmp = realloc(heap->tree, new_max * sizeof(void *));
- #endif
- if (NULL != tmp) {
- #ifdef HAVE_APR
- memcpy(tmp, (heap->tree), (heap->count) * sizeof(void *));
- #endif
- memset((tmp + (heap->count)), 0, (new_max - (heap->count + 1)) * sizeof(void *));
- heap->tree = tmp;
- heap->max = new_max;
- }
- else {
- heap->tree = NULL;
- return -1;
- }
- }
- /*
- * insertion of the datum after the last one of the tree...
- */
- heap->tree[heap->count] = datum;
- ipos = heap->count;
- ppos = NAPR_HEAP_PARENT(ipos);
- while (ipos > 0 && (heap->cmp(heap->tree[ppos], heap->tree[ipos]) < 0)) {
- /*
- * Swap the value ...
- */
- tmp = heap->tree[ppos];
- heap->tree[ppos] = heap->tree[ipos];
- heap->tree[ipos] = tmp;
- ipos = ppos;
- ppos = NAPR_HEAP_PARENT(ipos);
- }
- heap->count++;
- return 0;
- }
- void *napr_heap_extract(napr_heap_t *heap)
- {
- void *ret = NULL, *tmp;
- unsigned int ipos, rpos, lpos, mpos;
- if ((0 != heap->count) && (NULL != heap->tree)) {
- /* keep the value to return */
- ret = heap->tree[0];
- /* It works for count == 1 too (just think about it) */
- heap->tree[0] = heap->tree[heap->count - 1];
- heap->tree[heap->count - 1] = NULL;
- heap->count--;
- ipos = 0;
- while (1) {
- lpos = NAPR_HEAP_LEFT(ipos);
- rpos = NAPR_HEAP_RIGHT(ipos);
- if (lpos < heap->count) {
- if (heap->cmp(heap->tree[lpos], heap->tree[ipos]) > 0) {
- mpos = lpos;
- }
- else {
- mpos = ipos;
- }
- if ((rpos < heap->count) && (heap->cmp(heap->tree[rpos], heap->tree[mpos])) > 0) {
- mpos = rpos;
- }
- }
- else {
- mpos = ipos;
- }
- if (mpos != ipos) {
- /*
- * Swap the choosen children with the current node
- */
- tmp = heap->tree[mpos];
- heap->tree[mpos] = heap->tree[ipos];
- heap->tree[ipos] = tmp;
- ipos = mpos;
- }
- else {
- break;
- }
- }
- }
- return ret;
- }
- void *napr_heap_get_nth(const napr_heap_t *heap, unsigned int n)
- {
- if ((n < heap->count) && (NULL != heap->tree))
- return heap->tree[n];
- else
- return NULL;
- }
- unsigned int napr_heap_size(const napr_heap_t *heap)
- {
- return heap->count;
- }
- /*
- * Reentrant versions of previous functions.
- */
- napr_heap_t *napr_heap_make_r(
- #ifdef HAVE_APR
- apr_pool_t *pool,
- #endif
- napr_heap_cmp_callback_fn_t *cmp
- #ifndef HAVE_APR /* !HAVE_APR */
- , napr_heap_del_callback_fn_t *del
- #endif
- )
- {
- napr_heap_t *heap;
- if (NULL != (heap = napr_heap_make(
- #ifdef HAVE_APR
- pool,
- #endif
- cmp
- #ifndef HAVE_APR /* !HAVE_APR */
- , del
- #endif
- ))) {
- #ifdef HAVE_APR
- if (APR_SUCCESS != apr_thread_mutex_create(&(heap->mutex), APR_THREAD_MUTEX_DEFAULT, pool))
- heap = NULL;
- #else
- if (0 > pthread_mutex_init(&(heap->mutex), NULL)) {
- free(heap->tree);
- free(heap);
- heap = NULL;
- }
- #endif
- }
- heap->mutex_set = 1;
- return heap;
- }
- int napr_heap_insert_r(napr_heap_t *heap, void *datum)
- {
- int rc;
- if (1 == heap->mutex_set) {
- #ifdef HAVE_APR
- if (APR_SUCCESS == (rc = apr_thread_mutex_lock(heap->mutex))) {
- if (0 == (rc = napr_heap_insert(heap, datum)))
- rc = apr_thread_mutex_unlock(heap->mutex);
- }
- #else
- if (0 == (rc = pthread_mutex_lock(&heap->mutex))) {
- if (0 == (rc = napr_heap_insert(heap, datum)))
- rc = pthread_mutex_unlock(&heap->mutex);
- }
- #endif
- }
- else
- rc = -1;
- return rc;
- }
- void *napr_heap_extract_r(napr_heap_t *heap)
- {
- void *result;
- result = NULL;
- if (1 == heap->mutex_set) {
- #ifdef HAVE_APR
- if (APR_SUCCESS == apr_thread_mutex_lock(heap->mutex)) {
- if (NULL != (result = napr_heap_extract(heap)))
- if (APR_SUCCESS != apr_thread_mutex_unlock(heap->mutex)) {
- result = NULL;
- }
- }
- #else
- if (0 == pthread_mutex_lock(&heap->mutex)) {
- if (NULL != (result = napr_heap_extract(heap)))
- if (0 != pthread_mutex_unlock(&heap->mutex))
- result = NULL;
- }
- #endif
- }
- return result;
- }
- void napr_heap_set_display_cb(napr_heap_t *heap, napr_heap_display_callback_fn_t display)
- {
- heap->display = display;
- }
- void napr_heap_display(const napr_heap_t *heap)
- {
- unsigned int i;
- for (i = 0; i < heap->count; i++) {
- if (((i - 1) % 2) == 0) {
- }
- heap->display(heap->tree[i]);
- }
- fflush(stdout);
- }