2012-02-11 04:16:17 +00:00
|
|
|
/*
|
2011-09-09 02:52:20 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* 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,
|
2012-02-11 04:16:17 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2011-09-09 02:52:20 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): Joseph Eagar.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2013-09-12 03:02:50 +00:00
|
|
|
/** \file blender/blenlib/intern/smallhash.c
|
|
|
|
* \ingroup bli
|
2014-01-22 02:48:11 +11:00
|
|
|
*
|
|
|
|
* A light stack-friendly hash library, it uses stack space for smallish hash tables
|
|
|
|
* but falls back to heap memory once the stack limits reached.
|
|
|
|
*
|
|
|
|
* based on a doubling non-chaining approach
|
2013-09-12 03:02:50 +00:00
|
|
|
*/
|
|
|
|
|
2012-02-12 17:44:10 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2011-09-09 02:52:20 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
|
|
|
#include "BLI_smallhash.h"
|
2014-01-22 02:48:11 +11:00
|
|
|
|
2013-09-01 00:46:04 +00:00
|
|
|
#include "BLI_strict_flags.h"
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
/* SMHASH_CELL_UNUSED means this cell is inside a key series,
|
|
|
|
* while SMHASH_CELL_FREE means this cell terminates a key series.
|
|
|
|
*
|
|
|
|
* no chance of anyone shoving INT32_MAX-2 into a *val pointer, I
|
|
|
|
* imagine. hopefully.
|
|
|
|
*
|
2014-01-22 02:48:11 +11:00
|
|
|
* note: these have the SMHASH prefix because we may want to make them public.
|
2011-09-09 02:52:20 +00:00
|
|
|
*/
|
2012-05-12 15:02:10 +00:00
|
|
|
#define SMHASH_CELL_UNUSED ((void *)0x7FFFFFFF)
|
|
|
|
#define SMHASH_CELL_FREE ((void *)0x7FFFFFFD)
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2012-11-06 04:17:46 +00:00
|
|
|
/* typically this re-assigns 'h' */
|
|
|
|
#define SMHASH_NEXT(h, hoff) ( \
|
2013-08-17 04:48:34 +00:00
|
|
|
CHECK_TYPE_INLINE(&(h), unsigned int *), \
|
|
|
|
CHECK_TYPE_INLINE(&(hoff), unsigned int *), \
|
2013-05-08 12:54:07 +00:00
|
|
|
((h) + (((hoff) = ((hoff) * 2) + 1), (hoff))) \
|
2012-11-06 04:17:46 +00:00
|
|
|
)
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2013-10-10 20:22:17 +00:00
|
|
|
extern const unsigned int hashsizes[];
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
void BLI_smallhash_init(SmallHash *hash)
|
|
|
|
{
|
2013-06-22 20:20:06 +00:00
|
|
|
unsigned int i;
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
memset(hash, 0, sizeof(*hash));
|
|
|
|
|
|
|
|
hash->table = hash->_stacktable;
|
|
|
|
hash->curhash = 2;
|
|
|
|
hash->size = hashsizes[hash->curhash];
|
|
|
|
|
|
|
|
hash->copytable = hash->_copytable;
|
|
|
|
hash->stacktable = hash->_stacktable;
|
|
|
|
|
2012-02-12 17:44:10 +00:00
|
|
|
for (i = 0; i < hash->size; i++) {
|
2011-09-09 02:52:20 +00:00
|
|
|
hash->table[i].val = SMHASH_CELL_FREE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*NOTE: does *not* free *hash itself! only the direct data!*/
|
|
|
|
void BLI_smallhash_release(SmallHash *hash)
|
|
|
|
{
|
|
|
|
if (hash->table != hash->stacktable) {
|
|
|
|
MEM_freeN(hash->table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *hash, uintptr_t key)
|
|
|
|
{
|
|
|
|
SmallHashEntry *entry;
|
|
|
|
unsigned int h = (unsigned int)key;
|
|
|
|
unsigned int hoff = 1;
|
|
|
|
|
|
|
|
for (entry = &hash->table[h % hash->size];
|
2014-01-28 23:00:28 +11:00
|
|
|
!ELEM(entry->val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE);
|
|
|
|
h = SMHASH_NEXT(h, hoff), entry = &hash->table[h % hash->size])
|
2014-01-26 15:17:06 +01:00
|
|
|
{
|
|
|
|
/* Nothing else to do! */
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2011-09-09 02:52:20 +00:00
|
|
|
void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item)
|
|
|
|
{
|
2014-01-26 15:17:06 +01:00
|
|
|
SmallHashEntry *entry;
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
if (hash->size < hash->used * 3) {
|
2013-05-08 12:54:07 +00:00
|
|
|
unsigned int newsize = hashsizes[++hash->curhash];
|
2011-09-09 02:52:20 +00:00
|
|
|
SmallHashEntry *tmp;
|
2013-06-22 20:20:06 +00:00
|
|
|
unsigned int i = 0;
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
if (hash->table != hash->stacktable || newsize > SMSTACKSIZE) {
|
2012-02-17 05:33:23 +00:00
|
|
|
tmp = MEM_callocN(sizeof(*hash->table) * newsize, __func__);
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
SWAP(SmallHashEntry *, hash->stacktable, hash->copytable);
|
|
|
|
tmp = hash->stacktable;
|
|
|
|
}
|
|
|
|
|
|
|
|
SWAP(SmallHashEntry *, tmp, hash->table);
|
|
|
|
|
|
|
|
hash->size = newsize;
|
|
|
|
|
2012-02-12 17:44:10 +00:00
|
|
|
for (i = 0; i < hash->size; i++) {
|
2011-09-09 02:52:20 +00:00
|
|
|
hash->table[i].val = SMHASH_CELL_FREE;
|
|
|
|
}
|
|
|
|
|
2012-05-12 15:02:10 +00:00
|
|
|
for (i = 0; i < hashsizes[hash->curhash - 1]; i++) {
|
2011-09-09 02:52:20 +00:00
|
|
|
if (ELEM(tmp[i].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
entry = smallhash_lookup_first_free(hash, tmp[i].key);
|
|
|
|
entry->key = tmp[i].key;
|
|
|
|
entry->val = tmp[i].val;
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp != hash->stacktable && tmp != hash->copytable) {
|
|
|
|
MEM_freeN(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
entry = smallhash_lookup_first_free(hash, key);
|
|
|
|
entry->key = key;
|
|
|
|
entry->val = item;
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
hash->used++;
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *hash, uintptr_t key)
|
2011-09-09 02:52:20 +00:00
|
|
|
{
|
2014-01-26 15:17:06 +01:00
|
|
|
SmallHashEntry *entry;
|
|
|
|
unsigned int h = (unsigned int)key;
|
|
|
|
unsigned int hoff = 1;
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
for (entry = &hash->table[h % hash->size];
|
|
|
|
((entry->key != key) || (entry->val == SMHASH_CELL_UNUSED)) && (entry->val != SMHASH_CELL_FREE);
|
|
|
|
h = SMHASH_NEXT(h, hoff), entry = &hash->table[h % hash->size])
|
2011-09-09 02:52:20 +00:00
|
|
|
{
|
2014-01-26 15:17:06 +01:00
|
|
|
/* Nothing else to do! */
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
return entry;
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
void BLI_smallhash_remove(SmallHash *hash, uintptr_t key)
|
2011-09-09 02:52:20 +00:00
|
|
|
{
|
2014-01-26 15:17:06 +01:00
|
|
|
SmallHashEntry *entry = smallhash_lookup(hash, key);
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
if (entry->val != SMHASH_CELL_FREE) {
|
|
|
|
entry->key = 0;
|
|
|
|
entry->val = SMHASH_CELL_UNUSED;
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
2014-01-26 15:17:06 +01:00
|
|
|
}
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
void *BLI_smallhash_lookup(SmallHash *hash, uintptr_t key)
|
|
|
|
{
|
|
|
|
SmallHashEntry *entry = smallhash_lookup(hash, key);
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
return ELEM(entry->val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE) ? NULL : entry->val;
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-22 02:48:11 +11:00
|
|
|
bool BLI_smallhash_haskey(SmallHash *hash, uintptr_t key)
|
2011-09-09 02:52:20 +00:00
|
|
|
{
|
2014-01-26 15:17:06 +01:00
|
|
|
SmallHashEntry *entry = smallhash_lookup(hash, key);
|
2011-09-09 02:52:20 +00:00
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
return !ELEM(entry->val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE);
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int BLI_smallhash_count(SmallHash *hash)
|
|
|
|
{
|
2013-05-08 12:54:07 +00:00
|
|
|
return (int)hash->used;
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
|
|
|
|
{
|
|
|
|
while (iter->i < iter->hash->size) {
|
2013-04-20 16:49:02 +00:00
|
|
|
if ((iter->hash->table[iter->i].val != SMHASH_CELL_UNUSED) &&
|
|
|
|
(iter->hash->table[iter->i].val != SMHASH_CELL_FREE))
|
2011-09-09 02:52:20 +00:00
|
|
|
{
|
|
|
|
if (key) {
|
|
|
|
*key = iter->hash->table[iter->i].key;
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:17:06 +01:00
|
|
|
return iter->hash->table[iter->i++].val;
|
2011-09-09 02:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
iter->i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key)
|
|
|
|
{
|
|
|
|
iter->hash = hash;
|
|
|
|
iter->i = 0;
|
|
|
|
|
|
|
|
return BLI_smallhash_iternext(iter, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* note, this was called _print_smhash in knifetool.c
|
|
|
|
* it may not be intended for general use - campbell */
|
|
|
|
#if 0
|
|
|
|
void BLI_smallhash_print(SmallHash *hash)
|
|
|
|
{
|
2012-05-12 15:02:10 +00:00
|
|
|
int i, linecol = 79, c = 0;
|
2011-09-09 02:52:20 +00:00
|
|
|
|
|
|
|
printf("{");
|
2012-05-12 15:02:10 +00:00
|
|
|
for (i = 0; i < hash->size; i++) {
|
2011-09-09 02:52:20 +00:00
|
|
|
if (hash->table[i].val == SMHASH_CELL_UNUSED) {
|
|
|
|
printf("--u-");
|
|
|
|
}
|
|
|
|
else if (hash->table[i].val == SMHASH_CELL_FREE) {
|
|
|
|
printf("--f-");
|
|
|
|
}
|
2012-05-12 15:02:10 +00:00
|
|
|
else {
|
2011-09-09 02:52:20 +00:00
|
|
|
printf("%2x", (unsigned int)hash->table[i].key);
|
|
|
|
}
|
|
|
|
|
2012-05-12 15:02:10 +00:00
|
|
|
if (i != hash->size - 1)
|
2011-09-09 02:52:20 +00:00
|
|
|
printf(", ");
|
|
|
|
|
|
|
|
c += 6;
|
|
|
|
|
|
|
|
if (c >= linecol) {
|
|
|
|
printf("\n ");
|
|
|
|
c = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
#endif
|