160 lines
4.7 KiB
C
160 lines
4.7 KiB
C
/*
|
|
PRIQUEUE.h - 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.
|
|
|
|
*/
|
|
|
|
/** @file 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.
|
|
** 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 a key and a pointer,
|
|
** storing the key in the element can save dereferencing cost and thus improve
|
|
** cache locality.
|
|
**
|
|
** @warning elements in the queue get moved in memory, so referencing them is not allowed.
|
|
**
|
|
** @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
|
|
**
|
|
*/
|
|
|
|
|
|
#ifndef LIB_PRIQUEUE_H
|
|
#define LIB_PRIQUEUE_H
|
|
|
|
|
|
#include "lib/error.h"
|
|
|
|
|
|
typedef struct lumiera_priqueue_struct lumiera_priqueue;
|
|
typedef lumiera_priqueue* LumieraPriQueue;
|
|
|
|
/** function to compare 2 keys, mandatory */
|
|
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 *(*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 LumieraPriQueue (*lumiera_priqueue_resize_fn) (LumieraPriQueue);
|
|
|
|
|
|
/**
|
|
* @remarks this structure is not opaque to make it possible
|
|
* to implement a low level resize operation
|
|
* which has to reallocate the queue and update
|
|
* the high and low water marks.
|
|
*/
|
|
struct lumiera_priqueue_struct
|
|
{
|
|
void* queue;
|
|
size_t element_size;
|
|
unsigned used;
|
|
unsigned high_water; ///< elements in the queue
|
|
unsigned low_water; ///< size for shrinking the queue
|
|
|
|
lumiera_priqueue_cmp_fn cmpfn;
|
|
lumiera_priqueue_copy_fn copyfn;
|
|
|
|
lumiera_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);
|
|
|
|
|
|
|
|
LumieraPriQueue
|
|
lumiera_priqueue_destroy (LumieraPriQueue self);
|
|
|
|
|
|
/**
|
|
* calls resize to match for at least 'elements' in the queue
|
|
* 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
|
|
*/
|
|
LumieraPriQueue
|
|
lumiera_priqueue_reserve (LumieraPriQueue self, unsigned elements);
|
|
|
|
|
|
/**
|
|
* supplied/default resize function based on realloc
|
|
* initially allocates an array for 64 elements,
|
|
* doubles this when the high water mark is hit,
|
|
* shrinks at high_water/8-8 (that is, 64 is the minimum size)
|
|
*/
|
|
LumieraPriQueue
|
|
lumiera_priqueue_clib_resize (LumieraPriQueue self);
|
|
|
|
|
|
|
|
|
|
/**
|
|
* insert a new element into the priority queue
|
|
* the element will be copied
|
|
* @return \c NULL on error
|
|
*/
|
|
LumieraPriQueue
|
|
lumiera_priqueue_insert (LumieraPriQueue self, void* element);
|
|
|
|
|
|
/**
|
|
* @return pointer to the topmost element, \NULL on empty queue
|
|
* @note returned pointer is only valid as long
|
|
* as no insert or remove is called
|
|
*/
|
|
static inline void*
|
|
lumiera_priqueue_peek (LumieraPriQueue self)
|
|
{
|
|
if (self && self->queue)
|
|
return self->queue;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* removes the topmost element
|
|
* @return \c NULL on error (empty queue, resize failure)
|
|
*/
|
|
LumieraPriQueue
|
|
lumiera_priqueue_remove (LumieraPriQueue self);
|
|
|
|
|
|
|
|
#endif/*LIB_PRIQUEUE_H*/
|