integrate priority queue: adjust imports and doxygen comments
This commit is contained in:
parent
87a84a931f
commit
fc3cc1bc98
4 changed files with 469 additions and 65 deletions
|
|
@ -99,6 +99,7 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( gui_dbg, debugging);
|
||||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( library_dbg, debugging);
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( library_dbg, debugging);
|
||||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( mpool_dbg, library_dbg);
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( mpool_dbg, library_dbg);
|
||||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( psplay_dbg, library_dbg);
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( psplay_dbg, library_dbg);
|
||||||
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( priqueue, library_dbg);
|
||||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( resourcecollector_dbg, library_dbg);
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( resourcecollector_dbg, library_dbg);
|
||||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_dbg, library_dbg);
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_dbg, library_dbg);
|
||||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_dbg, library_dbg);
|
NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_dbg, library_dbg);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
priqueue - priority queue
|
PriQueue - simple heap based priority queue
|
||||||
|
|
||||||
Copyright (C)
|
Copyright (C) Lumiera.org
|
||||||
2011 Christian Thaeter <ct@pipapo.org>
|
2011, Christian Thaeter <ct@pipapo.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
|
|
@ -17,16 +17,18 @@
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
|
||||||
|
|
||||||
#include "priqueue.h"
|
* *****************************************************/
|
||||||
|
|
||||||
|
|
||||||
#include <nobug.h>
|
#include "lib/priqueue.h"
|
||||||
|
#include "include/logging.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <nobug.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NOBUG_DEFINE_FLAG (priqueue);
|
|
||||||
|
|
||||||
|
|
||||||
PriQueue
|
PriQueue
|
||||||
|
|
@ -36,7 +38,6 @@ priqueue_init (PriQueue self,
|
||||||
priqueue_copy_fn copyfn,
|
priqueue_copy_fn copyfn,
|
||||||
priqueue_resize_fn resizefn)
|
priqueue_resize_fn resizefn)
|
||||||
{
|
{
|
||||||
NOBUG_INIT_FLAG (priqueue);
|
|
||||||
TRACE (priqueue, "%p", self);
|
TRACE (priqueue, "%p", self);
|
||||||
|
|
||||||
REQUIRE (element_size);
|
REQUIRE (element_size);
|
||||||
|
|
@ -78,6 +79,7 @@ priqueue_destroy (PriQueue self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PriQueue
|
PriQueue
|
||||||
priqueue_reserve (PriQueue self, unsigned elements)
|
priqueue_reserve (PriQueue self, unsigned elements)
|
||||||
{
|
{
|
||||||
|
|
@ -102,9 +104,7 @@ priqueue_reserve (PriQueue self, unsigned elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
supplied/default resize function based on realloc
|
|
||||||
*/
|
|
||||||
PriQueue
|
PriQueue
|
||||||
priqueue_clib_resize (PriQueue self)
|
priqueue_clib_resize (PriQueue self)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
priqueue - priority queue
|
PRIQUEUE.h - simple heap based priority queue
|
||||||
|
|
||||||
Copyright (C)
|
Copyright (C) Lumiera.org
|
||||||
2011 Christian Thaeter <ct@pipapo.org>
|
2011, Christian Thaeter <ct@pipapo.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
|
|
@ -17,54 +17,67 @@
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PRIQUEUE_H
|
/** @file priqueue.h
|
||||||
#define PRIQUEUE_H
|
** Simple priority queue implementation based on a binary heap.
|
||||||
|
** Only 'insert' 'remove' and 'peek' operations are supported.
|
||||||
/*
|
** Memory is dynamically managed through an optionally user supplied 'resize' function.
|
||||||
This is a very minimalistic priority queue implementation based on a binary heap. Only 'insert' 'remove' and 'peek' operations are supported
|
** Elements in the queue have a user-define size but should kept as small as possible.
|
||||||
Memory is dynamically managed through an optionally user supplied 'resize' function.
|
** This is only intended to associate lightweight data such as a key and a pointer,
|
||||||
Elements in the queue have a user-define size but should kept as small as possible. This is only intended to associate lightweight data such as
|
** storing the key in the element can save dereferencing cost and thus improve
|
||||||
a key and a pointer, storing the key in the element can save dereferencing cost and thus improve cache locality. It must be noted
|
** cache locality.
|
||||||
that elements in the queue get moved in memory, so referencing them is invalid.
|
**
|
||||||
|
** @warning elements in the queue get moved in memory, so referencing them is not allowed.
|
||||||
There are API's (yet) to change the priority of an arbitary element or remove any but the topmost element. The idea is to let expired elements
|
**
|
||||||
sink to the top and detect that and then remove them.
|
** @todo we might add operations to change the priority of an arbitrary element or remove
|
||||||
*/
|
** any but the topmost element. The idea is to let expired elements sink to the top
|
||||||
|
** and just detect and remove them on next access.
|
||||||
|
**
|
||||||
|
** @see backend::engine::SchedulerFrontend
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#ifndef LIB_PRIQUEUE_H
|
||||||
|
#define LIB_PRIQUEUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "lib/error.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct priqueue_struct priqueue;
|
typedef struct priqueue_struct priqueue;
|
||||||
typedef priqueue* PriQueue;
|
typedef priqueue* PriQueue;
|
||||||
|
|
||||||
/* function to compare 2 keys, mandatory */
|
/** function to compare 2 keys, mandatory */
|
||||||
typedef int (*priqueue_cmp_fn)(void*, void*);
|
typedef int (*priqueue_cmp_fn)(void*, void*);
|
||||||
|
|
||||||
/* function to copy elements, optional. Has the same prototype as memcpy which is used by default */
|
/** 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 *(*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),
|
* or at priqueue_destroy (with queue != NULL, used elements == 0), optional.
|
||||||
optional.
|
*
|
||||||
|
* @note must be aware of resizes by more than just incrementing the queue by one
|
||||||
Must be aware of resizes by more than just incrementing the queue by one
|
|
||||||
*/
|
*/
|
||||||
typedef PriQueue (*priqueue_resize_fn) (PriQueue);
|
typedef PriQueue (*priqueue_resize_fn) (PriQueue);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
this structure is not opaque to make it possible to implement a low level resize operation which has to reallocate
|
* @remarks this structure is not opaque to make it possible
|
||||||
the queue and update the high and low water marks.
|
* to implement a low level resize operation
|
||||||
|
* which has to reallocate the queue and update
|
||||||
|
* the high and low water marks.
|
||||||
*/
|
*/
|
||||||
struct priqueue_struct
|
struct priqueue_struct
|
||||||
{
|
{
|
||||||
void* queue;
|
void* queue;
|
||||||
size_t element_size;
|
size_t element_size;
|
||||||
unsigned used;
|
unsigned used;
|
||||||
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;
|
priqueue_cmp_fn cmpfn;
|
||||||
priqueue_copy_fn copyfn;
|
priqueue_copy_fn copyfn;
|
||||||
|
|
@ -90,40 +103,41 @@ PriQueue
|
||||||
priqueue_destroy (PriQueue self);
|
priqueue_destroy (PriQueue self);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
calls resize to match for at least 'elements' in the queue and then sets low_water to 0, disabling shrinking
|
* calls resize to match for at least 'elements' in the queue
|
||||||
note that on overflow resize will re-enable low_water if it is not aware of this
|
* 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
|
||||||
priqueue_reserve (PriQueue self, unsigned elements);
|
priqueue_reserve (PriQueue self, unsigned elements);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
supplied/default resize function based on realloc
|
* supplied/default resize function based on realloc
|
||||||
initially allocates an array for 64 elements,
|
* initially allocates an array for 64 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
|
PriQueue
|
||||||
priqueue_clib_resize (PriQueue self);
|
priqueue_clib_resize (PriQueue self);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
insert a new element into the priority queue
|
* insert a new element into the priority queue
|
||||||
the element will be copied
|
* the element will be copied
|
||||||
returns NULL on error
|
* @return \c NULL on error
|
||||||
*/
|
*/
|
||||||
PriQueue
|
PriQueue
|
||||||
priqueue_insert (PriQueue self, void* element);
|
priqueue_insert (PriQueue self, void* element);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
returns a pointer to the topmost element
|
* @return pointer to the topmost element, \NULL on empty queue
|
||||||
note that this pointer is only valid as long no insert or remove is called
|
* @note returned pointer is only valid as long
|
||||||
returns NULL when the queue is empty
|
* as no insert or remove is called
|
||||||
*/
|
*/
|
||||||
static inline void*
|
static inline void*
|
||||||
priqueue_peek (PriQueue self)
|
priqueue_peek (PriQueue self)
|
||||||
{
|
{
|
||||||
|
|
@ -134,14 +148,13 @@ priqueue_peek (PriQueue self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
removes the topmost element
|
* removes the topmost element
|
||||||
returns NULL on error (queue emtpy, resize failure)
|
* @return \c NULL on error (empty queue, resize failure)
|
||||||
*/
|
*/
|
||||||
PriQueue
|
PriQueue
|
||||||
priqueue_remove (PriQueue self);
|
priqueue_remove (PriQueue self);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif/*LIB_PRIQUEUE_H*/
|
||||||
|
|
||||||
|
|
|
||||||
390
tests/library/c-lib/test-priqueue.c
Normal file
390
tests/library/c-lib/test-priqueue.c
Normal file
|
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
PriQueue - simple heap based priority queue
|
||||||
|
|
||||||
|
Copyright (C) Lumiera.org
|
||||||
|
2011, Christian Thaeter <ct@pipapo.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
* *****************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static inline void*
|
||||||
|
pq_index (PriQueue 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)
|
||||||
|
{
|
||||||
|
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
|
||||||
Loading…
Reference in a new issue