122944501Smrg/* xf86drmHash.c -- Small hash table support for integer -> integer mapping 222944501Smrg * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com 322944501Smrg * 422944501Smrg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 522944501Smrg * All Rights Reserved. 622944501Smrg * 722944501Smrg * Permission is hereby granted, free of charge, to any person obtaining a 822944501Smrg * copy of this software and associated documentation files (the "Software"), 922944501Smrg * to deal in the Software without restriction, including without limitation 1022944501Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1122944501Smrg * and/or sell copies of the Software, and to permit persons to whom the 1222944501Smrg * Software is furnished to do so, subject to the following conditions: 1322944501Smrg * 1422944501Smrg * The above copyright notice and this permission notice (including the next 1522944501Smrg * paragraph) shall be included in all copies or substantial portions of the 1622944501Smrg * Software. 1722944501Smrg * 1822944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1922944501Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2022944501Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2122944501Smrg * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2222944501Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2322944501Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2422944501Smrg * DEALINGS IN THE SOFTWARE. 2522944501Smrg * 2622944501Smrg * Authors: Rickard E. (Rik) Faith <faith@valinux.com> 2722944501Smrg * 2822944501Smrg * DESCRIPTION 2922944501Smrg * 3022944501Smrg * This file contains a straightforward implementation of a fixed-sized 3122944501Smrg * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for 3222944501Smrg * collision resolution. There are two potentially interesting things 3322944501Smrg * about this implementation: 3422944501Smrg * 3522944501Smrg * 1) The table is power-of-two sized. Prime sized tables are more 3622944501Smrg * traditional, but do not have a significant advantage over power-of-two 3722944501Smrg * sized table, especially when double hashing is not used for collision 3822944501Smrg * resolution. 3922944501Smrg * 4022944501Smrg * 2) The hash computation uses a table of random integers [Hanson97, 4122944501Smrg * pp. 39-41]. 4222944501Smrg * 4322944501Smrg * FUTURE ENHANCEMENTS 4422944501Smrg * 4522944501Smrg * With a table size of 512, the current implementation is sufficient for a 4622944501Smrg * few hundred keys. Since this is well above the expected size of the 4722944501Smrg * tables for which this implementation was designed, the implementation of 4822944501Smrg * dynamic hash tables was postponed until the need arises. A common (and 4922944501Smrg * naive) approach to dynamic hash table implementation simply creates a 5022944501Smrg * new hash table when necessary, rehashes all the data into the new table, 5122944501Smrg * and destroys the old table. The approach in [Larson88] is superior in 5222944501Smrg * two ways: 1) only a portion of the table is expanded when needed, 5322944501Smrg * distributing the expansion cost over several insertions, and 2) portions 5422944501Smrg * of the table can be locked, enabling a scalable thread-safe 5522944501Smrg * implementation. 5622944501Smrg * 5722944501Smrg * REFERENCES 5822944501Smrg * 5922944501Smrg * [Hanson97] David R. Hanson. C Interfaces and Implementations: 6022944501Smrg * Techniques for Creating Reusable Software. Reading, Massachusetts: 6122944501Smrg * Addison-Wesley, 1997. 6222944501Smrg * 6322944501Smrg * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: 6422944501Smrg * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. 6522944501Smrg * 6622944501Smrg * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April 6722944501Smrg * 1988, pp. 446-457. 6822944501Smrg * 6922944501Smrg */ 7022944501Smrg 7122944501Smrg#include <stdio.h> 7222944501Smrg#include <stdlib.h> 7322944501Smrg 747cdc0497Smrg#include "libdrm_macros.h" 75e6188e58Smrg#include "xf86drm.h" 76e6188e58Smrg#include "xf86drmHash.h" 7722944501Smrg 7822944501Smrg#define HASH_MAGIC 0xdeadbeef 7922944501Smrg 8022944501Smrgstatic unsigned long HashHash(unsigned long key) 8122944501Smrg{ 8222944501Smrg unsigned long hash = 0; 8322944501Smrg unsigned long tmp = key; 8422944501Smrg static int init = 0; 8522944501Smrg static unsigned long scatter[256]; 8622944501Smrg int i; 8722944501Smrg 8822944501Smrg if (!init) { 89e6188e58Smrg void *state; 90e6188e58Smrg state = drmRandomCreate(37); 91e6188e58Smrg for (i = 0; i < 256; i++) scatter[i] = drmRandom(state); 92e6188e58Smrg drmRandomDestroy(state); 9322944501Smrg ++init; 9422944501Smrg } 9522944501Smrg 9622944501Smrg while (tmp) { 9722944501Smrg hash = (hash << 1) + scatter[tmp & 0xff]; 9822944501Smrg tmp >>= 8; 9922944501Smrg } 10022944501Smrg 10122944501Smrg hash %= HASH_SIZE; 10222944501Smrg return hash; 10322944501Smrg} 10422944501Smrg 1057cdc0497Smrgdrm_public void *drmHashCreate(void) 10622944501Smrg{ 10722944501Smrg HashTablePtr table; 10822944501Smrg 109e6188e58Smrg table = drmMalloc(sizeof(*table)); 11022944501Smrg if (!table) return NULL; 11122944501Smrg table->magic = HASH_MAGIC; 11222944501Smrg 11322944501Smrg return table; 11422944501Smrg} 11522944501Smrg 1167cdc0497Smrgdrm_public int drmHashDestroy(void *t) 11722944501Smrg{ 11822944501Smrg HashTablePtr table = (HashTablePtr)t; 11922944501Smrg HashBucketPtr bucket; 12022944501Smrg HashBucketPtr next; 12122944501Smrg int i; 12222944501Smrg 12322944501Smrg if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ 12422944501Smrg 12522944501Smrg for (i = 0; i < HASH_SIZE; i++) { 12622944501Smrg for (bucket = table->buckets[i]; bucket;) { 12722944501Smrg next = bucket->next; 128e6188e58Smrg drmFree(bucket); 12922944501Smrg bucket = next; 13022944501Smrg } 13122944501Smrg } 132e6188e58Smrg drmFree(table); 13322944501Smrg return 0; 13422944501Smrg} 13522944501Smrg 13622944501Smrg/* Find the bucket and organize the list so that this bucket is at the 13722944501Smrg top. */ 13822944501Smrg 13922944501Smrgstatic HashBucketPtr HashFind(HashTablePtr table, 14022944501Smrg unsigned long key, unsigned long *h) 14122944501Smrg{ 14222944501Smrg unsigned long hash = HashHash(key); 14322944501Smrg HashBucketPtr prev = NULL; 14422944501Smrg HashBucketPtr bucket; 14522944501Smrg 14622944501Smrg if (h) *h = hash; 14722944501Smrg 14822944501Smrg for (bucket = table->buckets[hash]; bucket; bucket = bucket->next) { 14922944501Smrg if (bucket->key == key) { 15022944501Smrg if (prev) { 15122944501Smrg /* Organize */ 15222944501Smrg prev->next = bucket->next; 15322944501Smrg bucket->next = table->buckets[hash]; 15422944501Smrg table->buckets[hash] = bucket; 15522944501Smrg ++table->partials; 15622944501Smrg } else { 15722944501Smrg ++table->hits; 15822944501Smrg } 15922944501Smrg return bucket; 16022944501Smrg } 16122944501Smrg prev = bucket; 16222944501Smrg } 16322944501Smrg ++table->misses; 16422944501Smrg return NULL; 16522944501Smrg} 16622944501Smrg 1677cdc0497Smrgdrm_public int drmHashLookup(void *t, unsigned long key, void **value) 16822944501Smrg{ 16922944501Smrg HashTablePtr table = (HashTablePtr)t; 17022944501Smrg HashBucketPtr bucket; 17122944501Smrg 17222944501Smrg if (!table || table->magic != HASH_MAGIC) return -1; /* Bad magic */ 17322944501Smrg 17422944501Smrg bucket = HashFind(table, key, NULL); 17522944501Smrg if (!bucket) return 1; /* Not found */ 17622944501Smrg *value = bucket->value; 17722944501Smrg return 0; /* Found */ 17822944501Smrg} 17922944501Smrg 1807cdc0497Smrgdrm_public int drmHashInsert(void *t, unsigned long key, void *value) 18122944501Smrg{ 18222944501Smrg HashTablePtr table = (HashTablePtr)t; 18322944501Smrg HashBucketPtr bucket; 18422944501Smrg unsigned long hash; 18522944501Smrg 18622944501Smrg if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ 18722944501Smrg 18822944501Smrg if (HashFind(table, key, &hash)) return 1; /* Already in table */ 18922944501Smrg 190e6188e58Smrg bucket = drmMalloc(sizeof(*bucket)); 19122944501Smrg if (!bucket) return -1; /* Error */ 19222944501Smrg bucket->key = key; 19322944501Smrg bucket->value = value; 19422944501Smrg bucket->next = table->buckets[hash]; 19522944501Smrg table->buckets[hash] = bucket; 19622944501Smrg return 0; /* Added to table */ 19722944501Smrg} 19822944501Smrg 1997cdc0497Smrgdrm_public int drmHashDelete(void *t, unsigned long key) 20022944501Smrg{ 20122944501Smrg HashTablePtr table = (HashTablePtr)t; 20222944501Smrg unsigned long hash; 20322944501Smrg HashBucketPtr bucket; 20422944501Smrg 20522944501Smrg if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ 20622944501Smrg 20722944501Smrg bucket = HashFind(table, key, &hash); 20822944501Smrg 20922944501Smrg if (!bucket) return 1; /* Not found */ 21022944501Smrg 21122944501Smrg table->buckets[hash] = bucket->next; 212e6188e58Smrg drmFree(bucket); 21322944501Smrg return 0; 21422944501Smrg} 21522944501Smrg 2167cdc0497Smrgdrm_public int drmHashNext(void *t, unsigned long *key, void **value) 21722944501Smrg{ 21822944501Smrg HashTablePtr table = (HashTablePtr)t; 21922944501Smrg 22022944501Smrg while (table->p0 < HASH_SIZE) { 22122944501Smrg if (table->p1) { 22222944501Smrg *key = table->p1->key; 22322944501Smrg *value = table->p1->value; 22422944501Smrg table->p1 = table->p1->next; 22522944501Smrg return 1; 22622944501Smrg } 22722944501Smrg table->p1 = table->buckets[table->p0]; 22822944501Smrg ++table->p0; 22922944501Smrg } 23022944501Smrg return 0; 23122944501Smrg} 23222944501Smrg 2337cdc0497Smrgdrm_public int drmHashFirst(void *t, unsigned long *key, void **value) 23422944501Smrg{ 23522944501Smrg HashTablePtr table = (HashTablePtr)t; 23622944501Smrg 23722944501Smrg if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ 23822944501Smrg 23922944501Smrg table->p0 = 0; 24022944501Smrg table->p1 = table->buckets[0]; 24122944501Smrg return drmHashNext(table, key, value); 24222944501Smrg} 243