Blame src/fchash.c

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
}