abstract hash table functions

This commit is contained in:
Akira TAGOH 2017-11-15 16:10:49 +09:00
parent 68ff99c414
commit 8f88b1c47c
8 changed files with 283 additions and 225 deletions

View File

@ -140,6 +140,7 @@ libfontconfig_la_SOURCES = \
fcfreetype.c \
fcfs.c \
fcptrlist.c \
fchash.c \
fcinit.c \
fclang.c \
fclist.c \

View File

@ -44,92 +44,10 @@
#define O_BINARY 0
#endif
#define FC_UUID_HASH_SIZE 4099
typedef struct _FcUuidBucket {
struct _FcUuidBucket *next;
FcChar8 *file;
uuid_t uuid;
} FcUuidBucket;
typedef struct _FcUuidHashTable {
FcUuidBucket *buckets[FC_UUID_HASH_SIZE];
} FcUuidHashTable;
static FcUuidHashTable uuid_table;
static FcBool
FcCacheUuidAdd (FcUuidHashTable *table,
const FcChar8 *file,
uuid_t uuid)
{
FcUuidBucket **prev, *bucket;
FcChar32 hash = FcStrHashIgnoreCase (file);
for (prev = &table->buckets[hash % FC_UUID_HASH_SIZE];
(bucket = *prev); prev = &(bucket->next))
{
if (FcStrCmp (bucket->file, file) == 0)
return FcTrue;
}
bucket = (FcUuidBucket *) malloc (sizeof (FcUuidBucket));
if (!bucket)
return FcFalse;
bucket->next = NULL;
bucket->file = FcStrdup (file);
uuid_copy (bucket->uuid, uuid);
if (!bucket->file)
{
free (bucket);
return FcFalse;
}
*prev = bucket;
return FcTrue;
}
static void
FcCacheUuidDestroy (FcUuidHashTable *table)
{
int i;
for (i = 0; i < FC_UUID_HASH_SIZE; i++)
{
FcUuidBucket *bucket = table->buckets[i], *prev;
while (bucket)
{
FcStrFree (bucket->file);
prev = bucket;
bucket = bucket->next;
free (prev);
}
table->buckets[i] = NULL;
}
}
static FcBool
FcCacheUuidFind (FcUuidHashTable *table,
const FcChar8 *file,
uuid_t ret)
{
FcUuidBucket *bucket;
FcChar32 hash = FcStrHashIgnoreCase (file);
for (bucket = table->buckets[hash % FC_UUID_HASH_SIZE]; bucket; bucket = bucket->next)
{
if (FcStrCmp (bucket->file, file) == 0)
{
uuid_copy (ret, bucket->uuid);
return FcTrue;
}
}
return FcFalse;
}
FcBool
FcDirCacheCreateUUID (const FcChar8 *dir,
FcBool force)
FcDirCacheCreateUUID (FcChar8 *dir,
FcBool force,
FcConfig *config)
{
FcBool ret = FcTrue;
FcChar8 *uuidname;
@ -163,7 +81,11 @@ FcDirCacheCreateUUID (const FcChar8 *dir,
goto bail3;
}
uuid_generate_random (uuid);
FcCacheUuidAdd (&uuid_table, dir, uuid);
if (!FcHashTableAdd (config->uuid_table, dir, uuid))
{
ret = FcFalse;
goto bail3;
}
uuid_unparse (uuid, out);
if (FcDebug () & FC_DBG_CACHE)
printf ("FcDirCacheCreateUUID %s: %s\n", uuidname, out);
@ -182,11 +104,13 @@ FcDirCacheCreateUUID (const FcChar8 *dir,
}
static void
FcDirCacheReadUUID (const FcChar8 *dir)
FcDirCacheReadUUID (FcChar8 *dir,
FcConfig *config)
{
void *u;
uuid_t uuid;
if (!FcCacheUuidFind (&uuid_table, dir, uuid))
if (!FcHashTableFind (config->uuid_table, dir, &u))
{
FcChar8 *uuidname = FcStrBuildFilename (dir, ".uuid", NULL);
int fd;
@ -203,7 +127,7 @@ FcDirCacheReadUUID (const FcChar8 *dir)
{
if (FcDebug () & FC_DBG_CACHE)
printf ("FcDirCacheReadUUID %s -> %s\n", uuidname, suuid);
FcCacheUuidAdd (&uuid_table, dir, uuid);
FcHashTableAdd (config->uuid_table, dir, uuid);
}
}
close (fd);
@ -215,111 +139,8 @@ FcDirCacheReadUUID (const FcChar8 *dir)
}
FcStrFree (uuidname);
}
}
#define FC_ALIAS_HASH_SIZE 4099
typedef struct _FcAliasBucket {
struct _FcAliasBucket *next;
FcChar8 *orig;
FcChar8 *alias;
} FcAliasBucket;
typedef struct _FcAliasHashTable {
FcAliasBucket *buckets[FC_ALIAS_HASH_SIZE];
} FcAliasHashTable;
static FcAliasHashTable alias_table;
static FcBool
FcCacheAliasAdd (FcAliasHashTable *table,
const FcChar8 *orig,
const FcChar8 *alias)
{
FcAliasBucket **prev, *bucket;
FcChar32 hash = FcStrHashIgnoreCase (orig);
for (prev = &table->buckets[hash % FC_ALIAS_HASH_SIZE];
(bucket = *prev); prev = &(bucket->next))
{
if (FcStrCmp (bucket->orig, orig) == 0)
return FcTrue;
}
bucket = (FcAliasBucket *) malloc (sizeof (FcAliasBucket));
if (!bucket)
return FcFalse;
bucket->next = NULL;
bucket->orig = FcStrdup (orig);
bucket->alias = FcStrdup (alias);
if (!bucket->orig || !bucket->alias)
{
if (bucket->orig)
FcStrFree (bucket->orig);
if (bucket->alias)
FcStrFree (bucket->alias);
free (bucket);
return FcFalse;
}
*prev = bucket;
return FcTrue;
}
static void
FcCacheAliasDestroy (FcAliasHashTable *table)
{
int i;
for (i = 0; i < FC_ALIAS_HASH_SIZE; i++)
{
FcAliasBucket *bucket = table->buckets[i], *prev;
while (bucket)
{
prev = bucket;
FcStrFree (bucket->orig);
FcStrFree (bucket->alias);
bucket = bucket->next;
free (prev);
}
table->buckets[i] = NULL;
}
}
static FcBool
FcCacheAliasFind (FcAliasHashTable *table,
const FcChar8 *orig,
const FcChar8 **ret)
{
FcAliasBucket *bucket;
FcChar32 hash = FcStrHashIgnoreCase (orig);
for (bucket = table->buckets[hash % FC_ALIAS_HASH_SIZE]; bucket; bucket = bucket->next)
{
if (FcStrCmp (bucket->orig, orig) == 0)
{
*ret = bucket->alias;
return FcTrue;
}
}
return FcFalse;
}
static void
FcDirCacheAddAliasPath (const FcChar8 *orig,
const FcChar8 *alias)
{
FcCacheAliasAdd (&alias_table, orig, alias);
}
const FcChar8 *
FcDirCacheFindAliasPath (const FcChar8 *dir)
{
const FcChar8 *ret = NULL;
if (FcCacheAliasFind (&alias_table, dir, &ret))
return ret;
return NULL;
else
FcHashUuidFree (u);
}
struct MD5Context {
@ -398,20 +219,21 @@ FcDirCacheBasenameMD5 (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN])
}
static FcChar8 *
FcDirCacheBasenameUUID (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN])
FcDirCacheBasenameUUID (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN], FcConfig *config)
{
uuid_t uuid;
const FcChar8 *alias;
FcChar8 *alias;
alias = FcDirCacheFindAliasPath (dir);
if (!alias)
alias = dir;
if (FcCacheUuidFind (&uuid_table, alias, uuid))
if (!FcHashTableFind (config->alias_table, dir, (void **)&alias))
alias = FcStrdup (dir);
if (FcHashTableFind (config->uuid_table, alias, (void **)&uuid))
{
uuid_unparse (uuid, (char *) cache_base);
strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
FcStrFree (alias);
return cache_base;
}
FcStrFree (alias);
return NULL;
}
@ -424,7 +246,7 @@ FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
FcChar8 *cache_dir;
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
if (!FcDirCacheBasenameUUID (dir, cache_base))
if (!FcDirCacheBasenameUUID (dir, cache_base, config))
FcDirCacheBasenameMD5 (dir, cache_base);
list = FcStrListCreate (config->cacheDirs);
@ -501,7 +323,7 @@ FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
}
FcStrFree (d);
if (!FcDirCacheBasenameUUID (dir, cache_base))
if (!FcDirCacheBasenameUUID (dir, cache_base, config))
FcDirCacheBasenameMD5 (dir, cache_base);
list = FcStrListCreate (config->cacheDirs);
@ -832,14 +654,7 @@ FcCacheObjectDereference (void *object)
if (skip)
{
if (FcRefDec (&skip->ref) == 1)
{
FcDirCacheDisposeUnlocked (skip->cache);
if (fcCacheMaxLevel == 0)
{
FcCacheUuidDestroy (&uuid_table);
FcCacheAliasDestroy (&alias_table);
}
}
}
unlock_cache ();
}
@ -1099,7 +914,7 @@ FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
FcCache *cache = NULL;
const FcChar8 *d;
FcDirCacheReadUUID (dir);
FcDirCacheReadUUID ((FcChar8 *) dir, config);
if (!FcDirCacheProcess (config, dir,
FcDirCacheMapHelper,
&cache, cache_file))
@ -1107,7 +922,7 @@ FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
d = FcCacheDir (cache);
if (FcStrCmp (dir, d))
FcDirCacheAddAliasPath (d, dir);
FcHashTableAdd (config->alias_table, (FcChar8 *) d, (FcChar8 *) dir);
return cache;
}
@ -1360,7 +1175,7 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config)
if (!cache_dir)
return FcFalse;
if (!FcDirCacheBasenameUUID (dir, cache_base))
if (!FcDirCacheBasenameUUID (dir, cache_base, config))
FcDirCacheBasenameMD5 (dir, cache_base);
cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
if (!cache_hashed)
@ -1558,7 +1373,7 @@ FcDirCacheLock (const FcChar8 *dir,
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
int fd = -1;
if (!FcDirCacheBasenameUUID (dir, cache_base))
if (!FcDirCacheBasenameUUID (dir, cache_base, config))
FcDirCacheBasenameMD5 (dir, cache_base);
list = FcStrListCreate (config->cacheDirs);
if (!list)

View File

@ -151,6 +151,19 @@ FcConfigCreate (void)
if (!config->availConfigFiles)
goto bail10;
config->uuid_table = FcHashTableCreate ((FcHashFunc) FcStrHashIgnoreCase,
(FcCompareFunc) FcStrCmp,
FcHashStrCopy,
FcHashUuidCopy,
(FcDestroyFunc) FcStrFree,
FcHashUuidFree);
config->alias_table = FcHashTableCreate ((FcHashFunc) FcStrHashIgnoreCase,
(FcCompareFunc) FcStrCmp,
FcHashStrCopy,
FcHashStrCopy,
(FcDestroyFunc) FcStrFree,
(FcDestroyFunc) FcStrFree);
FcRefInit (&config->ref, 1);
return config;
@ -312,6 +325,9 @@ FcConfigDestroy (FcConfig *config)
if (config->sysRoot)
FcStrFree (config->sysRoot);
FcHashTableDestroy (config->uuid_table);
FcHashTableDestroy (config->alias_table);
free (config);
}
@ -371,14 +387,15 @@ FcConfigAddCache (FcConfig *config, FcCache *cache,
for (i = 0; i < cache->dirs_count; i++)
{
const FcChar8 *dir = FcCacheSubdir (cache, i);
const FcChar8 *alias;
FcChar8 *alias;
FcChar8 *d = FcStrDirname (dir);
FcChar8 *s = NULL;
if ((alias = FcDirCacheFindAliasPath (d)))
if (FcHashTableFind (config->alias_table, d, (void **)&alias))
{
FcChar8 *base = FcStrBasename (dir);
dir = s = FcStrBuildFilename (alias, base, NULL);
FcStrFree (alias);
FcStrFree (base);
}
FcStrFree (d);

View File

@ -409,7 +409,7 @@ FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
{
FcCache *cache = NULL;
FcDirCacheCreateUUID (dir, force);
FcDirCacheCreateUUID ((FcChar8 *) dir, force, config);
/* Try to use existing cache file */
if (!force)
cache = FcDirCacheLoad (dir, config, NULL);

181
src/fchash.c Normal file
View File

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

View File

@ -392,6 +392,13 @@ typedef struct _FcStrBuf {
FcChar8 buf_static[16 * sizeof (void *)];
} FcStrBuf;
typedef struct _FcHashTable FcHashTable;
typedef FcChar32 (* FcHashFunc) (const void *data);
typedef int (* FcCompareFunc) (const void *v1, const void *v2);
typedef FcBool (* FcCopyFunc) (const void *src, void **dest);
struct _FcCache {
unsigned int magic; /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */
int version; /* FC_CACHE_VERSION_NUMBER */
@ -558,6 +565,8 @@ struct _FcConfig {
FcChar8 *sysRoot; /* override the system root directory */
FcStrSet *availConfigFiles; /* config files available */
FcPtrList *rulesetList; /* List of rulesets being installed */
FcHashTable *uuid_table; /* UUID table for cachedirs */
FcHashTable *alias_table; /* alias table for cachedirs */
};
typedef struct _FcFileTime {
@ -588,11 +597,9 @@ struct _FcValuePromotionBuffer {
/* fccache.c */
FcPrivate FcBool
FcDirCacheCreateUUID (const FcChar8 *dir,
FcBool force);
FcPrivate const FcChar8 *
FcDirCacheFindAliasPath (const FcChar8 *dir);
FcDirCacheCreateUUID (FcChar8 *dir,
FcBool force,
FcConfig *config);
FcPrivate FcCache *
FcDirCacheScan (const FcChar8 *dir, FcConfig *config);
@ -1300,4 +1307,38 @@ FcObjectLookupOtherTypeById (FcObject id);
FcPrivate const FcObjectType *
FcObjectLookupOtherTypeByName (const char *str);
/* fchash.c */
FcPrivate FcBool
FcHashStrCopy (const void *src,
void **dest);
FcPrivate FcBool
FcHashUuidCopy (const void *src,
void **dest);
FcPrivate void
FcHashUuidFree (void *data);
FcPrivate FcHashTable *
FcHashTableCreate (FcHashFunc hash_func,
FcCompareFunc compare_func,
FcCopyFunc key_copy_func,
FcCopyFunc value_copy_func,
FcDestroyFunc key_destroy_func,
FcDestroyFunc value_destroy_func);
FcPrivate void
FcHashTableDestroy (FcHashTable *table);
FcPrivate FcBool
FcHashTableFind (FcHashTable *table,
const void *key,
void **value);
FcPrivate FcBool
FcHashTableAdd (FcHashTable *table,
void *key,
void *value);
#endif /* _FC_INT_H_ */

View File

@ -458,14 +458,16 @@ FcListAppend (FcListHashTable *table,
if (FcStat (FcValueString (&v->value), &statb) < 0)
{
FcChar8 *dir = FcStrDirname (FcValueString (&v->value));
const FcChar8 *alias;
FcChar8 *alias;
FcConfig *config = FcConfigGetCurrent (); /* FIXME: this may need to be exported as API? */
if ((alias = FcDirCacheFindAliasPath (dir)))
if (FcHashTableFind (config->alias_table, dir, (void **) &alias))
{
FcChar8 *base = FcStrBasename (FcValueString (&v->value));
FcChar8 *s = FcStrBuildFilename (alias, base, NULL);
FcValue vv;
FcStrFree (alias);
FcStrFree (base);
vv.type = FcTypeString;
vv.u.s = s;

View File

@ -653,14 +653,15 @@ FcFontRenderPrepare (FcConfig *config,
if (FcStat (FcValueString (&l->value), &statb) < 0)
{
FcChar8 *dir = FcStrDirname (FcValueString (&l->value));
const FcChar8 *alias;
FcChar8 *alias;
if ((alias = FcDirCacheFindAliasPath (dir)))
if (FcHashTableFind (config->alias_table, dir, (void **) &alias))
{
FcChar8 *base = FcStrBasename (FcValueString (&l->value));
FcChar8 *s = FcStrBuildFilename (alias, base, NULL);
FcValue v;
FcStrFree (alias);
FcStrFree (base);
v.type = FcTypeString;
v.u.s = s;