summaryrefslogtreecommitdiffstats
path: root/third_party/harfbuzz-ng/src/hb-common.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/harfbuzz-ng/src/hb-common.cc')
-rw-r--r--third_party/harfbuzz-ng/src/hb-common.cc89
1 files changed, 62 insertions, 27 deletions
diff --git a/third_party/harfbuzz-ng/src/hb-common.cc b/third_party/harfbuzz-ng/src/hb-common.cc
index bfbba65..331d255 100644
--- a/third_party/harfbuzz-ng/src/hb-common.cc
+++ b/third_party/harfbuzz-ng/src/hb-common.cc
@@ -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,52 @@ 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)
+ atexit (free_langs); /* First person registers atexit() callback. */
+#endif
+
+ return lang;
+}
+
hb_language_t
hb_language_from_string (const char *str, int len)
@@ -182,7 +223,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;
}
@@ -314,47 +355,41 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* hb_user_data_array_t */
-
-/* NOTE: Currently we use a global lock for user_data access
- * threadsafety. If one day we add a mutex to any object, we
- * should switch to using that insted for these too.
- */
-
-static hb_static_mutex_t user_data_lock;
-
bool
hb_user_data_array_t::set (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
- hb_bool_t replace)
+ hb_bool_t replace,
+ hb_mutex_t &lock)
{
if (!key)
return false;
if (replace) {
if (!data && !destroy) {
- items.remove (key, user_data_lock);
+ items.remove (key, lock);
return true;
}
}
hb_user_data_item_t item = {key, data, destroy};
- bool ret = !!items.replace_or_insert (item, user_data_lock, replace);
+ bool ret = !!items.replace_or_insert (item, lock, replace);
return ret;
}
void *
-hb_user_data_array_t::get (hb_user_data_key_t *key)
+hb_user_data_array_t::get (hb_user_data_key_t *key,
+ hb_mutex_t &lock)
{
hb_user_data_item_t item = {NULL };
- return items.find (key, &item, user_data_lock) ? item.data : NULL;
+ return items.find (key, &item, lock) ? item.data : NULL;
}
void
-hb_user_data_array_t::finish (void)
+hb_user_data_array_t::finish (hb_mutex_t &lock)
{
- items.finish (user_data_lock);
+ items.finish (lock);
}