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 241887081fSmrg#define FC_HASH_SIZE 227 251887081fSmrg 261887081fSmrgtypedef struct _FcHashBucket { 271887081fSmrg struct _FcHashBucket *next; 281887081fSmrg void *key; 291887081fSmrg void *value; 301887081fSmrg} FcHashBucket; 311887081fSmrg 321887081fSmrgstruct _FcHashTable { 331887081fSmrg FcHashBucket *buckets[FC_HASH_SIZE]; 341887081fSmrg FcHashFunc hash_func; 351887081fSmrg FcCompareFunc compare_func; 361887081fSmrg FcCopyFunc key_copy_func; 371887081fSmrg FcCopyFunc value_copy_func; 381887081fSmrg FcDestroyFunc key_destroy_func; 391887081fSmrg FcDestroyFunc value_destroy_func; 401887081fSmrg}; 411887081fSmrg 421887081fSmrg 431887081fSmrgFcBool 441887081fSmrgFcHashStrCopy (const void *src, 451887081fSmrg void **dest) 461887081fSmrg{ 471887081fSmrg *dest = FcStrdup (src); 481887081fSmrg 491887081fSmrg return *dest != NULL; 501887081fSmrg} 511887081fSmrg 521887081fSmrgFcHashTable * 531887081fSmrgFcHashTableCreate (FcHashFunc hash_func, 541887081fSmrg FcCompareFunc compare_func, 551887081fSmrg FcCopyFunc key_copy_func, 561887081fSmrg FcCopyFunc value_copy_func, 571887081fSmrg FcDestroyFunc key_destroy_func, 581887081fSmrg FcDestroyFunc value_destroy_func) 591887081fSmrg{ 601887081fSmrg FcHashTable *ret = malloc (sizeof (FcHashTable)); 611887081fSmrg 621887081fSmrg if (ret) 631887081fSmrg { 641887081fSmrg memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE); 651887081fSmrg ret->hash_func = hash_func; 661887081fSmrg ret->compare_func = compare_func; 671887081fSmrg ret->key_copy_func = key_copy_func; 681887081fSmrg ret->value_copy_func = value_copy_func; 691887081fSmrg ret->key_destroy_func = key_destroy_func; 701887081fSmrg ret->value_destroy_func = value_destroy_func; 711887081fSmrg } 721887081fSmrg return ret; 731887081fSmrg} 741887081fSmrg 751887081fSmrgvoid 761887081fSmrgFcHashTableDestroy (FcHashTable *table) 771887081fSmrg{ 781887081fSmrg int i; 791887081fSmrg 801887081fSmrg for (i = 0; i < FC_HASH_SIZE; i++) 811887081fSmrg { 821887081fSmrg FcHashBucket *bucket = table->buckets[i], *prev; 831887081fSmrg 841887081fSmrg while (bucket) 851887081fSmrg { 861887081fSmrg if (table->key_destroy_func) 871887081fSmrg table->key_destroy_func (bucket->key); 881887081fSmrg if (table->value_destroy_func) 891887081fSmrg table->value_destroy_func (bucket->value); 901887081fSmrg prev = bucket; 911887081fSmrg bucket = bucket->next; 921887081fSmrg free (prev); 931887081fSmrg } 941887081fSmrg table->buckets[i] = NULL; 951887081fSmrg } 961887081fSmrg free (table); 971887081fSmrg} 981887081fSmrg 991887081fSmrgFcBool 1001887081fSmrgFcHashTableFind (FcHashTable *table, 1011887081fSmrg const void *key, 1021887081fSmrg void **value) 1031887081fSmrg{ 1041887081fSmrg FcHashBucket *bucket; 1051887081fSmrg FcChar32 hash = table->hash_func (key); 1061887081fSmrg 1071887081fSmrg for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next) 1081887081fSmrg { 1091887081fSmrg if (!table->compare_func(bucket->key, key)) 1101887081fSmrg { 1111887081fSmrg if (table->value_copy_func) 1121887081fSmrg { 1131887081fSmrg if (!table->value_copy_func (bucket->value, value)) 1141887081fSmrg return FcFalse; 1151887081fSmrg } 1161887081fSmrg else 1171887081fSmrg *value = bucket->value; 1181887081fSmrg return FcTrue; 1191887081fSmrg } 1201887081fSmrg } 1211887081fSmrg return FcFalse; 1221887081fSmrg} 1231887081fSmrg 1241887081fSmrgstatic FcBool 1251887081fSmrgFcHashTableAddInternal (FcHashTable *table, 1261887081fSmrg void *key, 1271887081fSmrg void *value, 1281887081fSmrg FcBool replace) 1291887081fSmrg{ 1301887081fSmrg FcHashBucket **prev, *bucket, *b; 1311887081fSmrg FcChar32 hash = table->hash_func (key); 1321887081fSmrg FcBool ret = FcFalse; 1331887081fSmrg 1341887081fSmrg bucket = (FcHashBucket *) malloc (sizeof (FcHashBucket)); 1351887081fSmrg if (!bucket) 1361887081fSmrg return FcFalse; 1371887081fSmrg memset (bucket, 0, sizeof (FcHashBucket)); 1381887081fSmrg if (table->key_copy_func) 1391887081fSmrg ret |= !table->key_copy_func (key, &bucket->key); 1401887081fSmrg else 1411887081fSmrg bucket->key = key; 1421887081fSmrg if (table->value_copy_func) 1431887081fSmrg ret |= !table->value_copy_func (value, &bucket->value); 1441887081fSmrg else 1451887081fSmrg bucket->value = value; 1461887081fSmrg if (ret) 1471887081fSmrg { 1481887081fSmrg destroy: 1491887081fSmrg if (bucket->key && table->key_destroy_func) 1501887081fSmrg table->key_destroy_func (bucket->key); 1511887081fSmrg if (bucket->value && table->value_destroy_func) 1521887081fSmrg table->value_destroy_func (bucket->value); 1531887081fSmrg free (bucket); 1541887081fSmrg 1551887081fSmrg return !ret; 1561887081fSmrg } 1571887081fSmrg retry: 1581887081fSmrg for (prev = &table->buckets[hash % FC_HASH_SIZE]; 1591887081fSmrg (b = fc_atomic_ptr_get (prev)); prev = &(b->next)) 1601887081fSmrg { 1611887081fSmrg if (!table->compare_func (b->key, key)) 1621887081fSmrg { 1631887081fSmrg if (replace) 1641887081fSmrg { 1651887081fSmrg bucket->next = b->next; 1661887081fSmrg if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) 1671887081fSmrg goto retry; 1681887081fSmrg bucket = b; 1691887081fSmrg } 1701887081fSmrg else 1711887081fSmrg ret = FcTrue; 1721887081fSmrg goto destroy; 1731887081fSmrg } 1741887081fSmrg } 1751887081fSmrg bucket->next = NULL; 1761887081fSmrg if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) 1771887081fSmrg goto retry; 1781887081fSmrg 1791887081fSmrg return FcTrue; 1801887081fSmrg} 1811887081fSmrg 1821887081fSmrgFcBool 1831887081fSmrgFcHashTableAdd (FcHashTable *table, 1841887081fSmrg void *key, 1851887081fSmrg void *value) 1861887081fSmrg{ 1871887081fSmrg return FcHashTableAddInternal (table, key, value, FcFalse); 1881887081fSmrg} 1891887081fSmrg 1901887081fSmrgFcBool 1911887081fSmrgFcHashTableReplace (FcHashTable *table, 1921887081fSmrg void *key, 1931887081fSmrg void *value) 1941887081fSmrg{ 1951887081fSmrg return FcHashTableAddInternal (table, key, value, FcTrue); 1961887081fSmrg} 1971887081fSmrg 1981887081fSmrgFcBool 1991887081fSmrgFcHashTableRemove (FcHashTable *table, 2001887081fSmrg void *key) 2011887081fSmrg{ 2021887081fSmrg FcHashBucket **prev, *bucket; 2031887081fSmrg FcChar32 hash = table->hash_func (key); 2041887081fSmrg FcBool ret = FcFalse; 2051887081fSmrg 2061887081fSmrgretry: 2071887081fSmrg for (prev = &table->buckets[hash % FC_HASH_SIZE]; 2081887081fSmrg (bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next)) 2091887081fSmrg { 2101887081fSmrg if (!table->compare_func (bucket->key, key)) 2111887081fSmrg { 2121887081fSmrg if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next)) 2131887081fSmrg goto retry; 2141887081fSmrg if (table->key_destroy_func) 2151887081fSmrg table->key_destroy_func (bucket->key); 2161887081fSmrg if (table->value_destroy_func) 2171887081fSmrg table->value_destroy_func (bucket->value); 2181887081fSmrg free (bucket); 2191887081fSmrg ret = FcTrue; 2201887081fSmrg break; 2211887081fSmrg } 2221887081fSmrg } 2231887081fSmrg 2241887081fSmrg return ret; 2251887081fSmrg} 226