diff options
author | Andy Wingo <wingo@pobox.com> | 2011-01-07 09:03:12 -0800 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2011-01-07 09:18:41 -0800 |
commit | 30c282bf93d7162fd8898a035ab60a3a556c5199 (patch) | |
tree | cef67564e4a0e3d155254d44bb9be73e1c244598 /libguile/symbols.c | |
parent | 17072fd2c6acad1d4f2b5c98eb0d62911ea07406 (diff) | |
download | guile-30c282bf93d7162fd8898a035ab60a3a556c5199.tar.gz |
optimize scm_from_latin1_symboln
* libguile/symbols.c (lookup_interned_latin1_symbol): New helper.
(scm_from_latin1_symboln): Use lookup_interned_latin1_symbol, so we
avoid allocating a string in that case.
Diffstat (limited to 'libguile/symbols.c')
-rw-r--r-- | libguile/symbols.c | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/libguile/symbols.c b/libguile/symbols.c index ccd54d16c..b9d41b0e2 100644 --- a/libguile/symbols.c +++ b/libguile/symbols.c @@ -121,6 +121,49 @@ lookup_interned_symbol (SCM name, unsigned long raw_hash) return SCM_BOOL_F; } +struct latin1_lookup_data +{ + const char *str; + size_t len; + unsigned long string_hash; +}; + +static int +latin1_lookup_predicate_fn (SCM sym, void *closure) +{ + struct latin1_lookup_data *data = closure; + + return scm_i_symbol_hash (sym) == data->string_hash + && scm_i_is_narrow_symbol (sym) + && scm_i_symbol_length (sym) == data->len + && strncmp (scm_i_symbol_chars (sym), data->str, data->len) == 0; +} + +static SCM +lookup_interned_latin1_symbol (const char *str, size_t len, + unsigned long raw_hash) +{ + struct latin1_lookup_data data; + SCM handle; + + data.str = str; + data.len = len; + data.string_hash = raw_hash; + + /* Strictly speaking, we should take a lock here. But instead we rely + on the fact that if this fails, we do take the lock on the + intern_symbol path; and since nothing deletes from the hash table + except GC, we should be OK. */ + handle = scm_hash_fn_get_handle_by_hash (symbols, raw_hash, + latin1_lookup_predicate_fn, + &data); + + if (scm_is_true (handle)) + return SCM_CAR (handle); + else + return SCM_BOOL_F; +} + static unsigned long symbol_lookup_hash_fn (SCM obj, unsigned long max, void *closure) { @@ -422,8 +465,21 @@ scm_from_latin1_symbol (const char *sym) SCM scm_from_latin1_symboln (const char *sym, size_t len) { - SCM str = scm_from_latin1_stringn (sym, len); - return scm_i_str2symbol (str); + unsigned long hash; + SCM ret; + + if (len == (size_t) -1) + len = strlen (sym); + hash = scm_i_latin1_string_hash (sym, len); + + ret = lookup_interned_latin1_symbol (sym, len, hash); + if (scm_is_false (ret)) + { + SCM str = scm_from_latin1_stringn (sym, len); + ret = scm_i_str2symbol (str); + } + + return ret; } SCM |