fchash.c revision 1887081f
11887081fSmrg/* 21887081fSmrg * Copyright © 2000 Keith Packard 31887081fSmrg * 41887081fSmrg * Permission to use, copy, modify, distribute, and sell this software and its 51887081fSmrg * documentation for any purpose is hereby granted without fee, provided that 61887081fSmrg * the above copyright notice appear in all copies and that both that 71887081fSmrg * copyright notice and this permission notice appear in supporting 81887081fSmrg * documentation, and that the name of the author(s) not be used in 91887081fSmrg * advertising or publicity pertaining to distribution of the software without 101887081fSmrg * specific, written prior permission. The authors make no 111887081fSmrg * representations about the suitability of this software for any purpose. It 121887081fSmrg * is provided "as is" without express or implied warranty. 131887081fSmrg * 141887081fSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 151887081fSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 161887081fSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 171887081fSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 181887081fSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 191887081fSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 201887081fSmrg * PERFORMANCE OF THIS SOFTWARE. 211887081fSmrg */ 221887081fSmrg#include "fcint.h" 231887081fSmrg#if !defined TOOL_FCCACHE 241887081fSmrg#ifndef _WIN32 251887081fSmrg#include <uuid/uuid.h> 261887081fSmrg#endif 271887081fSmrg#endif 281887081fSmrg 291887081fSmrg#define FC_HASH_SIZE 227 301887081fSmrg 311887081fSmrgtypedef struct _FcHashBucket { 321887081fSmrg struct _FcHashBucket *next; 331887081fSmrg void *key; 341887081fSmrg void *value; 351887081fSmrg} FcHashBucket; 361887081fSmrg 371887081fSmrgstruct _FcHashTable { 381887081fSmrg FcHashBucket *buckets[FC_HASH_SIZE]; 391887081fSmrg FcHashFunc hash_func; 401887081fSmrg FcCompareFunc compare_func; 411887081fSmrg FcCopyFunc key_copy_func; 421887081fSmrg FcCopyFunc value_copy_func; 431887081fSmrg FcDestroyFunc key_destroy_func; 441887081fSmrg FcDestroyFunc value_destroy_func; 451887081fSmrg}; 461887081fSmrg 471887081fSmrg 481887081fSmrgFcBool 491887081fSmrgFcHashStrCopy (const void *src, 501887081fSmrg void **dest) 511887081fSmrg{ 521887081fSmrg *dest = FcStrdup (src); 531887081fSmrg 541887081fSmrg return *dest != NULL; 551887081fSmrg} 561887081fSmrg 571887081fSmrgFcBool 581887081fSmrgFcHashUuidCopy (const void *src, 591887081fSmrg void **dest) 601887081fSmrg{ 611887081fSmrg#if !defined TOOL_FCCACHE 621887081fSmrg#ifndef _WIN32 631887081fSmrg *dest = malloc (sizeof (uuid_t)); 641887081fSmrg uuid_copy (*dest, src); 651887081fSmrg#endif 661887081fSmrg#endif 671887081fSmrg return FcTrue; 681887081fSmrg} 691887081fSmrg 701887081fSmrgvoid 711887081fSmrgFcHashUuidFree (void *data) 721887081fSmrg{ 731887081fSmrg free (data); 741887081fSmrg} 751887081fSmrg 761887081fSmrgFcHashTable * 771887081fSmrgFcHashTableCreate (FcHashFunc hash_func, 781887081fSmrg FcCompareFunc compare_func, 791887081fSmrg FcCopyFunc key_copy_func, 801887081fSmrg FcCopyFunc value_copy_func, 811887081fSmrg FcDestroyFunc key_destroy_func, 821887081fSmrg FcDestroyFunc value_destroy_func) 831887081fSmrg{ 841887081fSmrg FcHashTable *ret = malloc (sizeof (FcHashTable)); 851887081fSmrg 861887081fSmrg if (ret) 871887081fSmrg { 881887081fSmrg memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE); 891887081fSmrg ret->hash_func = hash_func; 901887081fSmrg ret->compare_func = compare_func; 911887081fSmrg ret->key_copy_func = key_copy_func; 921887081fSmrg ret->value_copy_func = value_copy_func; 931887081fSmrg ret->key_destroy_func = key_destroy_func; 941887081fSmrg ret->value_destroy_func = value_destroy_func; 951887081fSmrg } 961887081fSmrg return ret; 971887081fSmrg} 981887081fSmrg 991887081fSmrgvoid 1001887081fSmrgFcHashTableDestroy (FcHashTable *table) 1011887081fSmrg{ 1021887081fSmrg int i; 1031887081fSmrg 1041887081fSmrg for (i = 0; i < FC_HASH_SIZE; i++) 1051887081fSmrg { 1061887081fSmrg FcHashBucket *bucket = table->buckets[i], *prev; 1071887081fSmrg 1081887081fSmrg while (bucket) 1091887081fSmrg { 1101887081fSmrg if (table->key_destroy_func) 1111887081fSmrg table->key_destroy_func (bucket->key); 1121887081fSmrg if (table->value_destroy_func) 1131887081fSmrg table->value_destroy_func (bucket->value); 1141887081fSmrg prev = bucket; 1151887081fSmrg bucket = bucket->next; 1161887081fSmrg free (prev); 1171887081fSmrg } 1181887081fSmrg table->buckets[i] = NULL; 1191887081fSmrg } 1201887081fSmrg free (table); 1211887081fSmrg} 1221887081fSmrg 1231887081fSmrgFcBool 1241887081fSmrgFcHashTableFind (FcHashTable *table, 1251887081fSmrg const void *key, 1261887081fSmrg void **value) 1271887081fSmrg{ 1281887081fSmrg FcHashBucket *bucket; 1291887081fSmrg FcChar32 hash = table->hash_func (key); 1301887081fSmrg 1311887081fSmrg for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next) 1321887081fSmrg { 1331887081fSmrg if (!table->compare_func(bucket->key, key)) 1341887081fSmrg { 1351887081fSmrg if (table->value_copy_func) 1361887081fSmrg { 1371887081fSmrg if (!table->value_copy_func (bucket->value, value)) 1381887081fSmrg return FcFalse; 1391887081fSmrg } 1401887081fSmrg else 1411887081fSmrg *value = bucket->value; 1421887081fSmrg return FcTrue; 1431887081fSmrg } 1441887081fSmrg } 1451887081fSmrg return FcFalse; 1461887081fSmrg} 1471887081fSmrg 1481887081fSmrgstatic FcBool 1491887081fSmrgFcHashTableAddInternal (FcHashTable *table, 1501887081fSmrg void *key, 1511887081fSmrg void *value, 1521887081fSmrg FcBool replace) 1531887081fSmrg{ 1541887081fSmrg FcHashBucket **prev, *bucket, *b; 1551887081fSmrg FcChar32 hash = table->hash_func (key); 1561887081fSmrg FcBool ret = FcFalse; 1571887081fSmrg 1581887081fSmrg bucket = (FcHashBucket *) malloc (sizeof (FcHashBucket)); 1591887081fSmrg if (!bucket) 1601887081fSmrg return FcFalse; 1611887081fSmrg memset (bucket, 0, sizeof (FcHashBucket)); 1621887081fSmrg if (table->key_copy_func) 1631887081fSmrg ret |= !table->key_copy_func (key, &bucket->key); 1641887081fSmrg else 1651887081fSmrg bucket->key = key; 1661887081fSmrg if (table->value_copy_func) 1671887081fSmrg ret |= !table->value_copy_func (value, &bucket->value); 1681887081fSmrg else 1691887081fSmrg bucket->value = value; 1701887081fSmrg if (ret) 1711887081fSmrg { 1721887081fSmrg destroy: 1731887081fSmrg if (bucket->key && table->key_destroy_func) 1741887081fSmrg table->key_destroy_func (bucket->key); 1751887081fSmrg if (bucket->value && table->value_destroy_func) 1761887081fSmrg table->value_destroy_func (bucket->value); 1771887081fSmrg free (bucket); 1781887081fSmrg 1791887081fSmrg return !ret; 1801887081fSmrg } 1811887081fSmrg retry: 1821887081fSmrg for (prev = &table->buckets[hash % FC_HASH_SIZE]; 1831887081fSmrg (b = fc_atomic_ptr_get (prev)); prev = &(b->next)) 1841887081fSmrg { 1851887081fSmrg if (!table->compare_func (b->key, key)) 1861887081fSmrg { 1871887081fSmrg if (replace) 1881887081fSmrg { 1891887081fSmrg bucket->next = b->next; 1901887081fSmrg if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) 1911887081fSmrg goto retry; 1921887081fSmrg bucket = b; 1931887081fSmrg } 1941887081fSmrg else 1951887081fSmrg ret = FcTrue; 1961887081fSmrg goto destroy; 1971887081fSmrg } 1981887081fSmrg } 1991887081fSmrg bucket->next = NULL; 2001887081fSmrg if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) 2011887081fSmrg goto retry; 2021887081fSmrg 2031887081fSmrg return FcTrue; 2041887081fSmrg} 2051887081fSmrg 2061887081fSmrgFcBool 2071887081fSmrgFcHashTableAdd (FcHashTable *table, 2081887081fSmrg void *key, 2091887081fSmrg void *value) 2101887081fSmrg{ 2111887081fSmrg return FcHashTableAddInternal (table, key, value, FcFalse); 2121887081fSmrg} 2131887081fSmrg 2141887081fSmrgFcBool 2151887081fSmrgFcHashTableReplace (FcHashTable *table, 2161887081fSmrg void *key, 2171887081fSmrg void *value) 2181887081fSmrg{ 2191887081fSmrg return FcHashTableAddInternal (table, key, value, FcTrue); 2201887081fSmrg} 2211887081fSmrg 2221887081fSmrgFcBool 2231887081fSmrgFcHashTableRemove (FcHashTable *table, 2241887081fSmrg void *key) 2251887081fSmrg{ 2261887081fSmrg FcHashBucket **prev, *bucket; 2271887081fSmrg FcChar32 hash = table->hash_func (key); 2281887081fSmrg FcBool ret = FcFalse; 2291887081fSmrg 2301887081fSmrgretry: 2311887081fSmrg for (prev = &table->buckets[hash % FC_HASH_SIZE]; 2321887081fSmrg (bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next)) 2331887081fSmrg { 2341887081fSmrg if (!table->compare_func (bucket->key, key)) 2351887081fSmrg { 2361887081fSmrg if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next)) 2371887081fSmrg goto retry; 2381887081fSmrg if (table->key_destroy_func) 2391887081fSmrg table->key_destroy_func (bucket->key); 2401887081fSmrg if (table->value_destroy_func) 2411887081fSmrg table->value_destroy_func (bucket->value); 2421887081fSmrg free (bucket); 2431887081fSmrg ret = FcTrue; 2441887081fSmrg break; 2451887081fSmrg } 2461887081fSmrg } 2471887081fSmrg 2481887081fSmrg return ret; 2491887081fSmrg} 250