diff options
Diffstat (limited to 'libguile/symbols.c')
-rw-r--r-- | libguile/symbols.c | 163 |
1 files changed, 107 insertions, 56 deletions
diff --git a/libguile/symbols.c b/libguile/symbols.c index 08512a63f..f93833b9d 100644 --- a/libguile/symbols.c +++ b/libguile/symbols.c @@ -1,5 +1,5 @@ /* Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2003, 2004, - * 2006, 2009, 2011 Free Software Foundation, Inc. + * 2006, 2009, 2011, 2013 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -23,6 +23,8 @@ # include <config.h> #endif +#include <unistr.h> + #include "libguile/_scm.h" #include "libguile/chars.h" #include "libguile/eval.h" @@ -33,8 +35,7 @@ #include "libguile/fluids.h" #include "libguile/strings.h" #include "libguile/vectors.h" -#include "libguile/hashtab.h" -#include "libguile/weaks.h" +#include "libguile/weak-set.h" #include "libguile/modules.h" #include "libguile/read.h" #include "libguile/srfi-13.h" @@ -52,7 +53,6 @@ static SCM symbols; -static scm_i_pthread_mutex_t symbols_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER; #ifdef GUILE_DEBUG SCM_DEFINE (scm_sys_symbols, "%symbols", 0, 0, 0, @@ -104,21 +104,13 @@ static SCM lookup_interned_symbol (SCM name, unsigned long raw_hash) { struct string_lookup_data data; - SCM handle; data.string = name; data.string_hash = raw_hash; - scm_i_pthread_mutex_lock (&symbols_lock); - handle = scm_hash_fn_get_handle_by_hash (symbols, raw_hash, - string_lookup_predicate_fn, - &data); - scm_i_pthread_mutex_unlock (&symbols_lock); - - if (scm_is_true (handle)) - return SCM_CAR (handle); - else - return SCM_BOOL_F; + return scm_c_weak_set_lookup (symbols, raw_hash, + string_lookup_predicate_fn, + &data, SCM_BOOL_F); } struct latin1_lookup_data @@ -144,63 +136,104 @@ 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; - scm_i_pthread_mutex_lock (&symbols_lock); - handle = scm_hash_fn_get_handle_by_hash (symbols, raw_hash, - latin1_lookup_predicate_fn, - &data); - scm_i_pthread_mutex_unlock (&symbols_lock); - - if (scm_is_true (handle)) - return SCM_CAR (handle); - else - return SCM_BOOL_F; + return scm_c_weak_set_lookup (symbols, raw_hash, + latin1_lookup_predicate_fn, + &data, SCM_BOOL_F); } -static unsigned long -symbol_lookup_hash_fn (SCM obj, unsigned long max, void *closure) +struct utf8_lookup_data { - return scm_i_symbol_hash (obj) % max; -} + const char *str; + size_t len; + unsigned long string_hash; +}; -static SCM -symbol_lookup_assoc_fn (SCM obj, SCM alist, void *closure) +static int +utf8_string_equals_wide_string (const scm_t_uint8 *narrow, size_t nlen, + const scm_t_wchar *wide, size_t wlen) { - for (; !scm_is_null (alist); alist = SCM_CDR (alist)) + size_t byte_idx = 0, char_idx = 0; + + while (byte_idx < nlen && char_idx < wlen) { - SCM sym = SCM_CAAR (alist); - - if (scm_i_symbol_hash (sym) == scm_i_symbol_hash (obj) - && scm_is_true (scm_string_equal_p (scm_symbol_to_string (sym), - scm_symbol_to_string (obj)))) - return SCM_CAR (alist); + ucs4_t c; + int nbytes; + + nbytes = u8_mbtouc (&c, narrow + byte_idx, nlen - byte_idx); + if (nbytes == 0) + break; + else if (c == 0xfffd) + /* Bad UTF-8. */ + return 0; + else if (c != wide[char_idx]) + return 0; + + byte_idx += nbytes; + char_idx++; } - return SCM_BOOL_F; + return byte_idx == nlen && char_idx == wlen; } -/* Intern SYMBOL, an uninterned symbol. Might return a different - symbol, if another one was interned at the same time. */ -static SCM -intern_symbol (SCM symbol) +static int +utf8_lookup_predicate_fn (SCM sym, void *closure) { - SCM handle; + struct utf8_lookup_data *data = closure; - scm_i_pthread_mutex_lock (&symbols_lock); - handle = scm_hash_fn_create_handle_x (symbols, symbol, SCM_UNDEFINED, - symbol_lookup_hash_fn, - symbol_lookup_assoc_fn, - NULL); - scm_i_pthread_mutex_unlock (&symbols_lock); + if (scm_i_symbol_hash (sym) != data->string_hash) + return 0; + + if (scm_i_is_narrow_symbol (sym)) + return (scm_i_symbol_length (sym) == data->len + && strncmp (scm_i_symbol_chars (sym), data->str, data->len) == 0); + else + return utf8_string_equals_wide_string ((const scm_t_uint8 *) data->str, + data->len, + scm_i_symbol_wide_chars (sym), + scm_i_symbol_length (sym)); +} - return SCM_CAR (handle); +static SCM +lookup_interned_utf8_symbol (const char *str, size_t len, + unsigned long raw_hash) +{ + struct utf8_lookup_data data; + + data.str = str; + data.len = len; + data.string_hash = raw_hash; + + return scm_c_weak_set_lookup (symbols, raw_hash, + utf8_lookup_predicate_fn, + &data, SCM_BOOL_F); } +static int +symbol_lookup_predicate_fn (SCM sym, void *closure) +{ + SCM other = SCM_PACK_POINTER (closure); + + if (scm_i_symbol_hash (sym) == scm_i_symbol_hash (other) + && scm_i_symbol_length (sym) == scm_i_symbol_length (other)) + { + if (scm_i_is_narrow_symbol (sym)) + return scm_i_is_narrow_symbol (other) + && (strncmp (scm_i_symbol_chars (sym), + scm_i_symbol_chars (other), + scm_i_symbol_length (other)) == 0); + else + return scm_is_true + (scm_string_equal_p (scm_symbol_to_string (sym), + scm_symbol_to_string (other))); + } + return 0; +} + static SCM scm_i_str2symbol (SCM str) { @@ -215,7 +248,12 @@ scm_i_str2symbol (SCM str) /* The symbol was not found, create it. */ symbol = scm_i_make_symbol (str, 0, raw_hash, scm_cons (SCM_BOOL_F, SCM_EOL)); - return intern_symbol (symbol); + + /* Might return a different symbol, if another one was interned at + the same time. */ + return scm_c_weak_set_add_x (symbols, raw_hash, + symbol_lookup_predicate_fn, + SCM_UNPACK_POINTER (symbol), symbol); } } @@ -491,14 +529,27 @@ scm_from_utf8_symbol (const char *sym) SCM scm_from_utf8_symboln (const char *sym, size_t len) { - SCM str = scm_from_utf8_stringn (sym, len); - return scm_i_str2symbol (str); + unsigned long hash; + SCM ret; + + if (len == (size_t) -1) + len = strlen (sym); + hash = scm_i_utf8_string_hash (sym, len); + + ret = lookup_interned_utf8_symbol (sym, len, hash); + if (scm_is_false (ret)) + { + SCM str = scm_from_utf8_stringn (sym, len); + ret = scm_i_str2symbol (str); + } + + return ret; } void scm_symbols_prehistory () { - symbols = scm_make_weak_key_hash_table (scm_from_int (2139)); + symbols = scm_c_make_weak_set (5000); } |