diff --git a/src/lib/priqueue.c b/src/lib/priqueue.c index 8e957b967..ab667047d 100644 --- a/src/lib/priqueue.c +++ b/src/lib/priqueue.c @@ -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 - - -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 (mused) - { - 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 diff --git a/src/lib/priqueue.h b/src/lib/priqueue.h index 3f6bba002..7cdf5d935 100644 --- a/src/lib/priqueue.h +++ b/src/lib/priqueue.h @@ -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); diff --git a/src/lib/test/test.h b/src/lib/test/test.h index 8d45b984f..42ab15572 100644 --- a/src/lib/test/test.h +++ b/src/lib/test/test.h @@ -38,14 +38,13 @@ #include #include -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; \ \ diff --git a/tests/15priqueue.tests b/tests/15priqueue.tests new file mode 100644 index 000000000..0e8710e10 --- /dev/null +++ b/tests/15priqueue.tests @@ -0,0 +1,6 @@ +TESTING "Priority Queue" ./test-priqueue + +TEST "fill and clear" < @@ -21,254 +21,22 @@ * *****************************************************/ +#include "lib/test/test.h" #include "lib/priqueue.h" #include "include/logging.h" -#include -#include - - - - - -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 (nused && 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 - 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