|
Packit |
352660 |
/*
|
|
Packit |
352660 |
* Copyright © 2000 Keith Packard
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
Packit |
352660 |
* documentation for any purpose is hereby granted without fee, provided that
|
|
Packit |
352660 |
* the above copyright notice appear in all copies and that both that
|
|
Packit |
352660 |
* copyright notice and this permission notice appear in supporting
|
|
Packit |
352660 |
* documentation, and that the name of the author(s) not be used in
|
|
Packit |
352660 |
* advertising or publicity pertaining to distribution of the software without
|
|
Packit |
352660 |
* specific, written prior permission. The authors make no
|
|
Packit |
352660 |
* representations about the suitability of this software for any purpose. It
|
|
Packit |
352660 |
* is provided "as is" without express or implied warranty.
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
Packit |
352660 |
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
Packit |
352660 |
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
Packit |
352660 |
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
Packit |
352660 |
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
Packit |
352660 |
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
Packit |
352660 |
* PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
352660 |
*/
|
|
Packit |
352660 |
#include "fcint.h"
|
|
Packit |
352660 |
#ifndef _WIN32
|
|
Packit |
352660 |
#include <uuid/uuid.h>
|
|
Packit |
352660 |
#endif
|
|
Packit |
352660 |
|
|
Packit |
352660 |
#define FC_HASH_SIZE 227
|
|
Packit |
352660 |
|
|
Packit |
352660 |
typedef struct _FcHashBucket {
|
|
Packit |
352660 |
struct _FcHashBucket *next;
|
|
Packit |
352660 |
void *key;
|
|
Packit |
352660 |
void *value;
|
|
Packit |
352660 |
} FcHashBucket;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
struct _FcHashTable {
|
|
Packit |
352660 |
FcHashBucket *buckets[FC_HASH_SIZE];
|
|
Packit |
352660 |
FcHashFunc hash_func;
|
|
Packit |
352660 |
FcCompareFunc compare_func;
|
|
Packit |
352660 |
FcCopyFunc key_copy_func;
|
|
Packit |
352660 |
FcCopyFunc value_copy_func;
|
|
Packit |
352660 |
FcDestroyFunc key_destroy_func;
|
|
Packit |
352660 |
FcDestroyFunc value_destroy_func;
|
|
Packit |
352660 |
};
|
|
Packit |
352660 |
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcBool
|
|
Packit |
352660 |
FcHashStrCopy (const void *src,
|
|
Packit |
352660 |
void **dest)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
*dest = FcStrdup (src);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return *dest != NULL;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcBool
|
|
Packit |
352660 |
FcHashUuidCopy (const void *src,
|
|
Packit |
352660 |
void **dest)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
#ifndef _WIN32
|
|
Packit |
352660 |
*dest = malloc (sizeof (uuid_t));
|
|
Packit |
352660 |
uuid_copy (*dest, src);
|
|
Packit |
352660 |
#endif
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
void
|
|
Packit |
352660 |
FcHashUuidFree (void *data)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
free (data);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcHashTable *
|
|
Packit |
352660 |
FcHashTableCreate (FcHashFunc hash_func,
|
|
Packit |
352660 |
FcCompareFunc compare_func,
|
|
Packit |
352660 |
FcCopyFunc key_copy_func,
|
|
Packit |
352660 |
FcCopyFunc value_copy_func,
|
|
Packit |
352660 |
FcDestroyFunc key_destroy_func,
|
|
Packit |
352660 |
FcDestroyFunc value_destroy_func)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcHashTable *ret = malloc (sizeof (FcHashTable));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (ret)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE);
|
|
Packit |
352660 |
ret->hash_func = hash_func;
|
|
Packit |
352660 |
ret->compare_func = compare_func;
|
|
Packit |
352660 |
ret->key_copy_func = key_copy_func;
|
|
Packit |
352660 |
ret->value_copy_func = value_copy_func;
|
|
Packit |
352660 |
ret->key_destroy_func = key_destroy_func;
|
|
Packit |
352660 |
ret->value_destroy_func = value_destroy_func;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
return ret;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
void
|
|
Packit |
352660 |
FcHashTableDestroy (FcHashTable *table)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int i;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
for (i = 0; i < FC_HASH_SIZE; i++)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcHashBucket *bucket = table->buckets[i], *prev;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while (bucket)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (table->key_destroy_func)
|
|
Packit |
352660 |
table->key_destroy_func (bucket->key);
|
|
Packit |
352660 |
if (table->value_destroy_func)
|
|
Packit |
352660 |
table->value_destroy_func (bucket->value);
|
|
Packit |
352660 |
prev = bucket;
|
|
Packit |
352660 |
bucket = bucket->next;
|
|
Packit |
352660 |
free (prev);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
table->buckets[i] = NULL;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
free (table);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcBool
|
|
Packit |
352660 |
FcHashTableFind (FcHashTable *table,
|
|
Packit |
352660 |
const void *key,
|
|
Packit |
352660 |
void **value)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcHashBucket *bucket;
|
|
Packit |
352660 |
FcChar32 hash = table->hash_func (key);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!table->compare_func(bucket->key, key))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (table->value_copy_func)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!table->value_copy_func (bucket->value, value))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
*value = bucket->value;
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
FcHashTableAddInternal (FcHashTable *table,
|
|
Packit |
352660 |
void *key,
|
|
Packit |
352660 |
void *value,
|
|
Packit |
352660 |
FcBool replace)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcHashBucket **prev, *bucket, *b;
|
|
Packit |
352660 |
FcChar32 hash = table->hash_func (key);
|
|
Packit |
352660 |
FcBool ret = FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
bucket = (FcHashBucket *) malloc (sizeof (FcHashBucket));
|
|
Packit |
352660 |
if (!bucket)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
memset (bucket, 0, sizeof (FcHashBucket));
|
|
Packit |
352660 |
if (table->key_copy_func)
|
|
Packit |
352660 |
ret |= !table->key_copy_func (key, &bucket->key);
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
bucket->key = key;
|
|
Packit |
352660 |
if (table->value_copy_func)
|
|
Packit |
352660 |
ret |= !table->value_copy_func (value, &bucket->value);
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
bucket->value = value;
|
|
Packit |
352660 |
if (ret)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
destroy:
|
|
Packit |
352660 |
if (bucket->key && table->key_destroy_func)
|
|
Packit |
352660 |
table->key_destroy_func (bucket->key);
|
|
Packit |
352660 |
if (bucket->value && table->value_destroy_func)
|
|
Packit |
352660 |
table->value_destroy_func (bucket->value);
|
|
Packit |
352660 |
free (bucket);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return !ret;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
retry:
|
|
Packit |
352660 |
for (prev = &table->buckets[hash % FC_HASH_SIZE];
|
|
Packit |
352660 |
(b = fc_atomic_ptr_get (prev)); prev = &(b->next))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!table->compare_func (b->key, key))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (replace)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
bucket->next = b->next;
|
|
Packit |
352660 |
if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
|
|
Packit |
352660 |
goto retry;
|
|
Packit |
352660 |
bucket = b;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
ret = FcTrue;
|
|
Packit |
352660 |
goto destroy;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
bucket->next = NULL;
|
|
Packit |
352660 |
if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
|
|
Packit |
352660 |
goto retry;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcBool
|
|
Packit |
352660 |
FcHashTableAdd (FcHashTable *table,
|
|
Packit |
352660 |
void *key,
|
|
Packit |
352660 |
void *value)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
return FcHashTableAddInternal (table, key, value, FcFalse);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcBool
|
|
Packit |
352660 |
FcHashTableReplace (FcHashTable *table,
|
|
Packit |
352660 |
void *key,
|
|
Packit |
352660 |
void *value)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
return FcHashTableAddInternal (table, key, value, FcTrue);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcBool
|
|
Packit |
352660 |
FcHashTableRemove (FcHashTable *table,
|
|
Packit |
352660 |
void *key)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcHashBucket **prev, *bucket;
|
|
Packit |
352660 |
FcChar32 hash = table->hash_func (key);
|
|
Packit |
352660 |
FcBool ret = FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
retry:
|
|
Packit |
352660 |
for (prev = &table->buckets[hash % FC_HASH_SIZE];
|
|
Packit |
352660 |
(bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!table->compare_func (bucket->key, key))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next))
|
|
Packit |
352660 |
goto retry;
|
|
Packit |
352660 |
if (table->key_destroy_func)
|
|
Packit |
352660 |
table->key_destroy_func (bucket->key);
|
|
Packit |
352660 |
if (table->value_destroy_func)
|
|
Packit |
352660 |
table->value_destroy_func (bucket->value);
|
|
Packit |
352660 |
free (bucket);
|
|
Packit |
352660 |
ret = FcTrue;
|
|
Packit |
352660 |
break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return ret;
|
|
Packit |
352660 |
}
|