Merge branch 'devel' of git://git.lumiera.org/lumiera/ct into work
This commit is contained in:
commit
f030798844
33 changed files with 1948 additions and 369 deletions
|
|
@ -34,7 +34,7 @@ include $(top_srcdir)/admin/Makefile.am
|
|||
|
||||
# core
|
||||
include $(top_srcdir)/src/lib/Makefile.am
|
||||
include $(top_srcdir)/src/backend/Makefile.am
|
||||
#include $(top_srcdir)/src/backend/Makefile.am
|
||||
|
||||
# plugins
|
||||
#include $(top_srcdir)/src...
|
||||
|
|
|
|||
|
|
@ -24,20 +24,25 @@ liblumi_a_CPPFLAGS = -I$(top_srcdir)/src/
|
|||
liblumi_a_SOURCES = \
|
||||
$(liblumi_a_srcdir)/plugin.c \
|
||||
$(liblumi_a_srcdir)/error.c \
|
||||
$(liblumi_a_srcdir)/framerate.c \
|
||||
$(liblumi_a_srcdir)/mutex.c \
|
||||
$(liblumi_a_srcdir)/rwlock.c \
|
||||
$(liblumi_a_srcdir)/condition.c \
|
||||
$(liblumi_a_srcdir)/references.c
|
||||
$(liblumi_a_srcdir)/references.c \
|
||||
$(liblumi_a_srcdir)/uuid.c \
|
||||
$(liblumi_a_srcdir)/safeclib.c \
|
||||
$(liblumi_a_srcdir)/cuckoo.c \
|
||||
$(liblumi_a_srcdir)/mrucache.c
|
||||
|
||||
|
||||
noinst_HEADERS += \
|
||||
$(liblumi_a_srcdir)/plugin.h \
|
||||
$(liblumi_a_srcdir)/error.h \
|
||||
$(liblumi_a_srcdir)/framerate.h \
|
||||
$(liblumi_a_srcdir)/locking.h \
|
||||
$(liblumi_a_srcdir)/mutex.h \
|
||||
$(liblumi_a_srcdir)/rwlock.h \
|
||||
$(liblumi_a_srcdir)/condition.h \
|
||||
$(liblumi_a_srcdir)/references.h
|
||||
|
||||
$(liblumi_a_srcdir)/references.h \
|
||||
$(liblumi_a_srcdir)/uuid.h \
|
||||
$(liblumi_a_srcdir)/safeclib.h \
|
||||
$(liblumi_a_srcdir)/cuckoo.h \
|
||||
$(liblumi_a_srcdir)/mrucache.h
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
* @file Condition variables
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed");
|
||||
|
||||
/**
|
||||
* Initialize a condition variable
|
||||
* @param self is a pointer to the condition variable to be initialized
|
||||
|
|
@ -53,9 +55,9 @@ lumiera_condition_destroy (LumieraCondition self)
|
|||
if (self)
|
||||
{
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
else if (pthread_cond_destroy (&self->cond))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (CONDITION_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
* @file Condition variables, header
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
|
||||
|
||||
/**
|
||||
* Condition variables.
|
||||
|
|
@ -59,10 +60,10 @@ lumiera_condition_signal (LumieraCondition self)
|
|||
{
|
||||
REQUIRE (self);
|
||||
if (pthread_mutex_lock (&self->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
pthread_cond_signal (&self->cond);
|
||||
if (pthread_mutex_unlock (&self->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_UNLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,10 +75,10 @@ lumiera_condition_broadcast (LumieraCondition self)
|
|||
{
|
||||
REQUIRE (self);
|
||||
if (pthread_mutex_lock (&self->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
pthread_cond_broadcast (&self->cond);
|
||||
if (pthread_mutex_unlock (&self->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_UNLOCK);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -124,7 +125,7 @@ lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition
|
|||
self->state = state;
|
||||
if (state == LUMIERA_LOCKED)
|
||||
if (pthread_mutex_lock (&cond->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
@ -141,7 +142,7 @@ lumiera_conditionacquirer_lock (LumieraConditionacquirer self)
|
|||
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
|
||||
|
||||
if (pthread_mutex_lock (&self->cond->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
self->state = LUMIERA_LOCKED;
|
||||
}
|
||||
|
|
@ -172,7 +173,7 @@ lumiera_conditionacquirer_unlock (LumieraConditionacquirer self)
|
|||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
|
||||
if (pthread_mutex_unlock (&self->cond->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_UNLOCK);
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
}
|
||||
|
||||
|
|
|
|||
497
src/lib/cuckoo.c
Normal file
497
src/lib/cuckoo.c
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
A cuckoo hash implementation
|
||||
|
||||
Copyright (C)
|
||||
2008, 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 "cuckoo.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
enum compact_state
|
||||
{
|
||||
COMPACTING_OFF,
|
||||
COMPACTING_AUTO,
|
||||
COMPACTED
|
||||
};
|
||||
|
||||
struct cuckoo_struct
|
||||
{
|
||||
size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */
|
||||
size_t itemsize;
|
||||
|
||||
cuckoo_hashfunc h1; /* hash function */
|
||||
uint32_t r1; /* random, reset for each rehash */
|
||||
cuckoo_hashfunc h2;
|
||||
uint32_t r2;
|
||||
cuckoo_hashfunc h3;
|
||||
uint32_t r3;
|
||||
|
||||
cuckoo_cmpfunc cmp;
|
||||
|
||||
void* t1;
|
||||
void* t2;
|
||||
void* t3;
|
||||
|
||||
unsigned maxloops; /* sqrt (4 * size) */
|
||||
|
||||
enum compact_state autocompact;
|
||||
size_t elements;
|
||||
};
|
||||
|
||||
|
||||
static inline uint32_t cuckoo_fast_prng ()
|
||||
{
|
||||
static uint32_t rnd = 0xbabeface;
|
||||
return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1);
|
||||
}
|
||||
|
||||
Cuckoo
|
||||
cuckoo_init (Cuckoo self,
|
||||
cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize)
|
||||
{
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->size = 1<<startsize;
|
||||
self->itemsize = itemsize;
|
||||
self->h1 = h1;
|
||||
self->r1 = cuckoo_fast_prng ();
|
||||
self->h2 = h2;
|
||||
self->r2 = cuckoo_fast_prng ();
|
||||
self->h3 = h3;
|
||||
self->r3 = cuckoo_fast_prng ();
|
||||
|
||||
self->cmp = cmp;
|
||||
|
||||
self->t1 = calloc (self->size * 4, itemsize);
|
||||
self->t2 = calloc (self->size * 2, itemsize);
|
||||
self->t3 = calloc (self->size, itemsize);
|
||||
if (!self->t1 || !self->t2 || !self->t3)
|
||||
{
|
||||
free (self->t1);
|
||||
free (self->t2);
|
||||
free (self->t3);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->maxloops = 1;
|
||||
while (self->maxloops * self->maxloops < self->size * 4)
|
||||
++self->maxloops;
|
||||
|
||||
self->autocompact = COMPACTING_AUTO;
|
||||
self->elements = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
Cuckoo
|
||||
cuckoo_new (cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize)
|
||||
{
|
||||
Cuckoo self = malloc (sizeof (struct cuckoo_struct));
|
||||
if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize))
|
||||
{
|
||||
free (self);
|
||||
return NULL;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
Cuckoo
|
||||
cuckoo_destroy (Cuckoo self)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
free (self->t1);
|
||||
free (self->t2);
|
||||
free (self->t3);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cuckoo_free (Cuckoo self)
|
||||
{
|
||||
free (cuckoo_destroy (self));
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
iszero (void* mem, size_t size)
|
||||
{
|
||||
while (size && !*(int*)mem)
|
||||
{
|
||||
size -= sizeof (int);
|
||||
mem += sizeof (int);
|
||||
}
|
||||
return !size;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xmemcpy (void* dst, void* src, size_t size)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
size -= sizeof (int);
|
||||
*(int*)(dst + size) = *(int*)(src + size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cuckoo_insert_internal_ (Cuckoo self, void* item)
|
||||
{
|
||||
void* pos;
|
||||
char tmp[self->itemsize];
|
||||
|
||||
for (unsigned n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
/* find nest */
|
||||
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
|
||||
/* kick old egg out */
|
||||
xmemcpy (tmp, pos, self->itemsize);
|
||||
/* lay egg */
|
||||
xmemcpy (pos, item, self->itemsize);
|
||||
|
||||
if (iszero (tmp, self->itemsize))
|
||||
return 1;
|
||||
|
||||
/* find nest */
|
||||
pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size));
|
||||
/* kick old egg out */
|
||||
xmemcpy (item, pos, self->itemsize);
|
||||
/* lay egg */
|
||||
xmemcpy (pos, tmp, self->itemsize);
|
||||
|
||||
if (iszero (item, self->itemsize))
|
||||
return 1;
|
||||
|
||||
/* find nest */
|
||||
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
|
||||
/* kick old egg out */
|
||||
xmemcpy (tmp, pos, self->itemsize);
|
||||
/* lay egg */
|
||||
xmemcpy (pos, item, self->itemsize);
|
||||
|
||||
if (iszero (tmp, self->itemsize))
|
||||
return 1;
|
||||
|
||||
/* copy tmp to item, which will be reinserted on next interation / after rehashing */
|
||||
xmemcpy (item, tmp, self->itemsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cuckoo_rehash (Cuckoo self)
|
||||
{
|
||||
retry1:
|
||||
|
||||
self->r1 = cuckoo_fast_prng ();
|
||||
|
||||
for (size_t i = 0; i < 4*self->size; ++i)
|
||||
{
|
||||
unsigned n;
|
||||
void* pos = self->t1 + self->itemsize * i;
|
||||
if (!iszero (pos, self->itemsize))
|
||||
{
|
||||
for (n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
unsigned hash = self->h1 (pos, self->r1) % (4*self->size);
|
||||
if (hash != i)
|
||||
{
|
||||
char t[self->itemsize];
|
||||
void* hpos = self->t1 + self->itemsize * hash;
|
||||
xmemcpy (t, hpos, self->itemsize);
|
||||
xmemcpy (hpos, pos, self->itemsize);
|
||||
xmemcpy (pos, t, self->itemsize);
|
||||
if (iszero (t, self->itemsize))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (n == self->maxloops)
|
||||
goto retry1;
|
||||
}
|
||||
}
|
||||
|
||||
retry2:
|
||||
self->r2 = cuckoo_fast_prng ();
|
||||
|
||||
for (size_t i = 0; i < 2*self->size; ++i)
|
||||
{
|
||||
unsigned n;
|
||||
void* pos = self->t2 + self->itemsize * i;
|
||||
if (!iszero (pos, self->itemsize))
|
||||
{
|
||||
for (n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
unsigned hash = self->h2 (pos, self->r2) % (2*self->size);
|
||||
if (hash != i)
|
||||
{
|
||||
char t[self->itemsize];
|
||||
void* hpos = self->t2 + self->itemsize * hash;
|
||||
xmemcpy (t, hpos, self->itemsize);
|
||||
xmemcpy (hpos, pos, self->itemsize);
|
||||
xmemcpy (pos, t, self->itemsize);
|
||||
if (iszero (t, self->itemsize))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (n == self->maxloops)
|
||||
goto retry2;
|
||||
}
|
||||
}
|
||||
|
||||
retry3:
|
||||
self->r3 = cuckoo_fast_prng ();
|
||||
|
||||
for (size_t i = 0; i < self->size; ++i)
|
||||
{
|
||||
unsigned n;
|
||||
void* pos = self->t3 + self->itemsize * i;
|
||||
if (!iszero (pos, self->itemsize))
|
||||
{
|
||||
for (n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
unsigned hash = self->h3 (pos, self->r3) % self->size;
|
||||
if (hash != i)
|
||||
{
|
||||
char t[self->itemsize];
|
||||
void* hpos = self->t3 + self->itemsize * hash;
|
||||
xmemcpy (t, hpos, self->itemsize);
|
||||
xmemcpy (hpos, pos, self->itemsize);
|
||||
xmemcpy (pos, t, self->itemsize);
|
||||
if (iszero (t, self->itemsize))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (n == self->maxloops)
|
||||
goto retry3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cuckoo_grow (Cuckoo self)
|
||||
{
|
||||
/* rotate hashfuncs, tables, randoms */
|
||||
cuckoo_hashfunc th = self->h3;
|
||||
self->h3 = self->h2;
|
||||
self->h2 = self->h1;
|
||||
self->h1 = th;
|
||||
|
||||
uint32_t tr = self->r3;
|
||||
self->r3 = self->r2;
|
||||
self->r2 = self->r1;
|
||||
self->r1 = tr;
|
||||
|
||||
void* tt = self->t3;
|
||||
self->t3 = self->t2;
|
||||
self->t2 = self->t1;
|
||||
|
||||
/* double new base size */
|
||||
self->size *= 2;
|
||||
while (self->maxloops * self->maxloops < self->size * 4)
|
||||
++self->maxloops;
|
||||
|
||||
/* alloc new t1 */
|
||||
self->t1 = calloc (self->size * 4, self->itemsize);
|
||||
if (!self->t1)
|
||||
{
|
||||
self->t1 = tt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reinsert tt */
|
||||
size_t ttsize = self->size / 2;
|
||||
for (size_t i = 0; i < ttsize; ++i)
|
||||
{
|
||||
void* pos = tt + i * self->itemsize;
|
||||
if (!iszero (pos, self->itemsize))
|
||||
{
|
||||
while (!cuckoo_insert_internal_ (self, pos))
|
||||
cuckoo_rehash (self);
|
||||
}
|
||||
}
|
||||
free (tt);
|
||||
|
||||
self->autocompact = COMPACTING_AUTO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cuckoo_reserve (Cuckoo self, size_t more)
|
||||
{
|
||||
int ret = 1;
|
||||
if (more)
|
||||
while (self->elements+self->maxloops+more >= 6*self->size)
|
||||
ret = cuckoo_grow (self);
|
||||
|
||||
self->autocompact = COMPACTING_OFF;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cuckoo_compact (Cuckoo self)
|
||||
{
|
||||
if (self->autocompact == COMPACTED)
|
||||
return 1;
|
||||
|
||||
if (self->size > 2 && self->elements < self->size * 3)
|
||||
{
|
||||
cuckoo_hashfunc th = self->h1;
|
||||
self->h1 = self->h2;
|
||||
self->h2 = self->h3;
|
||||
self->h3 = th;
|
||||
|
||||
uint32_t tr = self->r1;
|
||||
self->r1 = self->r2;
|
||||
self->r2 = self->r3;
|
||||
self->r3 = tr;
|
||||
|
||||
void* tt = self->t1;
|
||||
self->t1 = self->t2;
|
||||
self->t2 = self->t3;
|
||||
|
||||
/* halve base size */
|
||||
self->size /= 2;
|
||||
while (self->maxloops * self->maxloops >= self->size * 4)
|
||||
--self->maxloops;
|
||||
|
||||
/* alloc new t3 */
|
||||
self->t3 = calloc (self->size, self->itemsize);
|
||||
if (!self->t3)
|
||||
{
|
||||
self->t3 = tt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reinsert tt */
|
||||
size_t ttsize = self->size * 8;
|
||||
for (size_t i = 0; i < ttsize; ++i)
|
||||
{
|
||||
void* pos = tt + i * self->itemsize;
|
||||
if (!iszero (pos, self->itemsize))
|
||||
{
|
||||
--self->elements;
|
||||
cuckoo_insert (self, pos);
|
||||
}
|
||||
}
|
||||
free (tt);
|
||||
self->autocompact = COMPACTED;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cuckoo_insert (Cuckoo self, void* item)
|
||||
{
|
||||
char tmp[self->itemsize];
|
||||
|
||||
void* found;
|
||||
if ((found = cuckoo_find (self, item)))
|
||||
{
|
||||
xmemcpy (found, item, self->itemsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
xmemcpy (tmp, item, self->itemsize);
|
||||
|
||||
for (unsigned n = 6; n; --n) /* rehash/grow loop */
|
||||
{
|
||||
if (cuckoo_insert_internal_ (self, tmp))
|
||||
{
|
||||
++self->elements;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (self->elements > n*self->size)
|
||||
{
|
||||
n = 6;
|
||||
if (!cuckoo_grow (self))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
cuckoo_rehash (self);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
cuckoo_find (Cuckoo self, void* item)
|
||||
{
|
||||
void* pos;
|
||||
|
||||
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
|
||||
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
|
||||
return pos;
|
||||
|
||||
pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size));
|
||||
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
|
||||
return pos;
|
||||
|
||||
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
|
||||
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
|
||||
return pos;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cuckoo_remove (Cuckoo self, void* item)
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
memset (item, 0, self->itemsize);
|
||||
--self->elements;
|
||||
|
||||
if (self->autocompact == COMPACTING_AUTO && self->size > 2 && self->elements <= self->size*2)
|
||||
cuckoo_compact (self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
167
src/lib/cuckoo.h
Normal file
167
src/lib/cuckoo.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
A cuckoo hash implementation
|
||||
|
||||
Copyright (C)
|
||||
2008, 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.
|
||||
*/
|
||||
#ifndef CUCKOO_H
|
||||
#define CUCKOO_H
|
||||
|
||||
/**
|
||||
* @file Cuckoo hashing
|
||||
* This hashing gives guaranteed O(1) lookup complexity and amortized O(1) insert and remove complexity.
|
||||
* Hash tables by default grow and shrink automatically. It is posible to preallocate entries and turn
|
||||
* automatic shrinking off taking out the memory management factors for insert and remove operations.
|
||||
* This implementation uses 3 Tables which exponential growing sizes.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct cuckoo_struct;
|
||||
typedef struct cuckoo_struct * Cuckoo;
|
||||
|
||||
/**
|
||||
* Hash function.
|
||||
* User supplied universal hash function
|
||||
* @param item address of the item to be hashed
|
||||
* @param r pseudo random number, 31 significant bits, regenerated on each rehash
|
||||
* @return hash value
|
||||
*/
|
||||
typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r);
|
||||
|
||||
/**
|
||||
* Compare function.
|
||||
* User supplied compare function
|
||||
* @param item1 address of the first item
|
||||
* @param item2 address of the second item
|
||||
* @return 1 when the items are identical, 0 otherwise
|
||||
*/
|
||||
typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2);
|
||||
|
||||
/**
|
||||
* Initialize a cuckoo hash.
|
||||
* @param self pointer to a uninitialized cuckoo datastructure
|
||||
* @param h1 hash function for the first table
|
||||
* @param h2 hash function for the second table
|
||||
* @param h3 hash function for the third table
|
||||
* @param cmp function which compares two keys
|
||||
* @param startsize initial size of table t3, as 2's exponent
|
||||
* @return The initialized hashtable or NULL at allocation failure
|
||||
*/
|
||||
Cuckoo
|
||||
cuckoo_init (Cuckoo self,
|
||||
cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize);
|
||||
|
||||
/**
|
||||
* Allocate a new cuckoo hash.
|
||||
* @param h1 hash function for the first table
|
||||
* @param h2 hash function for the second table
|
||||
* @param h3 hash function for the third table
|
||||
* @param cmp function which compares two keys
|
||||
* @param startsize initial size of table t3, as 2's exponent
|
||||
* @return The initialized hashtable or NULL at allocation failure
|
||||
*/
|
||||
Cuckoo
|
||||
cuckoo_new (cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize);
|
||||
|
||||
/**
|
||||
* Destroy a cuckoo hash.
|
||||
* Frees internal used resources.
|
||||
* @param self cuckoo hash to destroy
|
||||
* @return The now uninitialized hashtable
|
||||
*/
|
||||
Cuckoo
|
||||
cuckoo_destroy (Cuckoo self);
|
||||
|
||||
/**
|
||||
* Deallocate a cuckoo hash.
|
||||
* @param self handle of the hash table to be freed
|
||||
*/
|
||||
void
|
||||
cuckoo_free (Cuckoo self);
|
||||
|
||||
/**
|
||||
* Insert an element into a hash.
|
||||
* amortized O(1) complexity because it may rarely rehash the tables or even grow them.
|
||||
* see cuckoo_reserve() about how to preallocate entries to prevent the growing costs.
|
||||
* @param self handle to the hash table
|
||||
* @param item pointer to a item to be inserted
|
||||
* @return 1 on successful insert, 0 on allocation failure
|
||||
* Note: at failure there is one arbitary hash cell lost!
|
||||
*/
|
||||
int
|
||||
cuckoo_insert (Cuckoo self, void* item);
|
||||
|
||||
/**
|
||||
* Find a value by key in a hash.
|
||||
* @param self handle to the hash table
|
||||
* @param item pointer to an item to be looked up
|
||||
* @return found object or NULL if not present
|
||||
*/
|
||||
void*
|
||||
cuckoo_find (Cuckoo self, void* item);
|
||||
|
||||
/**
|
||||
* Remove a item from a hash.
|
||||
* amortized O(1) complexity when it automatically shrink its tables.
|
||||
* guaranteed O(1) complexity when automatic shrinking is turned off.
|
||||
* see cuckoo_reserve() about how turn automatic shrinking off.
|
||||
* @param self handle to the hash table
|
||||
* @param item pointer to the item to be removed
|
||||
*/
|
||||
void
|
||||
cuckoo_remove (Cuckoo self, void* item);
|
||||
|
||||
/**
|
||||
* Shrink the hash sizes when possible and turn autocompacting on.
|
||||
* only useful when autmatic shrinking is turned off.
|
||||
* see cuckoo_reserve() about how turn shrinking off.
|
||||
* @param self handle to the hash table
|
||||
*/
|
||||
int
|
||||
cuckoo_compact (Cuckoo self);
|
||||
|
||||
/**
|
||||
* Prereserve hash entries and turn autocompacting off.
|
||||
* @param self handle to the hash table
|
||||
* @param more number of entries to be additionally reserved
|
||||
* In rare circumstances inserting into a hash which has reserved some entries
|
||||
* it may still need to rehash (or even rarer) to grow the table.
|
||||
* While autocompacting is turned off, removing is completely O(1).
|
||||
*/
|
||||
int
|
||||
cuckoo_reserve (Cuckoo self, size_t more);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -39,7 +39,8 @@ extern "C" {
|
|||
* Abort unconditionally with a 'Fatal Error!' message.
|
||||
* This macro is used whenever the program end up in a invalid state from which no runtime recovery is possible
|
||||
*/
|
||||
#define LUMIERA_DIE do { NOBUG_ERROR(NOBUG_ON, "Fatal Error!"); abort(); } while(0)
|
||||
#define LUMIERA_DIE(err) \
|
||||
do { NOBUG_ERROR(NOBUG_ON, "Fatal Error: %s ", strchr(LUMIERA_ERROR_##err, ':')); abort(); } while(0)
|
||||
|
||||
/**
|
||||
* Forward declare an error constant.
|
||||
|
|
@ -58,7 +59,8 @@ extern const char* LUMIERA_ERROR_##err
|
|||
#define LUMIERA_ERROR_DEFINE(err, msg) \
|
||||
const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
|
||||
|
||||
/** Helper macro to raise an error for the current thread.
|
||||
/**
|
||||
* Helper macro to raise an error for the current thread.
|
||||
* This macro eases setting an error. It adds NoBug logging support to the low level error handling.
|
||||
* @param flag NoBug flag describing the subsystem where the error was raised
|
||||
* @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY)
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
framerate.h - framerate calculations
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_FRAMERATE_H
|
||||
#define LUMIERA_FRAMERATE_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "lib/error.h"
|
||||
|
||||
/**
|
||||
* @file Framerate calculations, header.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* framerates are defined as a rational number
|
||||
* for example NTSC with 30000/1001fps
|
||||
*/
|
||||
struct lumiera_framerate_struct
|
||||
{
|
||||
unsigned n; //numerator
|
||||
unsigned d; //denominator
|
||||
};
|
||||
|
||||
typedef struct lumiera_framerate_struct lumiera_framerate;
|
||||
typedef lumiera_framerate* LumieraFramerate;
|
||||
|
||||
typedef signed long lumiera_framepos;
|
||||
|
||||
LUMIERA_ERROR_DECLARE(FRAMERATE_ILLEGAL_TIME);
|
||||
LUMIERA_ERROR_DECLARE(FRAMERATE_ILLEGAL_FRAME);
|
||||
|
||||
#define LUMIERA_FRAMEPOS_ERROR LONG_MIN
|
||||
|
||||
/**
|
||||
* Get the frame number of a given time at a given frame rate.
|
||||
* frame indexing starts with 1
|
||||
* @param framerate is a pointer to the framerate used, defined as rational number. Must be given.
|
||||
* @param time is a pointer to a lumiera_time which shall be converted.
|
||||
* @return frame at the given time or LUMIERA_FRAMEPOS_ERROR on error.
|
||||
*/
|
||||
static inline lumiera_framepos
|
||||
lumiera_framerate_frame_get_time (const LumieraFramerate framerate, LumieraTime time)
|
||||
{
|
||||
REQUIRE (framerate);
|
||||
if (!time || time->tv_sec == (time_t)-1)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FRAMERATE_ILLEGAL_TIME);
|
||||
return LUMIERA_FRAMEPOS_ERROR;
|
||||
}
|
||||
|
||||
/* we add a magic microsecond for rounding, because of integer truncation frames may be calculated at most 1us earlier,
|
||||
the idea is to compensate odd framerates which fall out off microsecond precision.
|
||||
*/
|
||||
return ((time->tv_sec * 1000000ULL + time->tv_usec + /*magic*/1) * framerate->n)/(framerate->d * 1000000ULL) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start time for a frame.
|
||||
* frame indexing starts with 1
|
||||
* @param framerate is a pointer to the framerate used, defined as rational number. Must be given.
|
||||
* @param time is a pointer to a lumiera_time which shall take the result.
|
||||
* @param frame frame number to be converted to time. This frame number must be greater than 0.
|
||||
* @return the pointer given in time or NULL on error (or when it was given as time).
|
||||
*/
|
||||
static inline LumieraTime
|
||||
lumiera_framerate_time_get_time_frame (const LumieraFramerate framerate,
|
||||
LumieraTime time,
|
||||
lumiera_framepos frame)
|
||||
{
|
||||
REQUIRE (framerate);
|
||||
if (time)
|
||||
{
|
||||
if (frame < 1)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FRAMERATE_ILLEGAL_FRAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long long usec = ((frame-1) * framerate->d * 1000000ULL - (/*magic*/frame>1?1:0)) / framerate->n;
|
||||
|
||||
time->tv_sec = usec / 1000000;
|
||||
time->tv_usec = usec % 1000000;
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -88,6 +88,7 @@ typedef llist * LList;
|
|||
typedef const llist * const_LList;
|
||||
typedef llist ** LList_ref;
|
||||
|
||||
|
||||
/**
|
||||
* Macro to instantiate a local llist.
|
||||
* @param name of the llist node
|
||||
|
|
@ -95,6 +96,14 @@ typedef llist ** LList_ref;
|
|||
#define LLIST_AUTO(name) llist name = {&name,&name}
|
||||
|
||||
|
||||
/*
|
||||
some macros for convenience
|
||||
*/
|
||||
#define llist_insert_head(list, element) llist_insert_next (list, element)
|
||||
#define llist_insert_tail(list, element) llist_insert_prev (list, element)
|
||||
#define llist_head llist_next
|
||||
#define llist_tail llist_prev
|
||||
|
||||
/**
|
||||
* cast back from a member of a structure to a pointer of the structure
|
||||
*/
|
||||
|
|
@ -129,6 +138,30 @@ typedef llist ** LList_ref;
|
|||
! llist_is_end (node, list); \
|
||||
llist_backward (&node))
|
||||
|
||||
|
||||
/**
|
||||
* Iterate forward over a range.
|
||||
* @param start first node to be interated
|
||||
* @param end node after the last node be iterated
|
||||
* @param node pointer to the iterated node
|
||||
*/
|
||||
#define LLIST_FORRANGE(start, end, node) \
|
||||
for (LList node = start; \
|
||||
node != end; \
|
||||
llist_forward (&node))
|
||||
|
||||
/**
|
||||
* Iterate backward over a range.
|
||||
* @param rstart first node to be interated
|
||||
* @param rend node before the last node be iterated
|
||||
* @param node pointer to the iterated node
|
||||
*/
|
||||
#define LLIST_FORRANGE_REV(rstart, rend, node) \
|
||||
for (LList node = rstart; \
|
||||
node != rend; \
|
||||
llist_backward (&node))
|
||||
|
||||
|
||||
/**
|
||||
* Consume a list from head.
|
||||
* The body of this statement should remove the head from the list, else it would be a infinite loop
|
||||
|
|
@ -290,7 +323,7 @@ LLIST_FUNC (LList llist_insert_next (LList self, LList next),
|
|||
/**
|
||||
* Insert a node before another.
|
||||
* @param self node before which we want to insert
|
||||
* @param prev node which shall be inserted nefore self. Could already linked to a list from where it will be removed.
|
||||
* @param prev node which shall be inserted before self. Could already linked to a list from where it will be removed.
|
||||
* @return self
|
||||
*/
|
||||
LLIST_FUNC (LList llist_insert_prev (LList self, LList prev),
|
||||
|
|
@ -314,10 +347,9 @@ LLIST_FUNC (LList llist_insertlist_next (LList self, LList next),
|
|||
if (!llist_is_empty (next))
|
||||
{
|
||||
self->next->prev = next->prev;
|
||||
self->next = next->next;
|
||||
|
||||
next->next->prev = self;
|
||||
next->prev->next = self->next;
|
||||
self->next = next->next;
|
||||
next->next->prev = self;
|
||||
|
||||
next->prev = next->next = next;
|
||||
}
|
||||
|
|
@ -335,10 +367,9 @@ LLIST_FUNC (LList llist_insertlist_prev (LList self, LList prev),
|
|||
if (!llist_is_empty (prev))
|
||||
{
|
||||
self->prev->next = prev->next;
|
||||
self->prev = prev->prev;
|
||||
|
||||
prev->prev->next = self;
|
||||
prev->next->prev = self->prev;
|
||||
self->prev = prev->prev;
|
||||
prev->prev->next = self;
|
||||
|
||||
prev->prev = prev->next = prev;
|
||||
}
|
||||
|
|
@ -494,20 +525,45 @@ LLIST_FUNC (LList llist_get_nth_stop (LList self, int n, const_LList stop),
|
|||
return self;
|
||||
);
|
||||
|
||||
/*
|
||||
some macros for convenience
|
||||
*/
|
||||
#define llist_insert_head(list, element) llist_insert_next (list, element)
|
||||
#define llist_insert_tail(list, element) llist_insert_prev (list, element)
|
||||
#define llist_head llist_next
|
||||
#define llist_tail llist_prev
|
||||
|
||||
/**
|
||||
* Sort a list.
|
||||
* @param self list to be sorted
|
||||
* @param cmp function takeing 2 LLists
|
||||
* simple recursive mergesort
|
||||
*/
|
||||
typedef int (*llist_cmpfn)(LList a, LList b);
|
||||
|
||||
LLIST_FUNC (LList llist_sort (LList self, llist_cmpfn cmp),
|
||||
llist left;
|
||||
llist right;
|
||||
llist_init (&left);
|
||||
llist_init (&right);
|
||||
unsigned n = 0;
|
||||
if (!llist_is_single (self))
|
||||
{
|
||||
LLIST_WHILE_HEAD (self, head)
|
||||
llist_insert_prev (++n & 1 ? &left : &right, head);
|
||||
|
||||
llist_sort (&left, cmp);
|
||||
llist_sort (&right, cmp);
|
||||
|
||||
while (!llist_is_empty (&left) && !llist_is_empty (&right))
|
||||
llist_insert_prev (self, cmp (left.next, right.next) < 0 ? left.next : right.next);
|
||||
|
||||
if (!llist_is_empty (&left))
|
||||
llist_insertlist_prev (self, &left);
|
||||
if (!llist_is_empty (&right))
|
||||
llist_insertlist_prev (self, &right);
|
||||
}
|
||||
return self;
|
||||
)
|
||||
|
||||
#endif /* LLIST_H */
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// End:
|
||||
// arch-tag: e8fe4a59-fd55-4c45-b860-5cd1e0771213
|
||||
// end_of_file
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@
|
|||
|
||||
#include "lib/error.h"
|
||||
|
||||
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
|
||||
|
||||
/**
|
||||
* @file Shared declarations for all locking primitives.
|
||||
*/
|
||||
|
|
|
|||
67
src/lib/mrucache.c
Normal file
67
src/lib/mrucache.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
mrucache.h - most recent used cache
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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/mrucache.h"
|
||||
|
||||
/**
|
||||
* @file Most recent used cache
|
||||
* Elements (addressed by a LList node) are either in the cache and thereby subject of aging
|
||||
* or checked out under control of the user.
|
||||
*/
|
||||
|
||||
|
||||
LumieraMruCache
|
||||
lumiera_mrucache_init (LumieraMruCache self, lumiera_cache_destructor_fn destructor_cb)
|
||||
{
|
||||
REQUIRE (self);
|
||||
llist_init (&self->cache_list);
|
||||
self->cached = 0;
|
||||
self->destructor_cb = destructor_cb;
|
||||
return self;
|
||||
}
|
||||
|
||||
LumieraMruCache
|
||||
lumiera_mrucache_destroy (LumieraMruCache self)
|
||||
{
|
||||
LLIST_WHILE_TAIL (&self->cache_list, node)
|
||||
{
|
||||
if (self->destructor_cb)
|
||||
free (self->destructor_cb (node));
|
||||
else
|
||||
free (node);
|
||||
}
|
||||
self->cached = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* destroy and free the nelem oldest elements
|
||||
*/
|
||||
int
|
||||
lumiera_mrucache_age (LumieraMruCache self, int nelem)
|
||||
{
|
||||
REQUIRE (self);
|
||||
while (self->cached && nelem--)
|
||||
free (lumiera_mrucache_pop (self));
|
||||
|
||||
return nelem;
|
||||
}
|
||||
119
src/lib/mrucache.h
Normal file
119
src/lib/mrucache.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
mrucache.h - most recent used cache
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_CACHE_H
|
||||
#define LUMIERA_CACHE_H
|
||||
|
||||
#include "lib/llist.h"
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file Most recent used cache
|
||||
* Elements (addressed by a LList node) are either in the cache and thereby subject of aging
|
||||
* or checked out under control of the user.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback function used to destruct/cleanup aged elements.
|
||||
* shall clean the element sufficiently up to be ready for being freed or reused
|
||||
* @param node the llist node used to link cache elements (will be empty at call)
|
||||
* @return pointer to the begin of the element.
|
||||
*/
|
||||
typedef void* (*lumiera_cache_destructor_fn)(LList node);
|
||||
|
||||
struct lumiera_mrucache_struct
|
||||
{
|
||||
llist cache_list;
|
||||
size_t cached;
|
||||
lumiera_cache_destructor_fn destructor_cb;
|
||||
};
|
||||
typedef struct lumiera_mrucache_struct lumiera_mrucache;
|
||||
typedef lumiera_mrucache* LumieraMruCache;
|
||||
|
||||
/**
|
||||
* Initialize a mrucache
|
||||
*/
|
||||
LumieraMruCache
|
||||
lumiera_mrucache_init (LumieraMruCache self, lumiera_cache_destructor_fn destructor_cb);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a mrucache
|
||||
*/
|
||||
LumieraMruCache
|
||||
lumiera_mrucache_destroy (LumieraMruCache self);
|
||||
|
||||
|
||||
/**
|
||||
* add an element to a mrucache
|
||||
*/
|
||||
static inline void
|
||||
lumiera_mrucache_add (LumieraMruCache self, LList node)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (node && llist_is_empty (node));
|
||||
llist_insert_head (&self->cache_list, node);
|
||||
++self->cached;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an element from a mrucache.
|
||||
*/
|
||||
static inline void
|
||||
lumiera_mrucache_remove (LumieraMruCache self, LList node)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (node && llist_is_member (&self->cache_list, node)); /* speedup loop warning :P, this check is costly */
|
||||
llist_unlink (node);
|
||||
--self->cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy the oldest element and return a pointer to it for reuse.
|
||||
*/
|
||||
static inline void*
|
||||
lumiera_mrucache_pop (LumieraMruCache self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
if (llist_is_empty (&self->cache_list))
|
||||
return NULL;
|
||||
|
||||
LList node = llist_tail (&self->cache_list);
|
||||
llist_unlink (node);
|
||||
--self->cached;
|
||||
|
||||
if (self->destructor_cb)
|
||||
return self->destructor_cb (node);
|
||||
else
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* destroy and free the nelem oldest elements
|
||||
*/
|
||||
int
|
||||
lumiera_mrucache_age (LumieraMruCache self, int nelem);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -25,6 +25,10 @@
|
|||
* @file Mutual exclusion locking.
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DEFINE (MUTEX_LOCK, "Mutex locking failed");
|
||||
LUMIERA_ERROR_DEFINE (MUTEX_UNLOCK, "Mutex unlocking failed");
|
||||
LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed");
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a mutex variable
|
||||
|
|
@ -52,7 +56,7 @@ lumiera_mutex_destroy (LumieraMutex self)
|
|||
if (self)
|
||||
{
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@
|
|||
* @file Mutual exclusion locking, header.
|
||||
*/
|
||||
|
||||
#define LUMIERA_MUTEX_SECTION(mutex) \
|
||||
lumiera_mutexacquirer lock_##__LINE__##_; \
|
||||
for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKED); \
|
||||
lock_##__LINE__##_.state == LUMIERA_LOCKED; \
|
||||
lumiera_mutexacquirer_unlock (&lock_##__LINE__##_))
|
||||
|
||||
|
||||
/**
|
||||
* Mutex.
|
||||
|
|
@ -106,7 +112,7 @@ lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex,
|
|||
self->state = state;
|
||||
if (state == LUMIERA_LOCKED)
|
||||
if (pthread_mutex_lock (&mutex->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
@ -124,7 +130,7 @@ lumiera_mutexacquirer_lock (LumieraMutexacquirer self)
|
|||
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
|
||||
|
||||
if (pthread_mutex_lock (&self->mutex->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
self->state = LUMIERA_LOCKED;
|
||||
}
|
||||
|
|
@ -164,7 +170,7 @@ lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex)
|
|||
case EBUSY:
|
||||
return LUMIERA_UNLOCKED;
|
||||
default:
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +186,7 @@ lumiera_mutexacquirer_unlock (LumieraMutexacquirer self)
|
|||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
|
||||
if (pthread_mutex_unlock (&self->mutex->mutex))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (MUTEX_UNLOCK);
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@
|
|||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "safeclib.h"
|
||||
|
||||
/**
|
||||
* @file Plugin loader.
|
||||
|
|
@ -159,8 +161,8 @@ lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path)
|
|||
{
|
||||
/* got it */
|
||||
TRACE (lumiera_plugin, "found %s", pathname);
|
||||
self->pathname = strdup (pathname);
|
||||
if (!self->pathname) LUMIERA_DIE;
|
||||
self->pathname = lumiera_strndup (pathname, PATH_MAX);
|
||||
|
||||
self->type = lumiera_plugin_extensions[i].type;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -195,21 +197,20 @@ lumiera_interface_open (const char* name, const char* interface, size_t min_revi
|
|||
plugin.name = name; /* for searching */
|
||||
|
||||
found = tsearch (&plugin, &lumiera_plugin_registry, lumiera_plugin_name_cmp);
|
||||
if (!found) LUMIERA_DIE;
|
||||
if (!found)
|
||||
LUMIERA_DIE (NO_MEMORY);
|
||||
|
||||
if (*found == &plugin)
|
||||
{
|
||||
NOTICE (lumiera_plugin, "new plugin");
|
||||
|
||||
/* now really create new item */
|
||||
*found = malloc (sizeof (struct lumiera_plugin));
|
||||
if (!*found) LUMIERA_DIE;
|
||||
*found = lumiera_malloc (sizeof (struct lumiera_plugin));
|
||||
|
||||
if (name) /* NULL is main app, no lookup needed */
|
||||
{
|
||||
/*lookup for $LUMIERA_PLUGIN_PATH*/
|
||||
(*found)->name = strdup (name);
|
||||
if (!(*found)->name) LUMIERA_DIE;
|
||||
(*found)->name = lumiera_strndup (name, PATH_MAX);
|
||||
|
||||
if (!!lumiera_plugin_lookup (*found, getenv("LUMIERA_PLUGIN_PATH"))
|
||||
#ifdef LUMIERA_PLUGIN_PATH
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "lib/references.h"
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
/**
|
||||
* @file Strong and Weak references
|
||||
|
|
@ -43,8 +44,7 @@
|
|||
LumieraReference
|
||||
lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*))
|
||||
{
|
||||
LumieraReftarget target = malloc (sizeof(lumiera_reftarget));
|
||||
if (!target) LUMIERA_DIE;
|
||||
LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget));
|
||||
|
||||
target->object = obj;
|
||||
target->dtor = dtor;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock");
|
||||
|
||||
/**
|
||||
* @file Read/write locks.
|
||||
|
|
@ -57,7 +61,7 @@ lumiera_rwlock_destroy (LumieraRWLock self)
|
|||
if (self)
|
||||
{
|
||||
if (pthread_rwlock_destroy (&self->rwlock))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (RWLOCK_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -95,7 +99,7 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e
|
|||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (RWLOCK_RLOCK);
|
||||
}
|
||||
case LUMIERA_WRLOCKED:
|
||||
switch (pthread_rwlock_wrlock (&rwlock->rwlock))
|
||||
|
|
@ -106,7 +110,7 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e
|
|||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (RWLOCK_WLOCK);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
|
@ -138,7 +142,7 @@ lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self)
|
|||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (RWLOCK_RLOCK);
|
||||
}
|
||||
|
||||
self->state = LUMIERA_RDLOCKED;
|
||||
|
|
@ -166,7 +170,7 @@ lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self)
|
|||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (RWLOCK_WLOCK);
|
||||
}
|
||||
|
||||
self->state = LUMIERA_WRLOCKED;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@
|
|||
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
|
||||
|
||||
/**
|
||||
* @file Read/write locks, header.
|
||||
|
|
@ -106,7 +110,7 @@ lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self)
|
|||
REQUIRE (self);
|
||||
REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked");
|
||||
if (pthread_rwlock_unlock (&self->rwlock->rwlock))
|
||||
LUMIERA_DIE;
|
||||
LUMIERA_DIE (RWLOCK_UNLOCK);
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
}
|
||||
|
||||
|
|
|
|||
214
src/lib/safeclib.c
Normal file
214
src/lib/safeclib.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
safe_clib.c - Portable and safe wrapers around some clib functions and some tools
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, 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.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* @file Portable and safe wrapers around some clib functions and some tools
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!");
|
||||
|
||||
/**
|
||||
* Allocate memory.
|
||||
* always succeeds or dies
|
||||
* @param size memory to be allocated
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
lumiera_malloc (size_t sz)
|
||||
{
|
||||
void* o = sz? malloc (sz) : NULL;
|
||||
if (!o)
|
||||
LUMIERA_DIE (NO_MEMORY);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate a C string.
|
||||
* always succeeds or dies
|
||||
* @param str string to be copied
|
||||
* @param len maximal length to be copied
|
||||
* @return pointer to the new string, "" if NULL was passed as str
|
||||
*/
|
||||
char*
|
||||
lumiera_strndup (const char* str, size_t len)
|
||||
{
|
||||
char* o;
|
||||
if (str)
|
||||
o = strndup (str, len);
|
||||
else
|
||||
o = strdup ("");
|
||||
|
||||
if (!o)
|
||||
LUMIERA_DIE (NO_MEMORY);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare two C strings.
|
||||
* Handles NULL pointers as "", shortcut for same addresses
|
||||
* @param a first string for comparsion
|
||||
* @param b second string for comparsion
|
||||
* @param len maximal length for the comparsion
|
||||
* @return 0 if the strings are identical, -1 if smaller 1 if bigger.
|
||||
*/
|
||||
int
|
||||
lumiera_strncmp (const char* a, const char* b, size_t len)
|
||||
{
|
||||
return a == b ? 0 : strncmp (a?a:"", b?b:"", len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check 2 strings for identity.
|
||||
* @param a first string for comparsion
|
||||
* @param b second string for comparsion
|
||||
* @return 1 when the strings are the the same, 0 if not.
|
||||
*/
|
||||
int
|
||||
lumiera_streq (const char* a, const char* b)
|
||||
{
|
||||
return !lumiera_strncmp (a, b, SIZE_MAX);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Round robin temporary buffers.
|
||||
* This provides 64 buffers per thread which are recycled with each use.
|
||||
* The idea here is to have fast buffers for temporal data without need for explicit heap management.
|
||||
*/
|
||||
struct lumiera_tmpbuf_struct
|
||||
{
|
||||
void* buffers[64];
|
||||
size_t sizes[64];
|
||||
unsigned idx;
|
||||
};
|
||||
|
||||
static pthread_once_t lumiera_tmpbuf_tls_once = PTHREAD_ONCE_INIT;
|
||||
static pthread_key_t lumiera_tmpbuf_tls_key;
|
||||
|
||||
void
|
||||
lumiera_tmpbuf_freeall (void);
|
||||
|
||||
static void
|
||||
lumiera_tmpbuf_destroy (void* buf)
|
||||
{
|
||||
lumiera_tmpbuf_freeall ();
|
||||
free (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
lumiera_tmpbuf_init (void)
|
||||
{
|
||||
pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* free all buffers associated with this thread.
|
||||
* This function is called automatically, usually one doesnt need to call it.
|
||||
*/
|
||||
void
|
||||
lumiera_tmpbuf_freeall (void)
|
||||
{
|
||||
pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init);
|
||||
struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key);
|
||||
if (!buf)
|
||||
pthread_setspecific (lumiera_tmpbuf_tls_key,
|
||||
buf = lumiera_malloc (sizeof (struct lumiera_tmpbuf_struct)));
|
||||
|
||||
for (buf->idx = 0; buf->idx < 64; ++buf->idx)
|
||||
{
|
||||
free (buf->buffers[buf->idx]);
|
||||
buf->buffers[buf->idx] = NULL;
|
||||
buf->sizes[buf->idx] = 0;
|
||||
}
|
||||
buf->idx = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query a thread local buffer.
|
||||
* @param size minimal needed size for the buffer
|
||||
* @return the buffer
|
||||
*/
|
||||
void*
|
||||
lumiera_tmpbuf_provide (size_t size)
|
||||
{
|
||||
pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init);
|
||||
struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key);
|
||||
if (!buf)
|
||||
pthread_setspecific (lumiera_tmpbuf_tls_key,
|
||||
buf = lumiera_malloc (sizeof (struct lumiera_tmpbuf_struct)));
|
||||
|
||||
buf->idx = (buf->idx + 1) & 0x3f;
|
||||
|
||||
if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size)
|
||||
{
|
||||
free (buf->buffers[buf->idx]);
|
||||
buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1);
|
||||
buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]);
|
||||
}
|
||||
return buf->buffers[buf->idx];
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
lumiera_tmpbuf_strndup (const char* src, size_t size)
|
||||
{
|
||||
size_t len = strlen (src);
|
||||
len = len > size ? size : len;
|
||||
|
||||
char* buf = lumiera_tmpbuf_provide (len + 1);
|
||||
strncpy (buf, src, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
lumiera_tmpbuf_sprintf (size_t size, const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, fmt);
|
||||
size_t len = vsnprintf (NULL, 0, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
len = len > size ? size : len;
|
||||
char* buf = lumiera_tmpbuf_provide (len);
|
||||
va_start (args, fmt);
|
||||
vsnprintf (buf, len, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
return buf;
|
||||
}
|
||||
114
src/lib/safeclib.h
Normal file
114
src/lib/safeclib.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
safe_clib.h - Portable and safe wrapers around some clib functions and some tools
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, 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 "error.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @file Portable and safe wrapers around some clib functions and some tools
|
||||
*/
|
||||
LUMIERA_ERROR_DECLARE(NO_MEMORY);
|
||||
|
||||
/**
|
||||
* Allocate memory.
|
||||
* always succeeds or dies
|
||||
* @param size memory to be allocated
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
lumiera_malloc (size_t sz);
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate a C string.
|
||||
* always succeeds or dies
|
||||
* @param str string to be copied
|
||||
* @param len maximal length to be copied
|
||||
* @return pointer to the new string, "" if NULL was passed as str
|
||||
*/
|
||||
char*
|
||||
lumiera_strndup (const char* str, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Compare two C strings.
|
||||
* Handles NULL pointers as "", shortcut for same addresses
|
||||
* @param a first string for comparsion
|
||||
* @param b second string for comparsion
|
||||
* @param len maximal length for the comparsion
|
||||
* @return 0 if the strings are identical, -1 if smaller 1 if bigger.
|
||||
*/
|
||||
int
|
||||
lumiera_strncmp (const char* a, const char* b, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* check 2 strings for identity.
|
||||
* @param a first string for comparsion
|
||||
* @param b second string for comparsion
|
||||
* @return 1 when the strings are the the same, 0 if not.
|
||||
*/
|
||||
int
|
||||
lumiera_streq (const char* a, const char* b);
|
||||
|
||||
|
||||
/**
|
||||
* Round robin temporary buffers.
|
||||
* This provides 64 buffers per thread which are recycled with each use.
|
||||
* The idea here is to have fast buffers for temporal data without need for explicit heap management.
|
||||
*/
|
||||
|
||||
/**
|
||||
* free all buffers associated with this thread.
|
||||
* This function is called automatically, usually one doesnt need to call it.
|
||||
*/
|
||||
void
|
||||
lumiera_tmpbuf_freeall (void);
|
||||
|
||||
|
||||
/**
|
||||
* Query a thread local tmpbuf.
|
||||
* @param size minimal needed size for the tmpbuf
|
||||
* @return the tmpbuf
|
||||
*/
|
||||
void*
|
||||
lumiera_tmpbuf_provide (size_t size);
|
||||
|
||||
/**
|
||||
* Duplicate string to a tmpbuf.
|
||||
* @param src string to be duplicated
|
||||
* @param size maximal length to be copied
|
||||
* @return temporary buffer containing a copy of the string
|
||||
*/
|
||||
char*
|
||||
lumiera_tmpbuf_strndup (const char* src, size_t size);
|
||||
|
||||
/**
|
||||
* Construct a string in a tmpbuf.
|
||||
* @param size maximal length for the string
|
||||
* @param fmt printf like formatstring
|
||||
* @param ... parameters
|
||||
* @return temporary buffer containing the constructed of the string
|
||||
*/
|
||||
char*
|
||||
lumiera_tmpbuf_sprintf (size_t size, const char* fmt, ...);
|
||||
|
||||
95
src/lib/uuid.c
Normal file
95
src/lib/uuid.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
uuid - Universal unique identifiers
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, 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/uuid.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr)
|
||||
{
|
||||
memset (uuid, 0, 16);
|
||||
*(void**)uuid = ptr;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
lumiera_uuid_ptr_get (lumiera_uuid* uuid)
|
||||
{
|
||||
return *(void**)uuid;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_uuid_gen (lumiera_uuid* uuid)
|
||||
{
|
||||
static int fd = -2;
|
||||
if (!uuid)
|
||||
return;
|
||||
|
||||
if (fd == -2)
|
||||
{
|
||||
fd = open ("/dev/urandom", O_RDONLY);
|
||||
if (fd == -1)
|
||||
fd = open ("/dev/random", O_RDONLY);
|
||||
if (fd >= 0)
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
else
|
||||
srand (getpid () + time (NULL));
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
((unsigned char*)uuid)[i] = (unsigned char)(rand()>>7);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read (fd, uuid, 16) < 0)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src)
|
||||
{
|
||||
memcpy (dest, src, 16);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb)
|
||||
{
|
||||
return !memcmp (uuida, uuidb, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
lumiera_uuid_hash (lumiera_uuid* uuid)
|
||||
{
|
||||
return *(size_t*)uuid;
|
||||
}
|
||||
|
||||
|
||||
67
src/lib/uuid.h
Normal file
67
src/lib/uuid.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
uuid - Universal unique identifiers
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, 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.
|
||||
*/
|
||||
#ifndef LUMIERA_UUID_H
|
||||
#define LUMIERA_UUID_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char lumiera_uuid[16];
|
||||
|
||||
/**
|
||||
* Retrieve a generic pointer stored in a uuid
|
||||
*/
|
||||
void*
|
||||
lumiera_uuid_ptr_get (lumiera_uuid* uuid);
|
||||
|
||||
/**
|
||||
* Generate a new uuid
|
||||
*/
|
||||
void
|
||||
lumiera_uuid_gen (lumiera_uuid* uuid);
|
||||
|
||||
/**
|
||||
* Store a generic pointer in a uuid
|
||||
*/
|
||||
void
|
||||
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr);
|
||||
|
||||
|
||||
/**
|
||||
* Copy an uuid
|
||||
*/
|
||||
void
|
||||
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src);
|
||||
|
||||
|
||||
/**
|
||||
* Test 2 uuid's for equality
|
||||
*/
|
||||
int
|
||||
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb);
|
||||
|
||||
|
||||
/**
|
||||
* Generate a hashsum over an uuid
|
||||
*/
|
||||
size_t
|
||||
lumiera_uuid_hash (lumiera_uuid* uuid);
|
||||
|
||||
#endif
|
||||
28
tests/15safeclib.tests
Normal file
28
tests/15safeclib.tests
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
TESTING "Safe clib and tools" ./test-safeclib
|
||||
|
||||
TEST "Allocating 0 bytes" allocation0 <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
TEST "Allocating some memory" allocation1024 <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "Allocation error" allocationtoobig <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
|
||||
TEST "string equal check" streq <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
TEST "temporary buffers" tmpbuf <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
|
||||
|
||||
15
tests/15uuid.tests
Normal file
15
tests/15uuid.tests
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
TESTING "UUID's" ./test-uuid
|
||||
|
||||
TEST "uuid generate" uuidgen_2 <<END
|
||||
out: 0
|
||||
END
|
||||
|
||||
TEST "uuid copy" uuidgen_copy <<END
|
||||
out: 1
|
||||
END
|
||||
|
||||
TEST "storing pointers" ptrs <<END
|
||||
out: 1
|
||||
END
|
||||
|
||||
|
||||
|
|
@ -36,6 +36,16 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c
|
|||
test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-safeclib
|
||||
test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c
|
||||
test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
test_safeclib_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-uuid
|
||||
test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c
|
||||
test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
test_uuid_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-references
|
||||
test_references_SOURCES = $(tests_srcdir)/library/test-references.c
|
||||
test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
|
|
|
|||
|
|
@ -23,173 +23,166 @@
|
|||
//#include <string.h>
|
||||
|
||||
#include "lib/llist.h"
|
||||
#include "lib/error.h"
|
||||
#include "tests/test.h"
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
LUMIERA_ERROR_DEFINE(TEST, "test error");
|
||||
|
||||
int
|
||||
main (int argc, char** argv)
|
||||
TEST ("basic")
|
||||
{
|
||||
NOBUG_INIT;
|
||||
LLIST_AUTO (node1);
|
||||
|
||||
if (argc == 1)
|
||||
return 0;
|
||||
llist node2;
|
||||
llist_init (&node2);
|
||||
|
||||
if (!strcmp(argv[1], "basic"))
|
||||
{
|
||||
LLIST_AUTO (node1);
|
||||
|
||||
llist node2;
|
||||
llist_init (&node2);
|
||||
|
||||
printf ("%d\n", llist_is_empty (&node1));
|
||||
printf ("%d\n", llist_is_empty (&node2));
|
||||
}
|
||||
else if (!strcmp(argv[1], "nodeinsert"))
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
|
||||
llist_insert_next (&list, &node1);
|
||||
printf ("%d\n", llist_is_empty (&list));
|
||||
printf ("%d\n", llist_is_empty (&node1));
|
||||
printf ("%d\n", llist_is_single (&node1));
|
||||
llist_insert_next (&node1, &node2);
|
||||
printf ("%d\n", llist_is_single (&node1));
|
||||
llist_insert_prev (&node1, &node3);
|
||||
printf ("%d\n", llist_next (&list) == &node3);
|
||||
printf ("%d\n", llist_next (&node3) == &node1);
|
||||
printf ("%d\n", llist_next (&node1) == &node2);
|
||||
printf ("%d\n", llist_prev (&list) == &node2);
|
||||
printf ("%d\n", llist_count (&list));
|
||||
}
|
||||
else if (!strcmp(argv[1], "predicates"))
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
LLIST_AUTO (node4);
|
||||
LLIST_AUTO (nil);
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
printf ("%d\n", llist_is_head (&list, &node1));
|
||||
printf ("%d\n", llist_is_tail (&list, &node4));
|
||||
printf ("%d\n", llist_is_head (&list, &node4));
|
||||
printf ("%d\n", llist_is_tail (&list, &node1));
|
||||
printf ("%d\n", llist_is_end (&list, &list));
|
||||
printf ("%d\n", llist_is_member (&list, &node3));
|
||||
printf ("%d\n", llist_is_member (&list, &nil));
|
||||
|
||||
printf ("%d\n", llist_is_before_after (&list, &node1, &node3));
|
||||
printf ("%d\n", llist_is_before_after (&list, &node3, &node1));
|
||||
printf ("%d\n", llist_is_before_after (&list, &node1, &nil));
|
||||
}
|
||||
else if (!strcmp(argv[1], "unlink"))
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
LLIST_AUTO (node4);
|
||||
LLIST_AUTO (nil);
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
LLIST_FOREACH_REV (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
|
||||
llist_unlink (&nil);
|
||||
llist_unlink (&node2);
|
||||
llist_unlink (&node3);
|
||||
|
||||
LLIST_FOREACH (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
printf ("%d\n", llist_is_empty (&node2));
|
||||
printf ("%d\n", llist_is_empty (&node3));
|
||||
printf ("%d\n", llist_is_empty (&nil));
|
||||
}
|
||||
else if (!strcmp(argv[1], "whiles"))
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
LLIST_AUTO (node4);
|
||||
LLIST_AUTO (nil);
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
LLIST_FOREACH_REV (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
|
||||
LLIST_WHILE_HEAD (&list, head)
|
||||
llist_unlink (head);
|
||||
|
||||
LLIST_FOREACH (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
LLIST_WHILE_TAIL (&list, tail)
|
||||
llist_unlink (tail);
|
||||
|
||||
LLIST_FOREACH (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
printf ("%d\n", llist_is_empty (&node1));
|
||||
printf ("%d\n", llist_is_empty (&node2));
|
||||
}
|
||||
|
||||
TEST ("nodeinsert")
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
|
||||
llist_insert_next (&list, &node1);
|
||||
printf ("%d\n", llist_is_empty (&list));
|
||||
printf ("%d\n", llist_is_empty (&node1));
|
||||
printf ("%d\n", llist_is_single (&node1));
|
||||
llist_insert_next (&node1, &node2);
|
||||
printf ("%d\n", llist_is_single (&node1));
|
||||
llist_insert_prev (&node1, &node3);
|
||||
printf ("%d\n", llist_next (&list) == &node3);
|
||||
printf ("%d\n", llist_next (&node3) == &node1);
|
||||
printf ("%d\n", llist_next (&node1) == &node2);
|
||||
printf ("%d\n", llist_prev (&list) == &node2);
|
||||
printf ("%d\n", llist_count (&list));
|
||||
}
|
||||
|
||||
TEST ("predicates")
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
LLIST_AUTO (node4);
|
||||
LLIST_AUTO (nil);
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
printf ("%d\n", llist_is_head (&list, &node1));
|
||||
printf ("%d\n", llist_is_tail (&list, &node4));
|
||||
printf ("%d\n", llist_is_head (&list, &node4));
|
||||
printf ("%d\n", llist_is_tail (&list, &node1));
|
||||
printf ("%d\n", llist_is_end (&list, &list));
|
||||
printf ("%d\n", llist_is_member (&list, &node3));
|
||||
printf ("%d\n", llist_is_member (&list, &nil));
|
||||
|
||||
printf ("%d\n", llist_is_before_after (&list, &node1, &node3));
|
||||
printf ("%d\n", llist_is_before_after (&list, &node3, &node1));
|
||||
printf ("%d\n", llist_is_before_after (&list, &node1, &nil));
|
||||
}
|
||||
|
||||
TEST ("unlink")
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
LLIST_AUTO (node4);
|
||||
LLIST_AUTO (nil);
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
LLIST_FOREACH_REV (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
|
||||
llist_unlink (&nil);
|
||||
llist_unlink (&node2);
|
||||
llist_unlink (&node3);
|
||||
|
||||
LLIST_FOREACH (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
printf ("%d\n", llist_is_empty (&node2));
|
||||
printf ("%d\n", llist_is_empty (&node3));
|
||||
printf ("%d\n", llist_is_empty (&nil));
|
||||
}
|
||||
|
||||
TEST ("whiles")
|
||||
{
|
||||
LLIST_AUTO (list);
|
||||
LLIST_AUTO (node1);
|
||||
LLIST_AUTO (node2);
|
||||
LLIST_AUTO (node3);
|
||||
LLIST_AUTO (node4);
|
||||
LLIST_AUTO (nil);
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
LLIST_FOREACH_REV (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
|
||||
LLIST_WHILE_HEAD (&list, head)
|
||||
llist_unlink (head);
|
||||
|
||||
LLIST_FOREACH (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
|
||||
llist_insert_tail (&list, &node2);
|
||||
llist_insert_tail (&list, &node3);
|
||||
llist_insert_tail (&list, &node4);
|
||||
llist_insert_head (&list, &node1);
|
||||
|
||||
LLIST_WHILE_TAIL (&list, tail)
|
||||
llist_unlink (tail);
|
||||
|
||||
LLIST_FOREACH (&list, itr)
|
||||
{
|
||||
if(itr == &node1) printf ("node1 ");
|
||||
else if(itr == &node2) printf ("node2 ");
|
||||
else if(itr == &node3) printf ("node3 ");
|
||||
else if(itr == &node4) printf ("node4 ");
|
||||
else printf ("unknown ");
|
||||
}
|
||||
printf (".\n");
|
||||
}
|
||||
|
||||
|
||||
TESTS_END
|
||||
|
|
|
|||
85
tests/library/test-safeclib.c
Normal file
85
tests/library/test-safeclib.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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/safeclib.h"
|
||||
#include "tests/test.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
TEST ("allocation0")
|
||||
{
|
||||
lumiera_malloc (0);
|
||||
NOTREACHED;
|
||||
}
|
||||
|
||||
TEST ("allocation1024")
|
||||
{
|
||||
void* data[1024];
|
||||
for (int i = 0; i < 1024; ++i)
|
||||
{
|
||||
data[i] = lumiera_malloc (1024);
|
||||
ENSURE (data[i]);
|
||||
}
|
||||
for (int i = 0; i < 1024; ++i)
|
||||
{
|
||||
free (data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST ("allocationtoobig")
|
||||
{
|
||||
struct rlimit rl;
|
||||
rl.rlim_cur = 100*1024*1024;
|
||||
rl.rlim_max = 100*1024*1024;
|
||||
setrlimit (RLIMIT_AS, &rl);
|
||||
lumiera_malloc (200*1024*1024);
|
||||
NOTREACHED;
|
||||
}
|
||||
|
||||
TEST ("streq")
|
||||
{
|
||||
if (!lumiera_streq ("foo", "foo"))
|
||||
LUMIERA_DIE (TEST);
|
||||
if (!lumiera_streq (NULL, NULL))
|
||||
LUMIERA_DIE (TEST);
|
||||
if (!!lumiera_streq (NULL, "foo"))
|
||||
LUMIERA_DIE (TEST);
|
||||
if (!!lumiera_streq ("foo", NULL))
|
||||
LUMIERA_DIE (TEST);
|
||||
if (!!lumiera_streq ("foo", "bar"))
|
||||
LUMIERA_DIE (TEST);
|
||||
}
|
||||
|
||||
TEST ("tmpbuf")
|
||||
{
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
char* buf = lumiera_tmpbuf_provide (1024);
|
||||
|
||||
for (int j = 0; j < 1024; ++j)
|
||||
{
|
||||
buf[j] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TESTS_END
|
||||
73
tests/library/test-uuid.c
Normal file
73
tests/library/test-uuid.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
test-uuid.c - test the uuid lib
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, 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 "cinelerra-config.h"
|
||||
|
||||
//#include <stdio.h>
|
||||
|
||||
|
||||
#include "lib/uuid.h"
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
//CINELERRA_ERROR_DEFINE(TEST, "test error");
|
||||
|
||||
int
|
||||
main (int argc, char** argv)
|
||||
{
|
||||
NOBUG_INIT;
|
||||
|
||||
if (argc == 1)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(argv[1], "uuidgen_2"))
|
||||
{
|
||||
lumiera_uuid uuid1;
|
||||
lumiera_uuid uuid2;
|
||||
|
||||
lumiera_uuid_gen (&uuid1);
|
||||
lumiera_uuid_gen (&uuid2);
|
||||
|
||||
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
|
||||
}
|
||||
else if (!strcmp(argv[1], "uuidgen_copy"))
|
||||
{
|
||||
lumiera_uuid uuid1;
|
||||
lumiera_uuid uuid2;
|
||||
|
||||
lumiera_uuid_gen (&uuid1);
|
||||
|
||||
lumiera_uuid_copy (&uuid2, &uuid1);
|
||||
|
||||
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
|
||||
}
|
||||
else if (!strcmp(argv[1], "ptrs"))
|
||||
{
|
||||
lumiera_uuid uuid;
|
||||
|
||||
lumiera_uuid_set_ptr (&uuid, &uuid);
|
||||
|
||||
printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid);
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -21,33 +21,21 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/error.h"
|
||||
|
||||
LUMIERA_ERROR_DEFINE(TEST, "test error");
|
||||
#include "tests/test.h"
|
||||
|
||||
int conditionforgotunlock ();
|
||||
int mutexforgotunlock ();
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
int
|
||||
main (int argc, char** argv)
|
||||
TEST ("conditionforgotunlock")
|
||||
{
|
||||
NOBUG_INIT;
|
||||
|
||||
if (argc == 1)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(argv[1], "conditionforgotunlock"))
|
||||
{
|
||||
return conditionforgotunlock ();
|
||||
}
|
||||
if (!strcmp(argv[1], "mutexforgotunlock"))
|
||||
{
|
||||
return mutexforgotunlock ();
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return conditionforgotunlock ();
|
||||
}
|
||||
|
||||
TEST ("mutexforgotunlock")
|
||||
{
|
||||
return mutexforgotunlock ();
|
||||
}
|
||||
|
||||
TESTS_END
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "lib/plugin.h"
|
||||
#include "hello_interface.h"
|
||||
|
||||
LUMIERA_ERROR_DEFINE(FAILURE, "test failure");
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
|
|
@ -25,7 +26,7 @@ main(int argc, char** argv)
|
|||
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_de =
|
||||
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin", "german_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
|
||||
|
||||
if (!hello_de) LUMIERA_DIE;
|
||||
if (!hello_de) LUMIERA_DIE (FAILURE);
|
||||
|
||||
hello_de->hello();
|
||||
hello_de->goodbye(argv[1]);
|
||||
|
|
@ -33,7 +34,7 @@ main(int argc, char** argv)
|
|||
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_en =
|
||||
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin", "english_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
|
||||
|
||||
if (!hello_en) LUMIERA_DIE;
|
||||
if (!hello_en) LUMIERA_DIE (FAILURE);
|
||||
|
||||
hello_en->hello();
|
||||
hello_en->goodbye(argv[1]);
|
||||
|
|
@ -48,7 +49,7 @@ main(int argc, char** argv)
|
|||
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_de =
|
||||
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin_cpp", "german_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
|
||||
|
||||
if (!hello_de) LUMIERA_DIE;
|
||||
if (!hello_de) LUMIERA_DIE (FAILURE);
|
||||
|
||||
hello_de->hello();
|
||||
hello_de->goodbye(argv[1]);
|
||||
|
|
@ -56,7 +57,7 @@ main(int argc, char** argv)
|
|||
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_en =
|
||||
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin_cpp", "english_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
|
||||
|
||||
if (!hello_en) LUMIERA_DIE;
|
||||
if (!hello_en) LUMIERA_DIE (FAILURE);
|
||||
|
||||
hello_en->hello();
|
||||
hello_en->goodbye(argv[1]);
|
||||
|
|
|
|||
52
tests/test.h
Normal file
52
tests/test.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
test.h - macros for running tests
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, 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.
|
||||
*/
|
||||
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
#include "lib/error.h"
|
||||
|
||||
LUMIERA_ERROR_DEFINE (TEST, "test error");
|
||||
|
||||
#define TESTS_BEGIN \
|
||||
int \
|
||||
main (int argc, char** argv) \
|
||||
{ \
|
||||
NOBUG_INIT; \
|
||||
\
|
||||
if (argc == 1) \
|
||||
return 1;
|
||||
|
||||
#define TEST(name) \
|
||||
else if (!strcmp(argv[1], name))
|
||||
|
||||
|
||||
#define TESTS_END \
|
||||
else \
|
||||
return 1; \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -2104,13 +2104,26 @@ if (oldText.indexOf("SplashScreen")==-1)
|
|||
}
|
||||
//}}}</pre>
|
||||
</div>
|
||||
<div title="StyleGuide" modifier="CehTeh" modified="200803261336" created="200803261258" changecount="4">
|
||||
<div title="StyleGuide" modifier="CehTeh" modified="200803261924" created="200803261258" changecount="6">
|
||||
<pre>! Source code formatting
|
||||
http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
|
||||
We decided to use the 'gnu-style' for indenting (using spaces and never tabs!):
|
||||
http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
|
||||
|
||||
It is reasonable to be relaxed about soem formatting rules:
|
||||
* line length might be longer when required
|
||||
* inter expession spacing can be changed to the actual needed ex: (2*x + 2)
|
||||
|
||||
Things we are pedantic about:
|
||||
* use never ever tab characters in C/C++ sources
|
||||
* be consistent
|
||||
* source files should end with a newline
|
||||
* no trailing or bogus whitespaces
|
||||
|
||||
! Coding Practices
|
||||
|
||||
! Writing Tests
|
||||
|
||||
! Contibuting
|
||||
|
||||
! Tests
|
||||
</pre>
|
||||
</div>
|
||||
<div title="StyleSheet" modifier="CehTeh" modified="200706090017" created="200701131624" tags="MPTWTheme" server.type="file" server.host="file:///home/ct/.homepage/home.html" server.page.revision="200706090017">
|
||||
|
|
|
|||
|
|
@ -930,11 +930,10 @@ git push git://git.pipapo.org/lumiera/mob
|
|||
|
||||
lumiera/mob is an anonymous account at pipapo.org where everyone can commit changes. </pre>
|
||||
</div>
|
||||
<div title="IRC-Transcripts" modifier="Ichthyostega" modified="200804120322" created="200708120209" tags="discuss irclog" changecount="8">
|
||||
<div title="IRC-Transcripts" modifier="CehTeh" modified="200803262159" created="200708120209" tags="discuss irclog" changecount="8">
|
||||
<pre>We keep a protocol or short summary of each important discussion. The summaries of the monthly developer meetings are posted to the Mailinglist and can be found on pipapo.org too
|
||||
|
||||
* [[04-08 developer meeting 3.Apr.2008|IRC_2008-04-03]]
|
||||
* [[03-08 developer meeting 6.Mar.2008|IRC_2008-03-06]]
|
||||
* [[2.official developer meeting 6.March.2008|IRC_2008-03-06]]
|
||||
* [[1.official developer meeting 1.Feb.2008|IRC_2008-02-01]]
|
||||
* [[informal developer meeting 10.Aug.2007|IRC_2007-08-10]]
|
||||
</pre>
|
||||
|
|
@ -1807,17 +1806,16 @@ Wiki works. It is simple to use and just flexible enough to handle the task. I d
|
|||
Please __end your tiddlers in a newline__, this makes merging in git easier since the /pre tag used in tiddlywiki will become on a single line.
|
||||
|
||||
----
|
||||
!Architecture and Subsystems
|
||||
!Design Draft
|
||||
to get started, we create design drafts emphasizing different aspects and regions of Lumiera
|
||||
|
||||
* Cehteh works on the data backend, see [[this page|backend.html]]
|
||||
* Ichthyo focuses mainly on Edit operations and Builder, [[see this separate page|renderengine.html]]
|
||||
* Gmerlin is in charge of [[GAVL|http://gmerlin.sourceforge.net/gavl.html]] for processing of video data
|
||||
* as of 4/08 a GuiWorkingGroup is emerging...
|
||||
* Ichthyo focuses mainly on the Render Engine and its interconnection to the EDL, [[see this separate page|renderengine.html]]
|
||||
* Cehteh works on the data backend draft, see [[this page|backend.html]]
|
||||
* Some tools which don't fit somewhere else and are used everywhere are put into a [[Support Library|support_library.html]]
|
||||
* [[Description of the Test System|TestSh]]
|
||||
|
||||
!Coding &mdash; Building &mdash; Testing
|
||||
how to organize several aspects of the practical coding...
|
||||
!Coding Structures
|
||||
next we should //start thinking// on how to organize several aspects of the practical coding...
|
||||
* what to do in BOUML? &rarr; [[more|whatInBOUML]]
|
||||
* how to organize packages, files, includes? &rarr; [[more|SrcTreeStructure]]
|
||||
* how to organize the executable to be built?
|
||||
|
|
|
|||
Loading…
Reference in a new issue