/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Hash, "Direct/Hash", "Hash table implementation" ); #define REMOVED ((void *) -1) typedef struct { unsigned long key; void *value; } Element; struct __D_DirectHash { int magic; int size; int count; int removed; Element *elements; }; /**************************************************************************************************/ static inline int locate_key( const DirectHash *hash, unsigned long key ) { int pos; const Element *element; pos = key % hash->size; element = &hash->elements[pos]; while (element->value) { if (element->value != REMOVED && element->key == key) return pos; if (++pos == hash->size) pos = 0; element = &hash->elements[pos]; } return -1; } /**************************************************************************************************/ DirectResult direct_hash_create( int size, DirectHash **ret_hash ) { DirectHash *hash; if (size < 17) size = 17; D_DEBUG_AT( Direct_Hash, "Creating hash table with initial capacity of %d...\n", size ); hash = D_CALLOC( 1, sizeof (DirectHash) ); if (!hash) { D_WARN( "out of memory" ); return DR_NOLOCALMEMORY; } hash->size = size; hash->elements = D_CALLOC( size, sizeof(Element) ); if (!hash->elements) { D_WARN( "out of memory" ); D_FREE( hash ); return DR_NOLOCALMEMORY; } D_MAGIC_SET( hash, DirectHash ); *ret_hash = hash; return DR_OK; } void direct_hash_destroy( DirectHash *hash ) { D_MAGIC_ASSERT( hash, DirectHash ); D_MAGIC_CLEAR( hash ); D_FREE( hash->elements ); D_FREE( hash ); } DirectResult direct_hash_insert( DirectHash *hash, unsigned long key, void *value ) { int pos; Element *element; D_MAGIC_ASSERT( hash, DirectHash ); D_ASSERT( value != NULL ); /* Need to resize the hash table? */ if ((hash->count + hash->removed) > hash->size / 4) { int i, size = hash->size * 3; Element *elements; D_DEBUG_AT( Direct_Hash, "Resizing from %d to %d... (count %d, removed %d)\n", hash->size, size, hash->count, hash->removed ); elements = D_CALLOC( size, sizeof(Element) ); if (!elements) { D_WARN( "out of memory" ); return DR_NOLOCALMEMORY; } for (i=0; isize; i++) { Element *element = &hash->elements[i]; Element *insertElement; if (element->value && element->value != REMOVED) { pos = element->key % size; insertElement = &elements[pos]; while (insertElement->value && insertElement->value != REMOVED) { if (++pos == size) pos = 0; insertElement = &elements[pos]; } elements[pos] = *element; } } D_FREE( hash->elements ); hash->size = size; hash->elements = elements; hash->removed = 0; } pos = key % hash->size; D_DEBUG_AT( Direct_Hash, "Attempting to insert key 0x%08lx at position %d...\n", key, pos ); element = &hash->elements[pos]; while (element->value && element->value != REMOVED) { if (element->key == key) { D_BUG( "key already exists" ); return DR_BUG; } if (++pos == hash->size) pos = 0; element = &hash->elements[pos]; } if (element->value == REMOVED) hash->removed--; element->key = key; element->value = value; hash->count++; D_DEBUG_AT( Direct_Hash, "...inserted at %d, new count = %d, removed = %d, size = %d, key = 0x%08lx.\n", pos, hash->count, hash->removed, hash->size, key ); return DR_OK; } void direct_hash_remove( DirectHash *hash, unsigned long key ) { int pos; D_MAGIC_ASSERT( hash, DirectHash ); pos = locate_key( hash, key ); if (pos == -1) { D_WARN( "key not found" ); return; } hash->elements[pos].value = REMOVED; hash->count--; hash->removed++; D_DEBUG_AT( Direct_Hash, "Removed key 0x%08lx at %d, new count = %d, removed = %d, size = %d.\n", key, pos, hash->count, hash->removed, hash->size ); } void * direct_hash_lookup( DirectHash *hash, unsigned long key ) { int pos; D_MAGIC_ASSERT( hash, DirectHash ); pos = locate_key( hash, key ); return (pos != -1) ? hash->elements[pos].value : NULL; } void direct_hash_iterate( DirectHash *hash, DirectHashIteratorFunc func, void *ctx ) { int i; D_MAGIC_ASSERT( hash, DirectHash ); for (i=0; isize; i++) { Element *element = &hash->elements[i]; if (!element->value || element->value == REMOVED) continue; if (!func( hash, element->key, element->value, ctx ) ) return; } }