|
|
|
@ -114,18 +114,16 @@ static const char canon_map[256] = { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static hb_bool_t |
|
|
|
|
lang_equal (const void *v1, |
|
|
|
|
const void *v2) |
|
|
|
|
lang_equal (hb_language_t v1, |
|
|
|
|
const void *v2) |
|
|
|
|
{ |
|
|
|
|
const unsigned char *p1 = (const unsigned char *) v1; |
|
|
|
|
const unsigned char *p2 = (const unsigned char *) v2; |
|
|
|
|
|
|
|
|
|
while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2]) |
|
|
|
|
{ |
|
|
|
|
p1++, p2++; |
|
|
|
|
} |
|
|
|
|
while (*p1 && *p1 == canon_map[*p2]) |
|
|
|
|
p1++, p2++; |
|
|
|
|
|
|
|
|
|
return (canon_map[*p1] == canon_map[*p2]); |
|
|
|
|
return *p1 == canon_map[*p2]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
@ -147,6 +145,7 @@ lang_hash (const void *key) |
|
|
|
|
|
|
|
|
|
struct hb_language_item_t { |
|
|
|
|
|
|
|
|
|
struct hb_language_item_t *next; |
|
|
|
|
hb_language_t lang; |
|
|
|
|
|
|
|
|
|
inline bool operator == (const char *s) const { |
|
|
|
@ -164,10 +163,53 @@ struct hb_language_item_t { |
|
|
|
|
void finish (void) { free (lang); } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static struct hb_static_lang_set_t : hb_lockable_set_t<hb_language_item_t, hb_static_mutex_t> { |
|
|
|
|
~hb_static_lang_set_t (void) { this->finish (lock); } |
|
|
|
|
hb_static_mutex_t lock; |
|
|
|
|
} langs; |
|
|
|
|
|
|
|
|
|
/* Thread-safe lock-free language list */ |
|
|
|
|
|
|
|
|
|
static hb_language_item_t *langs; |
|
|
|
|
|
|
|
|
|
static |
|
|
|
|
void free_langs (void) |
|
|
|
|
{ |
|
|
|
|
while (langs) { |
|
|
|
|
hb_language_item_t *next = langs->next; |
|
|
|
|
langs->finish (); |
|
|
|
|
free (langs); |
|
|
|
|
langs = next; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static hb_language_item_t * |
|
|
|
|
lang_find_or_insert (const char *key) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
retry: |
|
|
|
|
hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); |
|
|
|
|
|
|
|
|
|
for (hb_language_item_t *lang = first_lang; lang; lang = lang->next) |
|
|
|
|
if (*lang == key) |
|
|
|
|
return lang; |
|
|
|
|
|
|
|
|
|
/* Not found; allocate one. */ |
|
|
|
|
hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t)); |
|
|
|
|
if (unlikely (!lang)) |
|
|
|
|
return NULL; |
|
|
|
|
lang->next = first_lang; |
|
|
|
|
*lang = key; |
|
|
|
|
|
|
|
|
|
if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) { |
|
|
|
|
free (lang); |
|
|
|
|
goto retry; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef HAVE_ATEXIT |
|
|
|
|
if (!first_lang) /* First person registers atexit() callback. */ |
|
|
|
|
atexit (free_langs); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
return lang; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hb_language_t |
|
|
|
|
hb_language_from_string (const char *str, int len) |
|
|
|
@ -182,7 +224,7 @@ hb_language_from_string (const char *str, int len) |
|
|
|
|
strbuf[len] = '\0'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
hb_language_item_t *item = langs.find_or_insert (str, langs.lock); |
|
|
|
|
hb_language_item_t *item = lang_find_or_insert (str); |
|
|
|
|
|
|
|
|
|
return likely (item) ? item->lang : HB_LANGUAGE_INVALID; |
|
|
|
|
} |
|
|
|
|