Add a copy function to the priqueue

by providing a custom copy function one can adjust otherwise non-copyable
elements. This should be used cautionary because dereferencing elements may
poison the cache and thus have some considerable performance impact
(profile this)
This commit is contained in:
Christian Thaeter 2011-06-21 23:35:50 +02:00 committed by Ichthyostega
parent 98d6ba3967
commit ff51ea54e6
2 changed files with 17 additions and 6 deletions

View file

@ -33,6 +33,7 @@ PriQueue
priqueue_init (PriQueue self, priqueue_init (PriQueue self,
size_t element_size, size_t element_size,
priqueue_cmp_fn cmpfn, priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn) priqueue_resize_fn resizefn)
{ {
NOBUG_INIT_FLAG (priqueue); NOBUG_INIT_FLAG (priqueue);
@ -48,6 +49,10 @@ priqueue_init (PriQueue self,
self->used = self->high_water = self->low_water = 0; self->used = self->high_water = self->low_water = 0;
self->cmpfn = cmpfn; self->cmpfn = cmpfn;
if (!copyfn)
copyfn = memcpy;
self->copyfn = copyfn;
if (!resizefn) if (!resizefn)
resizefn = priqueue_clib_resize; resizefn = priqueue_clib_resize;
self->resizefn = resizefn; self->resizefn = resizefn;
@ -177,11 +182,11 @@ pq_up (PriQueue self, void* tmp)
while (p && self->cmpfn (tmp, pq_index(self, p-1)) < 0) while (p && self->cmpfn (tmp, pq_index(self, p-1)) < 0)
{ {
memcpy (pq_index (self, i-1), pq_index (self, p-1), self->element_size); self->copyfn (pq_index (self, i-1), pq_index (self, p-1), self->element_size);
i=p; p=i/2; i=p; p=i/2;
} }
memcpy (pq_index (self, i-1), tmp, self->element_size); self->copyfn (pq_index (self, i-1), tmp, self->element_size);
} }
@ -222,10 +227,10 @@ pq_down (PriQueue self, void* tmp)
if (self->cmpfn (tmp, pq_index(self, n-1)) < 0) if (self->cmpfn (tmp, pq_index(self, n-1)) < 0)
break; break;
memcpy (pq_index (self, i-1), pq_index (self, n-1), self->element_size); self->copyfn (pq_index (self, i-1), pq_index (self, n-1), self->element_size);
i = n; i = n;
} }
memcpy (pq_index (self, i-1), tmp, self->element_size); self->copyfn (pq_index (self, i-1), tmp, self->element_size);
} }
@ -257,7 +262,7 @@ priqueue_remove (PriQueue self)
#if 0 /* testing */ #ifdef PRIQUEUE_TEST /* testing */
#include <stdio.h> #include <stdio.h>
@ -303,10 +308,11 @@ int main()
r = priqueue_init (&pq, r = priqueue_init (&pq,
sizeof (int), sizeof (int),
cmpintptr, cmpintptr,
NULL,
NULL); NULL);
ENSURE (r==&pq); ENSURE (r==&pq);
#if 0 #if 1
data = 10; data = 10;
r = priqueue_insert (&pq, &data); r = priqueue_insert (&pq, &data);
ENSURE (r==&pq); ENSURE (r==&pq);

View file

@ -42,6 +42,9 @@ 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 */
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.
@ -64,6 +67,7 @@ struct priqueue_struct
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_resize_fn resizefn; priqueue_resize_fn resizefn;
}; };
@ -77,6 +81,7 @@ PriQueue
priqueue_init (PriQueue self, priqueue_init (PriQueue self,
size_t element_size, size_t element_size,
priqueue_cmp_fn cmpfn, priqueue_cmp_fn cmpfn,
priqueue_copy_fn copyfn,
priqueue_resize_fn resizefn); priqueue_resize_fn resizefn);