clean-up: remove cockoo hash (unused and unmaintained)

Cockoo hashing is a thrilling algorithm.
We investigated it during the time or our first draft
towards a confirugation system in 2008. This usage turned
up some problems -- not sure if based on the implementation
or the algorithm itself; at that time, we just switched
to the probabilistic splay tree. The whole configuration
system effort stalled afterwards; so the cuckoo implementation
remained in tree as a zombie.
This commit is contained in:
Fischlurch 2015-05-30 17:41:28 +02:00
parent 07822182d9
commit 97fec4179b
4 changed files with 2 additions and 737 deletions

View file

@ -142,7 +142,7 @@ lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key)
/* Lookup hash entries for the cuckoo hash */
/* == lookup hash entries using the PSplay tree */
/** @internal Structure defining single hash table entries.*/

View file

@ -1,528 +0,0 @@
/*
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>
#define CUCKOO_GRANULARITY int
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;
struct cuckoo_vtable vtable;
uint32_t r1; /* random, reset for each rehash */
uint32_t r2;
uint32_t r3;
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);
}
static inline int
iszero (void* mem, size_t size)
{
while (size && !*(CUCKOO_GRANULARITY*)mem)
{
size -= sizeof (CUCKOO_GRANULARITY);
mem += sizeof (CUCKOO_GRANULARITY);
}
return !size;
}
static inline void
xmemmov (void* dst, void* src, size_t size)
{
while (size)
{
size -= sizeof (CUCKOO_GRANULARITY);
*(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size);
}
}
Cuckoo
cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable)
{
if (!self)
return NULL;
self->size = 16;
self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY)
+ sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */
self->r1 = cuckoo_fast_prng ();
self->r2 = cuckoo_fast_prng ();
self->r3 = cuckoo_fast_prng ();
if (!vtable->h1 || !vtable->h2 || !vtable->h3)
return NULL;
self->vtable.h1 = vtable->h1;
self->vtable.h2 = vtable->h2;
self->vtable.h3 = vtable->h3;
if (!vtable->cmp)
return NULL;
self->vtable.cmp = vtable->cmp;
self->vtable.dtor = vtable->dtor;
if (vtable->mov)
self->vtable.mov = vtable->mov;
else
self->vtable.mov = xmemmov;
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 (size_t itemsize, struct cuckoo_vtable* vtable)
{
Cuckoo self = malloc (sizeof (struct cuckoo_struct));
if (!cuckoo_init (self, itemsize, vtable))
{
free (self);
return NULL;
}
return self;
}
Cuckoo
cuckoo_destroy (Cuckoo self)
{
if (self)
{
if (self->vtable.dtor)
{
void* elem;
for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size)
self->vtable.dtor (elem);
for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size)
self->vtable.dtor (elem);
for (elem = self->t3; elem < self->t1 + self->size; elem += self->size)
self->vtable.dtor (elem);
}
free (self->t1);
free (self->t2);
free (self->t3);
}
return self;
}
void
cuckoo_delete (Cuckoo self)
{
free (cuckoo_destroy (self));
}
static void*
cuckoo_insert_internal_ (Cuckoo self, void* item)
{
void* pos;
CUCKOO_GRANULARITY tmp[self->itemsize / sizeof(CUCKOO_GRANULARITY)];
for (unsigned n = 0; n < self->maxloops; ++n)
{
/* find nest */
pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
/* kick old egg out */
if (iszero (pos, self->itemsize))
memset (tmp, 0, self->itemsize);
else
self->vtable.mov (tmp, pos, self->itemsize);
/* lay egg */
self->vtable.mov (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
return pos;
/* find nest */
pos = self->t2 + self->itemsize * (self->vtable.h2 (tmp, self->r2) % (2*self->size));
/* kick old egg out */
self->vtable.mov (item, pos, self->itemsize);
/* lay egg */
self->vtable.mov (pos, tmp, self->itemsize);
if (iszero (item, self->itemsize))
return pos;
/* find nest */
pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
/* kick old egg out */
self->vtable.mov (tmp, pos, self->itemsize);
/* lay egg */
self->vtable.mov (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
return pos;
/* copy tmp to item, which will be reinserted on next interation / after rehashing */
self->vtable.mov (item, tmp, self->itemsize);
}
return NULL;
}
size_t
cuckoo_nelements (Cuckoo self)
{
return self->elements;
}
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->vtable.h1 (pos, self->r1) % (4*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t1 + self->itemsize * hash;
self->vtable.mov (t, hpos, self->itemsize);
self->vtable.mov (hpos, pos, self->itemsize);
self->vtable.mov (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->vtable.h2 (pos, self->r2) % (2*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t2 + self->itemsize * hash;
self->vtable.mov (t, hpos, self->itemsize);
self->vtable.mov (hpos, pos, self->itemsize);
self->vtable.mov (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->vtable.h3 (pos, self->r3) % self->size;
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t3 + self->itemsize * hash;
self->vtable.mov (t, hpos, self->itemsize);
self->vtable.mov (hpos, pos, self->itemsize);
self->vtable.mov (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->vtable.h3;
self->vtable.h3 = self->vtable.h2;
self->vtable.h2 = self->vtable.h1;
self->vtable.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->vtable.h1;
self->vtable.h1 = self->vtable.h2;
self->vtable.h2 = self->vtable.h3;
self->vtable.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;
}
void*
cuckoo_insert (Cuckoo self, void* item)
{
char tmp[self->itemsize];
void* found;
if ((found = cuckoo_find (self, item)))
{
if (self->vtable.dtor)
self->vtable.dtor (found);
self->vtable.mov (found, item, self->itemsize);
return found;
}
self->vtable.mov (tmp, item, self->itemsize);
for (unsigned n = 6; n; --n) /* rehash/grow loop */
{
if ((found = cuckoo_insert_internal_ (self, tmp)))
{
++self->elements;
return found;
}
if (self->elements > n*self->size)
{
n = 6;
if (!cuckoo_grow (self))
return NULL;
}
else
cuckoo_rehash (self);
}
return NULL;
}
void*
cuckoo_find (Cuckoo self, void* item)
{
void* pos;
pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
pos = self->t2 + self->itemsize * (self->vtable.h2 (item, self->r2) % (2*self->size));
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
return NULL;
}
void
cuckoo_remove (Cuckoo self, void* item)
{
if (item)
{
if (self->vtable.dtor)
self->vtable.dtor (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:
*/

View file

@ -1,197 +0,0 @@
/*
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);
/**
* Item destructor function.
* User supplied destructor function. This function is called when items are removed
* from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element.
* @param item address of the item to be destroyed
*/
typedef void (*cuckoo_dtorfunc)(void* item);
/**
* Move function.
* User supplied item move function
* @param dest target address for the move operation
* @param src source for the move operation
* @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY)
* It might be necessary to invalidate the source in some case, cuckoo will zero it out
* after moving.
*/
typedef void (*cuckoo_movfunc)(void* dest, void* src, size_t size);
/**
* Function table used to specialise various functions used by the hash.
* TODO some elements might be NULL, then defaults are used
*/
struct cuckoo_vtable
{
cuckoo_hashfunc h1;
cuckoo_hashfunc h2;
cuckoo_hashfunc h3;
cuckoo_cmpfunc cmp;
cuckoo_dtorfunc dtor;
cuckoo_movfunc mov;
};
/**
* Initialise a cuckoo hash.
* @param self pointer to a uninitialised cuckoo datastructure
* @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
* @param vtable initialised vtable
* @return The initialised hashtable or NULL at allocation failure
*/
Cuckoo
cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable);
/**
* Allocate a new cuckoo hash.
* @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
* @param startsize initial size of table t3, as 2's exponent
* @param vtable initialised vtable
* @return The initialised hashtable or NULL at allocation failure
*/
Cuckoo
cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable);
/**
* Destroy a cuckoo hash.
* Frees internal used resources.
* @param self cuckoo hash to destroy
* @return The now uninitialised hashtable
*/
Cuckoo
cuckoo_destroy (Cuckoo self);
/**
* Deallocate a cuckoo hash.
* @param self handle of the hash table to be freed
*/
void
cuckoo_delete (Cuckoo self);
/**
* Get the number of elements stored in a hash.
* @return number of elements, 0 when empty
*/
size_t
cuckoo_nelements (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.
* Inserting an element already in the hash calls the dtor for the old entry and places
* the new one into the hash.
* @param self handle to the hash table
* @param item pointer to a item to be inserted
* @return pointer to inserted element on successful insert, NULL on allocation failure
* Note: at failure there is one arbitary hash cell lost!
*/
void*
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:
*/

View file

@ -402,9 +402,7 @@ TESTS_END
/*
cuckoo support functions
*/
/* === PSplay support functions === */
static int
cmp_fn (const void* a, const void* b)
@ -431,10 +429,6 @@ delete_fn (PSplaynode node)
}
//static psplay_delete_fn
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
//{
//}
static int
@ -455,10 +449,6 @@ fdelete_fn (PSplaynode node)
testitem_delete ((TestItem) node);
}
//static psplay_delete_fn
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
//{
//}