Reimplement glyph cache as a hash table
This commit is contained in:
159
src/utf8map.c
159
src/utf8map.c
@@ -35,7 +35,13 @@ struct glyphid_cache_t {
|
|||||||
char *id;
|
char *id;
|
||||||
};
|
};
|
||||||
static struct glyphid_cache_t *glyphid_cache;
|
static struct glyphid_cache_t *glyphid_cache;
|
||||||
|
static unsigned glyphid_cache_lsize;
|
||||||
|
static size_t glyphid_cache_size;
|
||||||
struct find_struct glyphcache_find, to_custom_symbol_find;
|
struct find_struct glyphcache_find, to_custom_symbol_find;
|
||||||
|
static void init_glyph_cache(void);
|
||||||
|
static void add_glyph_to_cache(int glyphnum, const char *id);
|
||||||
|
static int find_glyph_in_cache(const char *id);
|
||||||
|
static uint32 glyph_hash(const char *id);
|
||||||
static void to_custom_symset_entry_callback(int glyph,
|
static void to_custom_symset_entry_callback(int glyph,
|
||||||
struct find_struct *findwhat);
|
struct find_struct *findwhat);
|
||||||
static int unicode_val(const char *cp);
|
static int unicode_val(const char *cp);
|
||||||
@@ -44,8 +50,6 @@ static int glyph_find_core(const char *id, struct find_struct *findwhat);
|
|||||||
static char *fix_glyphname(char *str);
|
static char *fix_glyphname(char *str);
|
||||||
static int32_t rgbstr_to_int32(const char *rgbstr);
|
static int32_t rgbstr_to_int32(const char *rgbstr);
|
||||||
boolean closest_color(uint32_t lcolor, uint32_t *closecolor, int *clridx);
|
boolean closest_color(uint32_t lcolor, uint32_t *closecolor, int *clridx);
|
||||||
static int glyphid_sort_compare(const void *p1, const void *p2);
|
|
||||||
static int glyphid_search_compare(const void *p1, const void *p2);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
to_custom_symset_entry_callback(int glyph, struct find_struct *findwhat)
|
to_custom_symset_entry_callback(int glyph, struct find_struct *findwhat)
|
||||||
@@ -316,15 +320,10 @@ glyph_find_core(const char *id, struct find_struct *findwhat)
|
|||||||
|
|
||||||
void fill_glyphid_cache(void)
|
void fill_glyphid_cache(void)
|
||||||
{
|
{
|
||||||
int glyph, reslt = 0;
|
int reslt = 0;
|
||||||
|
|
||||||
if (!glyphid_cache) {
|
if (!glyphid_cache) {
|
||||||
glyphid_cache = (struct glyphid_cache_t *) alloc(
|
init_glyph_cache();
|
||||||
MAX_GLYPH * sizeof(struct glyphid_cache_t));
|
|
||||||
for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
|
|
||||||
glyphid_cache[glyph].glyphnum = 0;
|
|
||||||
glyphid_cache[glyph].id = (char *) 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (glyphid_cache) {
|
if (glyphid_cache) {
|
||||||
glyphcache_find = zero_find;
|
glyphcache_find = zero_find;
|
||||||
@@ -337,26 +336,37 @@ void fill_glyphid_cache(void)
|
|||||||
glyphid_cache = (struct glyphid_cache_t *) 0;
|
glyphid_cache = (struct glyphid_cache_t *) 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (glyphid_cache) {
|
|
||||||
for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
|
|
||||||
if (glyphid_cache[glyph].id != NULL) {
|
|
||||||
lcase(glyphid_cache[glyph].id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qsort(glyphid_cache, MAX_GLYPH, sizeof(glyphid_cache[0]),
|
|
||||||
glyphid_sort_compare);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/*
|
||||||
glyphid_sort_compare(const void *p1, const void *p2)
|
* The glyph ID cache is a simple double-hash table.
|
||||||
{
|
* The cache size is a power of two, and two hashes are derived from the
|
||||||
const struct glyphid_cache_t *elem1 = (const struct glyphid_cache_t *) p1;
|
* cache ID. The first is a location in the table, and the second is an
|
||||||
const struct glyphid_cache_t *elem2 = (const struct glyphid_cache_t *) p2;
|
* offset. On any collision, the second hash is added to the first until
|
||||||
const char *id1 = elem1->id ? elem1->id : "";
|
* a match or an empty bucket is found.
|
||||||
const char *id2 = elem2->id ? elem2->id : "";
|
* The second hash is an odd number, which is necessary and sufficient
|
||||||
|
* to traverse the entire table.
|
||||||
|
*/
|
||||||
|
|
||||||
return strcmp(id1, id2);
|
static void
|
||||||
|
init_glyph_cache(void)
|
||||||
|
{
|
||||||
|
size_t glyph;
|
||||||
|
|
||||||
|
/* Cache size of power of 2 not less than 2*MAX_GLYPH */
|
||||||
|
glyphid_cache_lsize = 0;
|
||||||
|
glyphid_cache_size = 1;
|
||||||
|
while (glyphid_cache_size < 2*MAX_GLYPH) {
|
||||||
|
++glyphid_cache_lsize;
|
||||||
|
glyphid_cache_size <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
glyphid_cache = (struct glyphid_cache_t *) alloc(
|
||||||
|
glyphid_cache_size * sizeof(struct glyphid_cache_t));
|
||||||
|
for (glyph = 0; glyph < glyphid_cache_size; ++glyph) {
|
||||||
|
glyphid_cache[glyph].glyphnum = 0;
|
||||||
|
glyphid_cache[glyph].id = (char *) 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_glyphid_cache(void)
|
void free_glyphid_cache(void)
|
||||||
@@ -375,6 +385,73 @@ void free_glyphid_cache(void)
|
|||||||
glyphid_cache = (struct glyphid_cache_t *) 0;
|
glyphid_cache = (struct glyphid_cache_t *) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_glyph_to_cache(int glyphnum, const char *id)
|
||||||
|
{
|
||||||
|
uint32 hash = glyph_hash(id);
|
||||||
|
size_t hash1 = (size_t) (hash & (glyphid_cache_size - 1));
|
||||||
|
size_t hash2 = (size_t)
|
||||||
|
(((hash >> glyphid_cache_lsize) & (glyphid_cache_size - 1)) | 1);
|
||||||
|
size_t i = hash1;
|
||||||
|
unsigned count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
++count;
|
||||||
|
if (glyphid_cache[i].id == NULL) {
|
||||||
|
/* Empty bucket found */
|
||||||
|
glyphid_cache[i].id = dupstr(id);
|
||||||
|
glyphid_cache[i].glyphnum = glyphnum;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* For speed, assume that no ID occurs twice */
|
||||||
|
i = (i + hash2) & (glyphid_cache_size - 1);
|
||||||
|
} while (i != hash1);
|
||||||
|
/* This should never happen */
|
||||||
|
panic("glyphid_cache full");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_glyph_in_cache(const char *id)
|
||||||
|
{
|
||||||
|
uint32 hash = glyph_hash(id);
|
||||||
|
size_t hash1 = (size_t) (hash & (glyphid_cache_size - 1));
|
||||||
|
size_t hash2 = (size_t)
|
||||||
|
(((hash >> glyphid_cache_lsize) & (glyphid_cache_size - 1)) | 1);
|
||||||
|
size_t i = hash1;
|
||||||
|
unsigned count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
++count;
|
||||||
|
if (glyphid_cache[i].id == NULL) {
|
||||||
|
/* Empty bucket found */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (strcmpi(id, glyphid_cache[i].id) == 0) {
|
||||||
|
/* Match found */
|
||||||
|
return glyphid_cache[i].glyphnum;
|
||||||
|
}
|
||||||
|
i = (i + hash2) & (glyphid_cache_size - 1);
|
||||||
|
} while (i != hash1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
glyph_hash(const char *id)
|
||||||
|
{
|
||||||
|
uint32 hash = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; id[i] != '\0'; ++i) {
|
||||||
|
char ch = id[i];
|
||||||
|
if ('A' <= ch && ch <= 'Z') {
|
||||||
|
ch += 'a' - 'A';
|
||||||
|
}
|
||||||
|
hash = (hash << 1) | (hash >> 31);
|
||||||
|
hash ^= ch;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
boolean
|
boolean
|
||||||
glyphid_cache_status(void)
|
glyphid_cache_status(void)
|
||||||
{
|
{
|
||||||
@@ -613,19 +690,10 @@ parse_id(const char *id, struct find_struct *findwhat)
|
|||||||
}
|
}
|
||||||
if (is_G || filling_cache || dump_ids) {
|
if (is_G || filling_cache || dump_ids) {
|
||||||
if (!filling_cache && id && glyphid_cache) {
|
if (!filling_cache && id && glyphid_cache) {
|
||||||
char *id_l;
|
int val = find_glyph_in_cache(id);
|
||||||
const struct glyphid_cache_t *gptr;
|
if (val >= 0) {
|
||||||
|
|
||||||
id_l = dupstr(id);
|
|
||||||
lcase(id_l);
|
|
||||||
gptr = (const struct glyphid_cache_t *)
|
|
||||||
bsearch(id_l, glyphid_cache, MAX_GLYPH,
|
|
||||||
sizeof(glyphid_cache[0]),
|
|
||||||
glyphid_search_compare);
|
|
||||||
free(id_l);
|
|
||||||
if (gptr != NULL) {
|
|
||||||
findwhat->findtype = find_glyph;
|
findwhat->findtype = find_glyph;
|
||||||
findwhat->val = gptr->glyphnum;
|
findwhat->val = val;
|
||||||
findwhat->loadsyms_offset = 0;
|
findwhat->loadsyms_offset = 0;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -854,14 +922,13 @@ parse_id(const char *id, struct find_struct *findwhat)
|
|||||||
Snprintf(buf[0], sizeof buf[0], "G_%s%d", "warning", j);
|
Snprintf(buf[0], sizeof buf[0], "G_%s%d", "warning", j);
|
||||||
}
|
}
|
||||||
if (memchr(buf[0], '\0', sizeof buf[0]) == NULL)
|
if (memchr(buf[0], '\0', sizeof buf[0]) == NULL)
|
||||||
panic("parse_id: buf[0] overflowed\n");
|
panic("parse_id: buf[0] overflowed");
|
||||||
if (!skip_this_one) {
|
if (!skip_this_one) {
|
||||||
fix_glyphname(buf[0]+2);
|
fix_glyphname(buf[0]+2);
|
||||||
if (dump_ids) {
|
if (dump_ids) {
|
||||||
Fprintf(fp, "(%04d) %s\n", glyph, buf[0]);
|
Fprintf(fp, "(%04d) %s\n", glyph, buf[0]);
|
||||||
} else if (filling_cache) {
|
} else if (filling_cache) {
|
||||||
glyphid_cache[glyph].glyphnum = glyph;
|
add_glyph_to_cache(glyph, buf[0]);
|
||||||
glyphid_cache[glyph].id = dupstr(buf[0]);
|
|
||||||
} else if (id) {
|
} else if (id) {
|
||||||
if (!strcmpi(id, buf[0])) {
|
if (!strcmpi(id, buf[0])) {
|
||||||
findwhat->findtype = find_glyph;
|
findwhat->findtype = find_glyph;
|
||||||
@@ -910,16 +977,6 @@ parse_id(const char *id, struct find_struct *findwhat)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
glyphid_search_compare(const void *p1, const void *p2)
|
|
||||||
{
|
|
||||||
const char *key = (const char *) p1;
|
|
||||||
const struct glyphid_cache_t *elem = (const struct glyphid_cache_t *) p2;
|
|
||||||
const char *str = elem->id ? elem->id : "";
|
|
||||||
|
|
||||||
return strcmp(key, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
int index;
|
int index;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|||||||
Reference in New Issue
Block a user