summaryrefslogtreecommitdiffhomepage
path: root/src/symbol.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/symbol.c')
-rw-r--r--src/symbol.c173
1 files changed, 131 insertions, 42 deletions
diff --git a/src/symbol.c b/src/symbol.c
index aa5b659fa..b81296929 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -8,68 +8,99 @@
#include "mruby/khash.h"
#include <string.h>
-#include <stdarg.h>
-#include <string.h>
#include "mruby/string.h"
#include <ctype.h>
-#include "mruby/class.h"
-#include "mruby/variable.h"
-#include <stdio.h>
/* ------------------------------------------------------ */
-KHASH_INIT(s2n, mrb_sym, const char*, 1, kh_int_hash_func, kh_int_hash_equal)
-KHASH_MAP_INIT_STR(n2s, mrb_sym);
+typedef struct symbol_name {
+ int len;
+ const char *name;
+} symbol_name;
+
+static inline khint_t
+sym_hash_func(mrb_state *mrb, const symbol_name s)
+{
+ khint_t h = 0;
+ size_t i;
+ const char *p = s.name;
+
+ for (i=0; i<s.len; i++) {
+ h = (h << 5) - h + *p++;
+ }
+ return h;
+}
+#define sym_hash_equal(mrb,a, b) (a.len == b.len && memcmp(a.name, b.name, a.len) == 0)
+
+KHASH_DECLARE(n2s, symbol_name, mrb_sym, 1)
+KHASH_DEFINE (n2s, symbol_name, mrb_sym, 1, sym_hash_func, sym_hash_equal)
/* ------------------------------------------------------ */
mrb_sym
-mrb_intern(mrb_state *mrb, const char *name)
+mrb_intern2(mrb_state *mrb, const char *name, int len)
{
khash_t(n2s) *h = mrb->name2sym;
- khash_t(s2n) *rh = mrb->sym2name;
+ symbol_name sname;
khiter_t k;
- size_t len;
- char *p;
mrb_sym sym;
+ char *p;
- k = kh_get(n2s, h, name);
+ sname.len = len;
+ sname.name = name;
+ k = kh_get(n2s, h, sname);
if (k != kh_end(h))
return kh_value(h, k);
sym = ++mrb->symidx;
- len = strlen(name);
- p = mrb_malloc(mrb, len+1);
+ p = (char *)mrb_malloc(mrb, len+1);
memcpy(p, name, len);
p[len] = 0;
- k = kh_put(n2s, h, p);
+ sname.name = (const char*)p;
+ k = kh_put(n2s, h, sname);
kh_value(h, k) = sym;
- k = kh_put(s2n, rh, sym);
- kh_value(rh, k) = p;
-
return sym;
}
+mrb_sym
+mrb_intern(mrb_state *mrb, const char *name)
+{
+ return mrb_intern2(mrb, name, strlen(name));
+}
+
+mrb_sym
+mrb_intern_str(mrb_state *mrb, mrb_value str)
+{
+ return mrb_intern2(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
+}
+
const char*
-mrb_sym2name(mrb_state *mrb, mrb_sym sym)
+mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, int *lenp)
{
- khash_t(s2n) *h = mrb->sym2name;
+ khash_t(n2s) *h = mrb->name2sym;
khiter_t k;
+ symbol_name sname;
- k = kh_get(s2n, h, sym);
+ for (k = kh_begin(h); k != kh_end(h); k++) {
+ if (kh_exist(h, k)) {
+ if (kh_value(h, k) == sym) break;
+ }
+ }
if (k == kh_end(h)) {
- return NULL; /* missing */
+ *lenp = 0;
+ return NULL; /* missing */
}
- return kh_value(h, k);
+ sname = kh_key(h, k);
+ *lenp = sname.len;
+ return sname.name;
}
void
mrb_free_symtbls(mrb_state *mrb)
{
- khash_t(s2n) *h = mrb->sym2name;
+ khash_t(n2s) *h = mrb->name2sym;
khiter_t k;
- for (k = kh_begin(h); k != kh_end(h); ++k)
- if (kh_exist(h, k)) mrb_free(mrb, (char*)kh_value(h, k));
- kh_destroy(s2n,mrb->sym2name);
+ for (k = kh_begin(h); k != kh_end(h); k++)
+ if (kh_exist(h, k)) mrb_free(mrb, (char*)kh_key(h, k).name);
kh_destroy(n2s,mrb->name2sym);
}
@@ -77,7 +108,6 @@ void
mrb_init_symtbl(mrb_state *mrb)
{
mrb->name2sym = kh_init(n2s, mrb);
- mrb->sym2name = kh_init(s2n, mrb);
}
/**********************************************************************
@@ -148,8 +178,11 @@ mrb_value
mrb_sym_to_s(mrb_state *mrb, mrb_value sym)
{
mrb_sym id = SYM2ID(sym);
+ const char *p;
+ int len;
- return mrb_str_new_cstr(mrb, mrb_sym2name(mrb, id));
+ p = mrb_sym2name_len(mrb, id, &len);
+ return mrb_str_new(mrb, p, len);
}
/* 15.2.11.3.4 */
@@ -188,8 +221,7 @@ sym_to_sym(mrb_state *mrb, mrb_value sym)
#define is_identchar(c) (SIGN_EXTEND_CHAR(c)!=-1&&(ISALNUM(c) || (c) == '_'))
static int
-is_special_global_name(m)
- const char *m;
+is_special_global_name(const char* m)
{
switch (*m) {
case '~': case '*': case '$': case '?': case '!': case '@':
@@ -240,6 +272,7 @@ symname_p(const char *name)
case '>':
switch (*++m) {
case '>': case '=': ++m; break;
+ default: break;
}
break;
@@ -254,12 +287,20 @@ symname_p(const char *name)
case '*':
if (*++m == '*') ++m;
break;
-
+ case '!':
+ if (*++m == '=') ++m;
+ break;
case '+': case '-':
if (*++m == '@') ++m;
break;
+ case '|':
+ if (*++m == '|') ++m;
+ break;
+ case '&':
+ if (*++m == '&') ++m;
+ break;
- case '|': case '^': case '&': case '/': case '%': case '~': case '`':
+ case '^': case '/': case '%': case '~': case '`':
++m;
break;
@@ -275,7 +316,8 @@ id:
while (is_identchar(*m)) m += 1;
if (localid) {
switch (*m) {
- case '!': case '?': case '=': ++m;
+ case '!': case '?': case '=': ++m;
+ default: break;
}
}
break;
@@ -288,22 +330,69 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
{
mrb_value str;
const char *name;
+ int len;
mrb_sym id = SYM2ID(sym);
- name = mrb_sym2name(mrb, id); //mrb_id2name(id);
- str = mrb_str_new(mrb, 0, strlen(name)+1);
- RSTRING(str)->buf[0] = ':';
- strcpy(RSTRING(str)->buf+1, name);
- if (!symname_p(name)) {
+ name = mrb_sym2name_len(mrb, id, &len);
+ str = mrb_str_new(mrb, 0, len+1);
+ RSTRING(str)->ptr[0] = ':';
+ memcpy(RSTRING(str)->ptr+1, name, len);
+ if (!symname_p(name) || strlen(name) != len) {
str = mrb_str_dump(mrb, str);
- strncpy(RSTRING(str)->buf, ":\"", 2);
+ memcpy(RSTRING(str)->ptr, ":\"", 2);
}
return str;
}
+const char*
+mrb_sym2name(mrb_state *mrb, mrb_sym sym)
+{
+ int len;
+ const char *name = mrb_sym2name_len(mrb, sym, &len);
+
+ if (!name) return NULL;
+ if (symname_p(name) && strlen(name) == len) {
+ return name;
+ }
+ else {
+ mrb_value str = mrb_str_dump(mrb, mrb_str_new(mrb, name, len));
+ return RSTRING(str)->ptr;
+ }
+}
+
+#define lesser(a,b) (((a)>(b))?(b):(a))
+
+static mrb_value
+sym_cmp(mrb_state *mrb, mrb_value s1)
+{
+ mrb_value s2;
+ mrb_sym sym1, sym2;
+
+ mrb_get_args(mrb, "o", &s2);
+ if (mrb_type(s2) != MRB_TT_SYMBOL) return mrb_nil_value();
+ sym1 = mrb_symbol(s1);
+ sym2 = mrb_symbol(s2);
+ if (sym1 == sym2) return mrb_fixnum_value(0);
+ else {
+ const char *p1, *p2;
+ int len, len1, len2, retval;
+
+ p1 = mrb_sym2name_len(mrb, sym1, &len1);
+ p2 = mrb_sym2name_len(mrb, sym2, &len2);
+ len = lesser(len1, len2);
+ retval = memcmp(p1, p2, len);
+ if (retval == 0) {
+ if (len1 == len2) return mrb_fixnum_value(0);
+ if (len1 > len2) return mrb_fixnum_value(1);
+ return mrb_fixnum_value(-1);
+ }
+ if (retval > 0) return mrb_fixnum_value(1);
+ return mrb_fixnum_value(-1);
+ }
+}
void
-mrb_init_symbols(mrb_state *mrb)
+mrb_init_symbol(mrb_state *mrb)
{
struct RClass *sym;
@@ -313,6 +402,6 @@ mrb_init_symbols(mrb_state *mrb)
mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, ARGS_NONE()); /* 15.2.11.3.2 */
mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, ARGS_NONE()); /* 15.2.11.3.3 */
mrb_define_method(mrb, sym, "to_sym", sym_to_sym, ARGS_NONE()); /* 15.2.11.3.4 */
-
mrb_define_method(mrb, sym, "inspect", sym_inspect, ARGS_NONE()); /* 15.2.11.3.5(x) */
+ mrb_define_method(mrb, sym, "<=>", sym_cmp, ARGS_REQ(1));
}