fchash.c revision 1887081f
1/* 2 * Copyright © 2000 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of the author(s) not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. The authors make no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22#include "fcint.h" 23#if !defined TOOL_FCCACHE 24#ifndef _WIN32 25#include <uuid/uuid.h> 26#endif 27#endif 28 29#define FC_HASH_SIZE 227 30 31typedef struct _FcHashBucket { 32 struct _FcHashBucket *next; 33 void *key; 34 void *value; 35} FcHashBucket; 36 37struct _FcHashTable { 38 FcHashBucket *buckets[FC_HASH_SIZE]; 39 FcHashFunc hash_func; 40 FcCompareFunc compare_func; 41 FcCopyFunc key_copy_func; 42 FcCopyFunc value_copy_func; 43 FcDestroyFunc key_destroy_func; 44 FcDestroyFunc value_destroy_func; 45}; 46 47 48FcBool 49FcHashStrCopy (const void *src, 50 void **dest) 51{ 52 *dest = FcStrdup (src); 53 54 return *dest != NULL; 55} 56 57FcBool 58FcHashUuidCopy (const void *src, 59 void **dest) 60{ 61#if !defined TOOL_FCCACHE 62#ifndef _WIN32 63 *dest = malloc (sizeof (uuid_t)); 64 uuid_copy (*dest, src); 65#endif 66#endif 67 return FcTrue; 68} 69 70void 71FcHashUuidFree (void *data) 72{ 73 free (data); 74} 75 76FcHashTable * 77FcHashTableCreate (FcHashFunc hash_func, 78 FcCompareFunc compare_func, 79 FcCopyFunc key_copy_func, 80 FcCopyFunc value_copy_func, 81 FcDestroyFunc key_destroy_func, 82 FcDestroyFunc value_destroy_func) 83{ 84 FcHashTable *ret = malloc (sizeof (FcHashTable)); 85 86 if (ret) 87 { 88 memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE); 89 ret->hash_func = hash_func; 90 ret->compare_func = compare_func; 91 ret->key_copy_func = key_copy_func; 92 ret->value_copy_func = value_copy_func; 93 ret->key_destroy_func = key_destroy_func; 94 ret->value_destroy_func = value_destroy_func; 95 } 96 return ret; 97} 98 99void 100FcHashTableDestroy (FcHashTable *table) 101{ 102 int i; 103 104 for (i = 0; i < FC_HASH_SIZE; i++) 105 { 106 FcHashBucket *bucket = table->buckets[i], *prev; 107 108 while (bucket) 109 { 110 if (table->key_destroy_func) 111 table->key_destroy_func (bucket->key); 112 if (table->value_destroy_func) 113 table->value_destroy_func (bucket->value); 114 prev = bucket; 115 bucket = bucket->next; 116 free (prev); 117 } 118 table->buckets[i] = NULL; 119 } 120 free (table); 121} 122 123FcBool 124FcHashTableFind (FcHashTable *table, 125 const void *key, 126 void **value) 127{ 128 FcHashBucket *bucket; 129 FcChar32 hash = table->hash_func (key); 130 131 for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next) 132 { 133 if (!table->compare_func(bucket->key, key)) 134 { 135 if (table->value_copy_func) 136 { 137 if (!table->value_copy_func (bucket->value, value)) 138 return FcFalse; 139 } 140 else 141 *value = bucket->value; 142 return FcTrue; 143 } 144 } 145 return FcFalse; 146} 147 148static FcBool 149FcHashTableAddInternal (FcHashTable *table, 150 void *key, 151 void *value, 152 FcBool replace) 153{ 154 FcHashBucket **prev, *bucket, *b; 155 FcChar32 hash = table->hash_func (key); 156 FcBool ret = FcFalse; 157 158 bucket = (FcHashBucket *) malloc (sizeof (FcHashBucket)); 159 if (!bucket) 160 return FcFalse; 161 memset (bucket, 0, sizeof (FcHashBucket)); 162 if (table->key_copy_func) 163 ret |= !table->key_copy_func (key, &bucket->key); 164 else 165 bucket->key = key; 166 if (table->value_copy_func) 167 ret |= !table->value_copy_func (value, &bucket->value); 168 else 169 bucket->value = value; 170 if (ret) 171 { 172 destroy: 173 if (bucket->key && table->key_destroy_func) 174 table->key_destroy_func (bucket->key); 175 if (bucket->value && table->value_destroy_func) 176 table->value_destroy_func (bucket->value); 177 free (bucket); 178 179 return !ret; 180 } 181 retry: 182 for (prev = &table->buckets[hash % FC_HASH_SIZE]; 183 (b = fc_atomic_ptr_get (prev)); prev = &(b->next)) 184 { 185 if (!table->compare_func (b->key, key)) 186 { 187 if (replace) 188 { 189 bucket->next = b->next; 190 if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) 191 goto retry; 192 bucket = b; 193 } 194 else 195 ret = FcTrue; 196 goto destroy; 197 } 198 } 199 bucket->next = NULL; 200 if (!fc_atomic_ptr_cmpexch (prev, b, bucket)) 201 goto retry; 202 203 return FcTrue; 204} 205 206FcBool 207FcHashTableAdd (FcHashTable *table, 208 void *key, 209 void *value) 210{ 211 return FcHashTableAddInternal (table, key, value, FcFalse); 212} 213 214FcBool 215FcHashTableReplace (FcHashTable *table, 216 void *key, 217 void *value) 218{ 219 return FcHashTableAddInternal (table, key, value, FcTrue); 220} 221 222FcBool 223FcHashTableRemove (FcHashTable *table, 224 void *key) 225{ 226 FcHashBucket **prev, *bucket; 227 FcChar32 hash = table->hash_func (key); 228 FcBool ret = FcFalse; 229 230retry: 231 for (prev = &table->buckets[hash % FC_HASH_SIZE]; 232 (bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next)) 233 { 234 if (!table->compare_func (bucket->key, key)) 235 { 236 if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next)) 237 goto retry; 238 if (table->key_destroy_func) 239 table->key_destroy_func (bucket->key); 240 if (table->value_destroy_func) 241 table->value_destroy_func (bucket->value); 242 free (bucket); 243 ret = FcTrue; 244 break; 245 } 246 } 247 248 return ret; 249} 250