integrate priority queue: lumiera namespace prefix; unit test pass

This commit is contained in:
Fischlurch 2013-09-13 05:44:58 +02:00
parent fc3cc1bc98
commit 7f68bc9020
6 changed files with 98 additions and 466 deletions

View file

@ -31,12 +31,12 @@
PriQueue
priqueue_init (PriQueue self,
size_t element_size,
priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn)
LumieraPriQueue
lumiera_priqueue_init (LumieraPriQueue self,
size_t element_size,
lumiera_priqueue_cmp_fn cmpfn,
lumiera_priqueue_copy_fn copyfn,
lumiera_priqueue_resize_fn resizefn)
{
TRACE (priqueue, "%p", self);
@ -55,7 +55,7 @@ priqueue_init (PriQueue self,
self->copyfn = copyfn;
if (!resizefn)
resizefn = priqueue_clib_resize;
resizefn = lumiera_priqueue_clib_resize;
self->resizefn = resizefn;
self = self->resizefn (self);
@ -65,8 +65,8 @@ priqueue_init (PriQueue self,
PriQueue
priqueue_destroy (PriQueue self)
LumieraPriQueue
lumiera_priqueue_destroy (LumieraPriQueue self)
{
TRACE (priqueue, "%p", self);
if (self)
@ -80,8 +80,8 @@ priqueue_destroy (PriQueue self)
PriQueue
priqueue_reserve (PriQueue self, unsigned elements)
LumieraPriQueue
lumiera_priqueue_reserve (LumieraPriQueue self, unsigned elements)
{
TRACE (priqueue, "%p %d", self, elements);
if (self)
@ -105,8 +105,8 @@ priqueue_reserve (PriQueue self, unsigned elements)
PriQueue
priqueue_clib_resize (PriQueue self)
LumieraPriQueue
lumiera_priqueue_clib_resize (LumieraPriQueue self)
{
if (self)
{
@ -168,14 +168,14 @@ priqueue_clib_resize (PriQueue self)
static inline void*
pq_index (PriQueue self, unsigned nth)
pq_index (LumieraPriQueue self, unsigned nth)
{
return (char*)self->queue+self->element_size*nth;
}
static inline void
pq_up (PriQueue self, void* tmp)
pq_up (LumieraPriQueue self, void* tmp)
{
unsigned i = self->used;
unsigned p = i/2;
@ -191,8 +191,8 @@ pq_up (PriQueue self, void* tmp)
PriQueue
priqueue_insert (PriQueue self, void* element)
LumieraPriQueue
lumiera_priqueue_insert (LumieraPriQueue self, void* element)
{
TRACE (priqueue, "%p: insert %p", self, element);
@ -211,7 +211,7 @@ priqueue_insert (PriQueue self, void* element)
static inline void
pq_down (PriQueue self, void* tmp)
pq_down (LumieraPriQueue self, void* tmp)
{
if (!self->used)
return;
@ -234,8 +234,8 @@ pq_down (PriQueue self, void* tmp)
}
PriQueue
priqueue_remove (PriQueue self)
LumieraPriQueue
lumiera_priqueue_remove (LumieraPriQueue self)
{
TRACE (priqueue, "%p: remove", self);
@ -253,138 +253,3 @@ priqueue_remove (PriQueue self)
return self;
}
#ifdef PRIQUEUE_TEST /* testing */
#include <stdio.h>
void
nobug_priqueue_invariant (PriQueue self, int depth, const struct nobug_context invariant_context, void* extra)
{
intptr_t n = 1+(intptr_t)extra;
intptr_t m=n+n;
if (self && depth && m <= self->used)
{
INVARIANT_ASSERT (self->cmpfn (pq_index(self, n-1), pq_index(self, m-1)) <= 0, "%d %d", (int)n-1, (int)m-2);
nobug_priqueue_invariant (self, depth-1, invariant_context, (void*)m-1);
if (m<self->used)
{
INVARIANT_ASSERT (self->cmpfn (pq_index(self, n-1), pq_index(self, m)) <= 0, "%d %d", (int)n-1, (int)m-1);
nobug_priqueue_invariant (self, depth-1, invariant_context, (void*)m);
}
}
}
static int
cmpintptr (void* a, void* b)
{
return *(int*)a - *(int*)b;
}
NOBUG_DEFINE_FLAG (priqueue_test);
int main()
{
NOBUG_INIT;
NOBUG_INIT_FLAG (priqueue_test);
priqueue pq;
PriQueue r;
int data;
r = priqueue_init (&pq,
sizeof (int),
cmpintptr,
NULL,
NULL);
ENSURE (r==&pq);
#if 1
data = 10;
r = priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
#endif
#if 0
data = 5;
r = priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
#endif
#if 0
data = 15;
r = priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
data = 20;
r = priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
#endif
#if 1
for (int i = 0; i < 1000000; ++i)
{
data = i;
r = priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
}
#endif
#if 1
for (int i = 0; i < 1000000; ++i)
{
data = rand()%1000000;
r = priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
}
#endif
NOBUG_INVARIANT(priqueue, &pq, 100, NULL);
#if 1
for (int i = 0; pq.used; ++i)
{
TRACE (priqueue_test, "TOP: %d", *(int*)priqueue_peek (&pq));
r = priqueue_remove (&pq);
ENSURE (r==&pq);
}
#endif
r = priqueue_destroy (&pq);
ENSURE (r==&pq);
return 0;
}
#endif

View file

@ -47,22 +47,22 @@
#include "lib/error.h"
typedef struct priqueue_struct priqueue;
typedef priqueue* PriQueue;
typedef struct lumiera_priqueue_struct lumiera_priqueue;
typedef lumiera_priqueue* LumieraPriQueue;
/** function to compare 2 keys, mandatory */
typedef int (*priqueue_cmp_fn)(void*, void*);
typedef int (*lumiera_priqueue_cmp_fn)(void*, void*);
/** function to copy elements, optional.
* Has the same prototype as memcpy which is used by default */
typedef void *(*priqueue_copy_fn)(void *dest, const void *src, size_t n);
typedef void *(*lumiera_priqueue_copy_fn)(void *dest, const void *src, size_t n);
/** called when used hits the high or low water marks and initially by priqueue_init() (with queue==NULL)
* or at priqueue_destroy (with queue != NULL, used elements == 0), optional.
*
* @note must be aware of resizes by more than just incrementing the queue by one
*/
typedef PriQueue (*priqueue_resize_fn) (PriQueue);
typedef LumieraPriQueue (*lumiera_priqueue_resize_fn) (LumieraPriQueue);
/**
@ -71,7 +71,7 @@ typedef PriQueue (*priqueue_resize_fn) (PriQueue);
* which has to reallocate the queue and update
* the high and low water marks.
*/
struct priqueue_struct
struct lumiera_priqueue_struct
{
void* queue;
size_t element_size;
@ -79,10 +79,10 @@ struct priqueue_struct
unsigned high_water; ///< elements in the queue
unsigned low_water; ///< size for shrinking the queue
priqueue_cmp_fn cmpfn;
priqueue_copy_fn copyfn;
lumiera_priqueue_cmp_fn cmpfn;
lumiera_priqueue_copy_fn copyfn;
priqueue_resize_fn resizefn;
lumiera_priqueue_resize_fn resizefn;
};
@ -90,17 +90,17 @@ struct priqueue_struct
PriQueue
priqueue_init (PriQueue self,
size_t element_size,
priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn);
LumieraPriQueue
lumiera_priqueue_init (LumieraPriQueue self,
size_t element_size,
lumiera_priqueue_cmp_fn cmpfn,
lumiera_priqueue_copy_fn copyfn,
lumiera_priqueue_resize_fn resizefn);
PriQueue
priqueue_destroy (PriQueue self);
LumieraPriQueue
lumiera_priqueue_destroy (LumieraPriQueue self);
/**
@ -108,8 +108,8 @@ priqueue_destroy (PriQueue self);
* and then sets low_water to 0, disabling shrinking
* @note on overflow resize will re-enable low_water if it is not aware of this
*/
PriQueue
priqueue_reserve (PriQueue self, unsigned elements);
LumieraPriQueue
lumiera_priqueue_reserve (LumieraPriQueue self, unsigned elements);
/**
@ -118,8 +118,8 @@ priqueue_reserve (PriQueue self, unsigned elements);
* doubles this when the high water mark is hit,
* shrinks at high_water/8-8 (that is, 64 is the minimum size)
*/
PriQueue
priqueue_clib_resize (PriQueue self);
LumieraPriQueue
lumiera_priqueue_clib_resize (LumieraPriQueue self);
@ -129,8 +129,8 @@ priqueue_clib_resize (PriQueue self);
* the element will be copied
* @return \c NULL on error
*/
PriQueue
priqueue_insert (PriQueue self, void* element);
LumieraPriQueue
lumiera_priqueue_insert (LumieraPriQueue self, void* element);
/**
@ -139,7 +139,7 @@ priqueue_insert (PriQueue self, void* element);
* as no insert or remove is called
*/
static inline void*
priqueue_peek (PriQueue self)
lumiera_priqueue_peek (LumieraPriQueue self)
{
if (self && self->queue)
return self->queue;
@ -152,8 +152,8 @@ priqueue_peek (PriQueue self)
* removes the topmost element
* @return \c NULL on error (empty queue, resize failure)
*/
PriQueue
priqueue_remove (PriQueue self);
LumieraPriQueue
lumiera_priqueue_remove (LumieraPriQueue self);

View file

@ -38,14 +38,13 @@
#include <string.h>
#include <nobug.h>
NOBUG_DEFINE_FLAG_LIMIT(TEST, LOG_DEBUG);
#define TESTS_BEGIN \
int \
main (int argc, const char** argv) \
{ \
NOBUG_INIT; \
NOBUG_INIT_FLAG (TEST); \
unsigned testcnt=0; \
int ret = 0; \
\

6
tests/15priqueue.tests Normal file
View file

@ -0,0 +1,6 @@
TESTING "Priority Queue" ./test-priqueue
TEST "fill and clear" <<END
return: 0
END

View file

@ -40,7 +40,7 @@ return: 0
END
TEST "C++ plugin test" plugin_exampleplugin_cpp <<END
out: opened 0x.+ global interfaces 0x...
out: opened \S+ global interfaces \S+
out: Hallo Welt!
out: Tschüss schnöde Welt!
out: Hello World!

View file

@ -1,5 +1,5 @@
/*
PriQueue - simple heap based priority queue
TEST_PRIQUEUE - test the heap based priority queue implementation
Copyright (C) Lumiera.org
2011, Christian Thaeter <ct@pipapo.org>
@ -21,254 +21,22 @@
* *****************************************************/
#include "lib/test/test.h"
#include "lib/priqueue.h"
#include "include/logging.h"
#include <stdint.h>
#include <nobug.h>
PriQueue
priqueue_init (PriQueue self,
size_t element_size,
priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn)
{
TRACE (priqueue, "%p", self);
REQUIRE (element_size);
REQUIRE (cmpfn);
if (self)
{
self->queue = NULL;
self->element_size = element_size;
self->used = self->high_water = self->low_water = 0;
self->cmpfn = cmpfn;
if (!copyfn)
copyfn = memcpy;
self->copyfn = copyfn;
if (!resizefn)
resizefn = priqueue_clib_resize;
self->resizefn = resizefn;
self = self->resizefn (self);
}
return self;
}
PriQueue
priqueue_destroy (PriQueue self)
{
TRACE (priqueue, "%p", self);
if (self)
{
WARN_IF (self->used, priqueue, "queue was not empty");
self->used = 0;
self = self->resizefn (self);
}
return self;
}
PriQueue
priqueue_reserve (PriQueue self, unsigned elements)
{
TRACE (priqueue, "%p %d", self, elements);
if (self)
{
if (self->used+elements >= self->high_water)
{
self->used += elements;
self = self->resizefn (self);
if (!self)
{
ERROR (priqueue, "resize failed");
return NULL;
}
self->used -= elements;
}
self->low_water = 0;
}
return self;
}
PriQueue
priqueue_clib_resize (PriQueue self)
{
if (self)
{
if (!self->queue)
{
INFO (priqueue, "%p: initial alloc", self);
self->queue = malloc (64*self->element_size);
ERROR_IF (!self->queue, priqueue, "%p: allocation failed", self);
if (!self->queue)
return NULL;
self->high_water = 64;
}
else
{
if (self->used)
{
if (self->used >= self->high_water)
{
unsigned newwater = self->high_water;
while (self->used >= newwater)
newwater *= 2;
INFO (priqueue, "%p: resize %d -> %d", self, self->high_water, newwater);
void* newqueue = realloc (self->queue, self->element_size * newwater);
ERROR_IF (!newqueue, priqueue, "%p: allocation failed", self);
if (!newqueue)
return NULL;
self->queue = newqueue;
self->high_water = newwater;
self->low_water = self->high_water/8-8;
TRACE (priqueue, "%p: low_water: %d", self, self->low_water);
}
else
{
INFO (priqueue, "%p: shrink %d -> %d", self, self->high_water, (self->low_water+8)*4);
void* newqueue = realloc (self->queue, self->element_size * (self->low_water+8)*4);
ERROR_IF (!newqueue, priqueue, "allocation failed");
if (!newqueue)
return NULL;
self->queue = newqueue;
self->high_water = (self->low_water+8)*4;
self->low_water = self->high_water/8-8;
TRACE (priqueue, "%p: low_water: %d", self, self->low_water);
}
}
else
{
INFO (priqueue, "%p: freeing", self);
free (self->queue);
self->queue = NULL;
}
}
}
return self;
}
/* @note internal helper copied from priqueue.c */
static inline void*
pq_index (PriQueue self, unsigned nth)
pq_index (LumieraPriQueue self, unsigned nth)
{
return (char*)self->queue+self->element_size*nth;
}
static inline void
pq_up (PriQueue self, void* tmp)
{
unsigned i = self->used;
unsigned p = i/2;
while (p && self->cmpfn (tmp, pq_index(self, p-1)) < 0)
{
self->copyfn (pq_index (self, i-1), pq_index (self, p-1), self->element_size);
i=p; p=i/2;
}
self->copyfn (pq_index (self, i-1), tmp, self->element_size);
}
PriQueue
priqueue_insert (PriQueue self, void* element)
{
TRACE (priqueue, "%p: insert %p", self, element);
if (self && self->used >= self->high_water)
self = self->resizefn (self);
if (self)
{
++self->used;
pq_up (self, element);
}
return self;
}
static inline void
pq_down (PriQueue self, void* tmp)
{
if (!self->used)
return;
unsigned i = 1;
while (i <= self->used/2)
{
unsigned n=i+i;
if (n<self->used && self->cmpfn (pq_index(self, n-1), pq_index(self, n)) >= 0)
++n;
if (self->cmpfn (tmp, pq_index(self, n-1)) < 0)
break;
self->copyfn (pq_index (self, i-1), pq_index (self, n-1), self->element_size);
i = n;
}
self->copyfn (pq_index (self, i-1), tmp, self->element_size);
}
PriQueue
priqueue_remove (PriQueue self)
{
TRACE (priqueue, "%p: remove", self);
if (self)
{
if (!self->used)
return NULL;
--self->used;
pq_down (self, pq_index (self, self->used));
if (self->used < self->low_water)
self = self->resizefn (self);
}
return self;
}
#ifdef PRIQUEUE_TEST /* testing */
#include <stdio.h>
void
nobug_priqueue_invariant (PriQueue self, int depth, const struct nobug_context invariant_context, void* extra)
nobug_priqueue_invariant (LumieraPriQueue self, int depth, const struct nobug_context invariant_context, void* extra)
{
intptr_t n = 1+(intptr_t)extra;
@ -294,97 +62,91 @@ cmpintptr (void* a, void* b)
return *(int*)a - *(int*)b;
}
NOBUG_DEFINE_FLAG (priqueue_test);
int main()
{
NOBUG_INIT;
NOBUG_INIT_FLAG (priqueue_test);
priqueue pq;
PriQueue r;
int data;
r = priqueue_init (&pq,
sizeof (int),
cmpintptr,
NULL,
NULL);
TESTS_BEGIN
lumiera_priqueue pq;
LumieraPriQueue r;
int data, prev, curr;
r = lumiera_priqueue_init (&pq,
sizeof (int),
cmpintptr,
NULL,
NULL);
ENSURE (r==&pq);
#if 1
data = 10;
r = priqueue_insert (&pq, &data);
r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
#endif
TRACE (test, "inserted %d", data);
#if 0
data = 5;
r = priqueue_insert (&pq, &data);
r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
#endif
TRACE (test, "inserted %d", data);
#if 0
data = 15;
r = priqueue_insert (&pq, &data);
r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
TRACE (test, "inserted %d", data);
data = 20;
r = priqueue_insert (&pq, &data);
r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
#endif
TRACE (test, "inserted %d", data);
#if 1
for (int i = 0; i < 1000000; ++i)
{
data = i;
r = priqueue_insert (&pq, &data);
r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
TRACE (test, "inserted %d", data);
}
#endif
#if 1
for (int i = 0; i < 1000000; ++i)
{
data = rand()%1000000;
r = priqueue_insert (&pq, &data);
r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data);
TRACE (test, "inserted %d", data);
}
#endif
NOBUG_INVARIANT(priqueue, &pq, 100, NULL);
#if 1
prev = 0;
for (int i = 0; pq.used; ++i)
{
TRACE (priqueue_test, "TOP: %d", *(int*)priqueue_peek (&pq));
r = priqueue_remove (&pq);
curr = *(int*)lumiera_priqueue_peek (&pq);
TRACE (test, "TOP: %d", curr);
CHECK (prev <= curr, "priority ordering broken");
prev = curr;
r = lumiera_priqueue_remove (&pq);
ENSURE (r==&pq);
}
#endif
r = priqueue_destroy (&pq);
r = lumiera_priqueue_destroy (&pq);
ENSURE (r==&pq);
return 0;
}
#endif
TESTS_END