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 LumieraPriQueue
priqueue_init (PriQueue self, lumiera_priqueue_init (LumieraPriQueue self,
size_t element_size, size_t element_size,
priqueue_cmp_fn cmpfn, lumiera_priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn, lumiera_priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn) lumiera_priqueue_resize_fn resizefn)
{ {
TRACE (priqueue, "%p", self); TRACE (priqueue, "%p", self);
@ -55,7 +55,7 @@ priqueue_init (PriQueue self,
self->copyfn = copyfn; self->copyfn = copyfn;
if (!resizefn) if (!resizefn)
resizefn = priqueue_clib_resize; resizefn = lumiera_priqueue_clib_resize;
self->resizefn = resizefn; self->resizefn = resizefn;
self = self->resizefn (self); self = self->resizefn (self);
@ -65,8 +65,8 @@ priqueue_init (PriQueue self,
PriQueue LumieraPriQueue
priqueue_destroy (PriQueue self) lumiera_priqueue_destroy (LumieraPriQueue self)
{ {
TRACE (priqueue, "%p", self); TRACE (priqueue, "%p", self);
if (self) if (self)
@ -80,8 +80,8 @@ priqueue_destroy (PriQueue self)
PriQueue LumieraPriQueue
priqueue_reserve (PriQueue self, unsigned elements) lumiera_priqueue_reserve (LumieraPriQueue self, unsigned elements)
{ {
TRACE (priqueue, "%p %d", self, elements); TRACE (priqueue, "%p %d", self, elements);
if (self) if (self)
@ -105,8 +105,8 @@ priqueue_reserve (PriQueue self, unsigned elements)
PriQueue LumieraPriQueue
priqueue_clib_resize (PriQueue self) lumiera_priqueue_clib_resize (LumieraPriQueue self)
{ {
if (self) if (self)
{ {
@ -168,14 +168,14 @@ priqueue_clib_resize (PriQueue self)
static inline void* static inline void*
pq_index (PriQueue self, unsigned nth) pq_index (LumieraPriQueue self, unsigned nth)
{ {
return (char*)self->queue+self->element_size*nth; return (char*)self->queue+self->element_size*nth;
} }
static inline void static inline void
pq_up (PriQueue self, void* tmp) pq_up (LumieraPriQueue self, void* tmp)
{ {
unsigned i = self->used; unsigned i = self->used;
unsigned p = i/2; unsigned p = i/2;
@ -191,8 +191,8 @@ pq_up (PriQueue self, void* tmp)
PriQueue LumieraPriQueue
priqueue_insert (PriQueue self, void* element) lumiera_priqueue_insert (LumieraPriQueue self, void* element)
{ {
TRACE (priqueue, "%p: insert %p", self, element); TRACE (priqueue, "%p: insert %p", self, element);
@ -211,7 +211,7 @@ priqueue_insert (PriQueue self, void* element)
static inline void static inline void
pq_down (PriQueue self, void* tmp) pq_down (LumieraPriQueue self, void* tmp)
{ {
if (!self->used) if (!self->used)
return; return;
@ -234,8 +234,8 @@ pq_down (PriQueue self, void* tmp)
} }
PriQueue LumieraPriQueue
priqueue_remove (PriQueue self) lumiera_priqueue_remove (LumieraPriQueue self)
{ {
TRACE (priqueue, "%p: remove", self); TRACE (priqueue, "%p: remove", self);
@ -253,138 +253,3 @@ priqueue_remove (PriQueue self)
return 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" #include "lib/error.h"
typedef struct priqueue_struct priqueue; typedef struct lumiera_priqueue_struct lumiera_priqueue;
typedef priqueue* PriQueue; typedef lumiera_priqueue* LumieraPriQueue;
/** function to compare 2 keys, mandatory */ /** 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. /** function to copy elements, optional.
* Has the same prototype as memcpy which is used by default */ * 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) /** 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. * 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 * @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 * which has to reallocate the queue and update
* the high and low water marks. * the high and low water marks.
*/ */
struct priqueue_struct struct lumiera_priqueue_struct
{ {
void* queue; void* queue;
size_t element_size; size_t element_size;
@ -79,10 +79,10 @@ struct priqueue_struct
unsigned high_water; ///< elements in the queue unsigned high_water; ///< elements in the queue
unsigned low_water; ///< size for shrinking the queue unsigned low_water; ///< size for shrinking the queue
priqueue_cmp_fn cmpfn; lumiera_priqueue_cmp_fn cmpfn;
priqueue_copy_fn copyfn; lumiera_priqueue_copy_fn copyfn;
priqueue_resize_fn resizefn; lumiera_priqueue_resize_fn resizefn;
}; };
@ -90,17 +90,17 @@ struct priqueue_struct
PriQueue LumieraPriQueue
priqueue_init (PriQueue self, lumiera_priqueue_init (LumieraPriQueue self,
size_t element_size, size_t element_size,
priqueue_cmp_fn cmpfn, lumiera_priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn, lumiera_priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn); lumiera_priqueue_resize_fn resizefn);
PriQueue LumieraPriQueue
priqueue_destroy (PriQueue self); lumiera_priqueue_destroy (LumieraPriQueue self);
/** /**
@ -108,8 +108,8 @@ priqueue_destroy (PriQueue self);
* and then sets low_water to 0, disabling shrinking * 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 * @note on overflow resize will re-enable low_water if it is not aware of this
*/ */
PriQueue LumieraPriQueue
priqueue_reserve (PriQueue self, unsigned elements); 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, * doubles this when the high water mark is hit,
* shrinks at high_water/8-8 (that is, 64 is the minimum size) * shrinks at high_water/8-8 (that is, 64 is the minimum size)
*/ */
PriQueue LumieraPriQueue
priqueue_clib_resize (PriQueue self); lumiera_priqueue_clib_resize (LumieraPriQueue self);
@ -129,8 +129,8 @@ priqueue_clib_resize (PriQueue self);
* the element will be copied * the element will be copied
* @return \c NULL on error * @return \c NULL on error
*/ */
PriQueue LumieraPriQueue
priqueue_insert (PriQueue self, void* element); lumiera_priqueue_insert (LumieraPriQueue self, void* element);
/** /**
@ -139,7 +139,7 @@ priqueue_insert (PriQueue self, void* element);
* as no insert or remove is called * as no insert or remove is called
*/ */
static inline void* static inline void*
priqueue_peek (PriQueue self) lumiera_priqueue_peek (LumieraPriQueue self)
{ {
if (self && self->queue) if (self && self->queue)
return self->queue; return self->queue;
@ -152,8 +152,8 @@ priqueue_peek (PriQueue self)
* removes the topmost element * removes the topmost element
* @return \c NULL on error (empty queue, resize failure) * @return \c NULL on error (empty queue, resize failure)
*/ */
PriQueue LumieraPriQueue
priqueue_remove (PriQueue self); lumiera_priqueue_remove (LumieraPriQueue self);

View file

@ -38,14 +38,13 @@
#include <string.h> #include <string.h>
#include <nobug.h> #include <nobug.h>
NOBUG_DEFINE_FLAG_LIMIT(TEST, LOG_DEBUG);
#define TESTS_BEGIN \ #define TESTS_BEGIN \
int \ int \
main (int argc, const char** argv) \ main (int argc, const char** argv) \
{ \ { \
NOBUG_INIT; \ NOBUG_INIT; \
NOBUG_INIT_FLAG (TEST); \
unsigned testcnt=0; \ unsigned testcnt=0; \
int ret = 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 END
TEST "C++ plugin test" plugin_exampleplugin_cpp <<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: Hallo Welt!
out: Tschüss schnöde Welt! out: Tschüss schnöde Welt!
out: Hello World! 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 Copyright (C) Lumiera.org
2011, Christian Thaeter <ct@pipapo.org> 2011, Christian Thaeter <ct@pipapo.org>
@ -21,254 +21,22 @@
* *****************************************************/ * *****************************************************/
#include "lib/test/test.h"
#include "lib/priqueue.h" #include "lib/priqueue.h"
#include "include/logging.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* static inline void*
pq_index (PriQueue self, unsigned nth) pq_index (LumieraPriQueue self, unsigned nth)
{ {
return (char*)self->queue+self->element_size*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 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; intptr_t n = 1+(intptr_t)extra;
@ -294,97 +62,91 @@ cmpintptr (void* a, void* b)
return *(int*)a - *(int*)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,
TESTS_BEGIN
lumiera_priqueue pq;
LumieraPriQueue r;
int data, prev, curr;
r = lumiera_priqueue_init (&pq,
sizeof (int), sizeof (int),
cmpintptr, cmpintptr,
NULL, NULL,
NULL); NULL);
ENSURE (r==&pq); ENSURE (r==&pq);
#if 1
data = 10; data = 10;
r = priqueue_insert (&pq, &data); r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data); TRACE (test, "inserted %d", data);
#endif
#if 0
data = 5; data = 5;
r = priqueue_insert (&pq, &data); r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data); TRACE (test, "inserted %d", data);
#endif
#if 0
data = 15; data = 15;
r = priqueue_insert (&pq, &data); r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data); TRACE (test, "inserted %d", data);
data = 20; data = 20;
r = priqueue_insert (&pq, &data); r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data); TRACE (test, "inserted %d", data);
#endif
#if 1
for (int i = 0; i < 1000000; ++i) for (int i = 0; i < 1000000; ++i)
{ {
data = i; data = i;
r = priqueue_insert (&pq, &data); r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data); TRACE (test, "inserted %d", data);
} }
#endif
#if 1
for (int i = 0; i < 1000000; ++i) for (int i = 0; i < 1000000; ++i)
{ {
data = rand()%1000000; data = rand()%1000000;
r = priqueue_insert (&pq, &data); r = lumiera_priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);
TRACE (priqueue_test, "inserted %d", data); TRACE (test, "inserted %d", data);
} }
#endif
NOBUG_INVARIANT(priqueue, &pq, 100, NULL); NOBUG_INVARIANT(priqueue, &pq, 100, NULL);
#if 1 prev = 0;
for (int i = 0; pq.used; ++i) for (int i = 0; pq.used; ++i)
{ {
TRACE (priqueue_test, "TOP: %d", *(int*)priqueue_peek (&pq)); curr = *(int*)lumiera_priqueue_peek (&pq);
r = priqueue_remove (&pq); TRACE (test, "TOP: %d", curr);
CHECK (prev <= curr, "priority ordering broken");
prev = curr;
r = lumiera_priqueue_remove (&pq);
ENSURE (r==&pq); ENSURE (r==&pq);
} }
#endif
r = priqueue_destroy (&pq); r = lumiera_priqueue_destroy (&pq);
ENSURE (r==&pq); ENSURE (r==&pq);
return 0;
}
TESTS_END
#endif