Skip to content
Permalink
Browse files
Initial import
  • Loading branch information
rnewson committed Jan 30, 2019
0 parents commit 151c9bc8de819b5cdb90b3cc57786c37c4991f00
Showing 13 changed files with 1,679 additions and 0 deletions.
@@ -0,0 +1,8 @@
.hqueue.dev
*.o
*.beam
*.so
.eunit
erl_crash.dump
rebar

@@ -0,0 +1,28 @@
REBAR?=rebar

all: build


clean:
$(REBAR) clean
rm -rf .eunit
rm -f test/*.beam
rm -rf priv/*.so
rm -f c_src/valgrind_sample


distclean: clean
git clean -fxd


build:
$(REBAR) compile


check: build
$(REBAR) eunit

check-valgrind:
cc -I c_src/ -g -Wall -Werror c_src/hqueue.c c_src/valgrind_sample.c -o c_src/valgrind_sample
valgrind --leak-check=yes c_src/valgrind_sample

0 README
Empty file.
@@ -0,0 +1,318 @@
// 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.

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "hqueue.h"


struct hqueue
{
int version;
uint32_t idx;
uint32_t max_elems;
uint32_t heap_size;
hqnode_t* heap; // one based index
};


struct hqnode
{
double priority;
void* value;
};


static inline void
hqueue_exchange(hqueue_t* hqueue, int i, int j)
{
hqnode_t tmp;

tmp = hqueue->heap[i];
hqueue->heap[i] = hqueue->heap[j];
hqueue->heap[j] = tmp;
return;
}


static inline int
hqueue_less(hqueue_t* hqueue, int i, int j)
{
return hqueue->heap[i].priority < hqueue->heap[j].priority;
}


static void
hqueue_fix_up(hqueue_t* hqueue, int k)
{
while(k > 1 && hqueue_less(hqueue, k/2, k)) {
hqueue_exchange(hqueue, k/2, k);
k = k/2;
}
return;
}


static void
hqueue_fix_down(hqueue_t* hqueue, int k)
{
int j;
int n = hqueue->idx;

while(2*k <= n) {
j = 2*k;
if(j < n && hqueue_less(hqueue, j, j+1)) {
j++;
}
if(!hqueue_less(hqueue, k, j)) {
break;
}
hqueue_exchange(hqueue, k, j);
k = j;
}
return;
}


hqueue_t*
hqueue_new(uint32_t max_elems, uint32_t heap_size)
{
hqueue_t* hqueue = NULL;
size_t total_heap_size;

if(max_elems == 0 || heap_size == 0) {
return NULL;
}

if(max_elems < heap_size) {
heap_size = max_elems;
}

hqueue = HQUEUE_ALLOC(sizeof(hqueue_t));
if(hqueue == NULL) {
return NULL;
}

memset(hqueue, '\0', sizeof(hqueue_t));
hqueue->version = HQ_VERSION;
hqueue->max_elems = max_elems;
hqueue->heap_size = heap_size;
hqueue->idx = 0;

total_heap_size = sizeof(hqnode_t) * (hqueue->heap_size+1);

hqueue->heap = (hqnode_t*) HQUEUE_ALLOC(total_heap_size);

if(hqueue->heap == NULL ) {
HQUEUE_FREE(hqueue);
return NULL;
}

memset(hqueue->heap, '\0', total_heap_size);

return hqueue;
}


void
hqueue_free(hqueue_t* hqueue)
{
HQUEUE_FREE(hqueue->heap);
HQUEUE_FREE(hqueue);

return;
}


void
hqueue_free2(hqueue_t* hqueue, void (*free_node)(void* node))
{
uint32_t i;

for(i = 1; i < hqueue->heap_size + 1; i++) {
if(i <= hqueue->idx) {
free_node(hqueue->heap[i].value);
} else {
assert(hqueue->heap[i].value == NULL && "inactive elements must be NULL");
}
}

hqueue_free(hqueue);

return;
}


// Extraction order is undefined for entries with duplicate priorities
int
hqueue_extract_max(hqueue_t* hqueue, double* priority, void** value)
{
if(hqueue->idx <= 0) {
return 0;
}

hqueue_exchange(hqueue, 1, hqueue->idx);

*priority = hqueue->heap[hqueue->idx].priority;
*value = hqueue->heap[hqueue->idx].value;

hqueue->heap[hqueue->idx].value = NULL;

hqueue->idx--; // heap uses one based index, so we decrement after
hqueue_fix_down(hqueue, 1);

return 1;
}


void
hqueue_get_elem(hqueue_t* hqueue, uint32_t idx, double *priority, void** value)
{
*priority = hqueue->heap[idx].priority;
*value = hqueue->heap[idx].value;

return;
}


static int
hqueue_maybe_resize(hqueue_t* hqueue)
{
uint32_t min_resize;

if(hqueue->idx + 1 > hqueue->heap_size) {
if(hqueue->idx * HQ_SCALE_FACTOR > hqueue->max_elems) {
min_resize = hqueue->max_elems;
} else {
min_resize = hqueue->idx * HQ_SCALE_FACTOR;
}
return hqueue_resize_heap(hqueue, min_resize);
}

return 1;
}


int
hqueue_insert(hqueue_t* hqueue, double priority, void* value)
{
if(hqueue->idx >= hqueue->max_elems) {
return 0;
}

if(!hqueue_maybe_resize(hqueue)) {
return 0;
}

hqueue->idx++; // heap uses one based index, so we increment first
hqueue->heap[hqueue->idx].priority = priority;
hqueue->heap[hqueue->idx].value = value;

hqueue_fix_up(hqueue, hqueue->idx);

return 1;
}


uint32_t
hqueue_size(hqueue_t* hqueue)
{
return hqueue->idx;
}


uint32_t
hqueue_heap_size(hqueue_t* hqueue)
{
return hqueue->heap_size;
}


uint32_t
hqueue_max_elems(hqueue_t* hqueue)
{
return hqueue->max_elems;
}


void
hqueue_scale_by(hqueue_t* hqueue, double factor)
{
uint32_t i;

for(i = 1; i <= hqueue->idx && i <= hqueue->heap_size; i++) {
hqueue->heap[i].priority *= factor;
}

return;
}


uint32_t
hqueue_resize_heap(hqueue_t* hqueue, uint32_t new_heap_size)
{
uint32_t old_heap_size;
size_t total_heap_size;
hqnode_t* tmp_heap;
uint32_t i;

if(hqueue->idx > new_heap_size) {
return 0;
}

total_heap_size = sizeof(hqnode_t) * (new_heap_size+1);
old_heap_size = hqueue->heap_size;

if((tmp_heap = (hqnode_t*) HQUEUE_ALLOC(total_heap_size)) == NULL) {
return 0;
}

memset(tmp_heap, '\0', total_heap_size);

for(i = 1; i <= hqueue->idx && i <= old_heap_size; i++) {
if(i <= hqueue->idx) {
tmp_heap[i] = hqueue->heap[i];
hqueue->heap[i].value = NULL;
} else {
assert(hqueue->heap[i].value == NULL &&
"unexpected NULL element during heap resize");
}
}

HQUEUE_FREE(hqueue->heap);
hqueue->heap = tmp_heap;
hqueue->heap_size = new_heap_size;

return old_heap_size;
}


int
hqueue_set_max_elems(hqueue_t* hqueue, uint32_t new_max_elems)
{
uint32_t old_max_elems;

if(hqueue->heap_size > new_max_elems) {
if(!hqueue_resize_heap(hqueue, new_max_elems)) {
return 0;
}
}

old_max_elems = hqueue->max_elems;
hqueue->max_elems = new_max_elems;

return old_max_elems;
}

0 comments on commit 151c9bc

Please sign in to comment.