2 ** symbol.c - Symbol class
4 ** See Copyright Notice in mruby.h
10 #include <mruby/khash.h>
11 #include <mruby/string.h>
12 #include <mruby/dump.h>
13 #include <mruby/class.h>
15 /* ------------------------------------------------------ */
16 typedef struct symbol_name {
23 #define SYMBOL_INLINE_BIT_POS 1
24 #define SYMBOL_INLINE_LOWER_BIT_POS 2
25 #define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT_POS - 1))
26 #define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT_POS - 1))
27 #define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT_POS
28 #define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT_POS
29 #ifdef MRB_ENABLE_ALL_SYMBOLS
30 # define SYMBOL_INLINE_P(sym) FALSE
31 # define SYMBOL_INLINE_LOWER_P(sym) FALSE
32 # define sym_inline_pack(name, len) 0
33 # define sym_inline_unpack(sym, buf, lenp) NULL
35 # define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE)
36 # define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER)
40 sym_validate_len(mrb_state *mrb, size_t len)
42 if (len >= RITE_LV_NULL_MARK) {
43 mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long");
47 #ifndef MRB_ENABLE_ALL_SYMBOLS
48 static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
51 sym_inline_pack(const char *name, size_t len)
53 const size_t lower_length_max = (MRB_SYMBOL_BIT - 2) / 5;
54 const size_t mix_length_max = (MRB_SYMBOL_BIT - 2) / 6;
60 mrb_bool lower = TRUE;
62 if (len > lower_length_max) return 0; /* too long */
63 for (i=0; i<len; i++) {
67 if (c == 0) return 0; /* NUL in name */
68 p = strchr(pack_table, (int)c);
69 if (p == 0) return 0; /* non alnum char */
70 bits = (uint32_t)(p - pack_table)+1;
71 if (bits > 27) lower = FALSE;
72 if (i >= mix_length_max) break;
73 sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT);
77 for (i=0; i<len; i++) {
81 p = strchr(pack_table, (int)c);
82 bits = (uint32_t)(p - pack_table)+1;
83 sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT);
85 return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER;
87 if (len > mix_length_max) return 0;
88 return sym | SYMBOL_INLINE;
92 sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp)
94 int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6;
97 mrb_assert(SYMBOL_INLINE_P(sym));
99 for (i=0; i<30/bit_per_char; i++) {
100 uint32_t bits = sym>>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1<<bit_per_char)-1);
101 if (bits == 0) break;
102 buf[i] = pack_table[bits-1];;
111 symhash(const char *key, size_t len)
115 for(hash = i = 0; i < len; ++i) {
117 hash += (hash << 10);
121 hash ^= (hash >> 11);
122 hash += (hash << 15);
127 find_symbol(mrb_state *mrb, const char *name, size_t len, uint8_t *hashp)
134 i = sym_inline_pack(name, len);
137 hash = symhash(name, len);
138 if (hashp) *hashp = hash;
140 i = mrb->symhash[hash];
141 if (i == 0) return 0;
143 sname = &mrb->symtbl[i];
144 if (sname->len == len && memcmp(sname->name, name, len) == 0) {
145 return i<<SYMBOL_NORMAL_SHIFT;
147 if (sname->prev == 0xff) {
149 sname = &mrb->symtbl[i];
150 while (mrb->symtbl < sname) {
151 if (sname->len == len && memcmp(sname->name, name, len) == 0) {
152 return (mrb_sym)(sname - mrb->symtbl)<<SYMBOL_NORMAL_SHIFT;
159 } while (sname->prev > 0);
164 sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
170 sym_validate_len(mrb, len);
171 sym = find_symbol(mrb, name, len, &hash);
172 if (sym > 0) return sym;
174 /* registering a new symbol */
175 sym = mrb->symidx + 1;
176 if (mrb->symcapa < sym) {
177 size_t symcapa = mrb->symcapa;
178 if (symcapa == 0) symcapa = 100;
179 else symcapa = (size_t)(symcapa * 6 / 5);
180 mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(symcapa+1));
181 mrb->symcapa = symcapa;
183 sname = &mrb->symtbl[sym];
184 sname->len = (uint16_t)len;
185 if (lit || mrb_ro_data_p(name)) {
190 char *p = (char *)mrb_malloc(mrb, len+1);
191 memcpy(p, name, len);
193 sname->name = (const char*)p;
196 if (mrb->symhash[hash]) {
197 mrb_sym i = sym - mrb->symhash[hash];
206 mrb->symhash[hash] = mrb->symidx = sym;
208 return sym<<SYMBOL_NORMAL_SHIFT;
212 mrb_intern(mrb_state *mrb, const char *name, size_t len)
214 return sym_intern(mrb, name, len, FALSE);
218 mrb_intern_static(mrb_state *mrb, const char *name, size_t len)
220 return sym_intern(mrb, name, len, TRUE);
224 mrb_intern_cstr(mrb_state *mrb, const char *name)
226 return mrb_intern(mrb, name, strlen(name));
230 mrb_intern_str(mrb_state *mrb, mrb_value str)
232 return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
236 mrb_check_intern(mrb_state *mrb, const char *name, size_t len)
240 sym_validate_len(mrb, len);
241 sym = find_symbol(mrb, name, len, NULL);
242 if (sym > 0) return mrb_symbol_value(sym);
243 return mrb_nil_value();
247 mrb_check_intern_cstr(mrb_state *mrb, const char *name)
249 return mrb_check_intern(mrb, name, strlen(name));
253 mrb_check_intern_str(mrb_state *mrb, mrb_value str)
255 return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str));
259 sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp)
261 if (SYMBOL_INLINE_P(sym)) return sym_inline_unpack(sym, buf, lenp);
263 sym >>= SYMBOL_NORMAL_SHIFT;
264 if (sym == 0 || mrb->symidx < sym) {
269 if (lenp) *lenp = mrb->symtbl[sym].len;
270 return mrb->symtbl[sym].name;
274 mrb_sym_name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
276 return sym2name_len(mrb, sym, mrb->symbuf, lenp);
280 mrb_free_symtbl(mrb_state *mrb)
284 for (i=1, lim=mrb->symidx+1; i<lim; i++) {
285 if (!mrb->symtbl[i].lit) {
286 mrb_free(mrb, (char*)mrb->symtbl[i].name);
289 mrb_free(mrb, mrb->symtbl);
293 mrb_init_symtbl(mrb_state *mrb)
297 /**********************************************************************
298 * Document-class: Symbol
300 * <code>Symbol</code> objects represent names and some strings
302 * interpreter. They are generated using the <code>:name</code> and
303 * <code>:"string"</code> literals
304 * syntax, and by the various <code>to_sym</code> methods. The same
305 * <code>Symbol</code> object will be created for a given name or string
306 * for the duration of a program's execution, regardless of the context
307 * or meaning of that name. Thus if <code>Fred</code> is a constant in
308 * one context, a method in another, and a class in a third, the
309 * <code>Symbol</code> <code>:Fred</code> will be the same object in
310 * all three contexts.
324 * $f1.object_id #=> 2514190
325 * $f2.object_id #=> 2514190
326 * $f3.object_id #=> 2514190
334 * sym.id2name -> string
337 * Returns the name or string corresponding to <i>sym</i>.
339 * :fred.id2name #=> "fred"
342 sym_to_s(mrb_state *mrb, mrb_value sym)
344 return mrb_sym_str(mrb, mrb_symbol(sym));
353 * In general, <code>to_sym</code> returns the <code>Symbol</code> corresponding
354 * to an object. As <i>sym</i> is already a symbol, <code>self</code> is returned
359 sym_to_sym(mrb_state *mrb, mrb_value sym)
367 * sym.inspect -> string
369 * Returns the representation of <i>sym</i> as a symbol literal.
371 * :fred.inspect #=> ":fred"
375 # define SIGN_EXTEND_CHAR(c) ((signed char)(c))
376 #else /* not __STDC__ */
377 /* As in Harbison and Steele. */
378 # define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128)
380 #define is_identchar(c) (SIGN_EXTEND_CHAR(c)!=-1&&(ISALNUM(c) || (c) == '_'))
383 is_special_global_name(const char* m)
386 case '~': case '*': case '$': case '?': case '!': case '@':
387 case '/': case '\\': case ';': case ',': case '.': case '=':
388 case ':': case '<': case '>': case '\"':
389 case '&': case '`': case '\'': case '+':
395 if (is_identchar(*m)) m += 1;
398 if (!ISDIGIT(*m)) return FALSE;
399 do ++m; while (ISDIGIT(*m));
406 symname_p(const char *name)
408 const char *m = name;
409 mrb_bool localid = FALSE;
411 if (!m) return FALSE;
417 if (is_special_global_name(++m)) return TRUE;
421 if (*++m == '@') ++m;
426 case '<': ++m; break;
427 case '=': if (*++m == '>') ++m; break;
434 case '>': case '=': ++m; break;
441 case '~': ++m; break;
442 case '=': if (*++m == '=') ++m; break;
443 default: return FALSE;
448 if (*++m == '*') ++m;
452 case '=': case '~': ++m;
456 if (*++m == '@') ++m;
459 if (*++m == '|') ++m;
462 if (*++m == '&') ++m;
465 case '^': case '/': case '%': case '~': case '`':
470 if (*++m != ']') return FALSE;
471 if (*++m == '=') ++m;
475 localid = !ISUPPER(*m);
477 if (*m != '_' && !ISALPHA(*m)) return FALSE;
478 while (is_identchar(*m)) m += 1;
481 case '!': case '?': case '=': ++m;
487 return *m ? FALSE : TRUE;
491 sym_inspect(mrb_state *mrb, mrb_value sym)
496 mrb_sym id = mrb_symbol(sym);
499 name = mrb_sym_name_len(mrb, id, &len);
500 str = mrb_str_new(mrb, 0, len+1);
501 sp = RSTRING_PTR(str);
503 memcpy(sp+1, name, len);
504 mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
505 if (!symname_p(name) || strlen(name) != (size_t)len) {
506 str = mrb_str_inspect(mrb, str);
507 sp = RSTRING_PTR(str);
511 #ifdef MRB_UTF8_STRING
512 if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
518 mrb_sym_str(mrb_state *mrb, mrb_sym sym)
521 const char *name = mrb_sym_name_len(mrb, sym, &len);
523 if (!name) return mrb_undef_value(); /* can't happen */
524 if (SYMBOL_INLINE_P(sym)) {
525 mrb_value str = mrb_str_new(mrb, name, len);
526 RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
529 return mrb_str_new_static(mrb, name, len);
533 sym_name(mrb_state *mrb, mrb_sym sym, mrb_bool dump)
536 const char *name = mrb_sym_name_len(mrb, sym, &len);
538 if (!name) return NULL;
539 if (strlen(name) == (size_t)len && (!dump || symname_p(name))) {
543 mrb_value str = SYMBOL_INLINE_P(sym) ?
544 mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len);
545 str = mrb_str_dump(mrb, str);
546 return RSTRING_PTR(str);
551 mrb_sym_name(mrb_state *mrb, mrb_sym sym)
553 return sym_name(mrb, sym, FALSE);
557 mrb_sym_dump(mrb_state *mrb, mrb_sym sym)
559 return sym_name(mrb, sym, TRUE);
562 #define lesser(a,b) (((a)>(b))?(b):(a))
565 sym_cmp(mrb_state *mrb, mrb_value s1)
567 mrb_value s2 = mrb_get_arg1(mrb);
570 if (!mrb_symbol_p(s2)) return mrb_nil_value();
571 sym1 = mrb_symbol(s1);
572 sym2 = mrb_symbol(s2);
573 if (sym1 == sym2) return mrb_fixnum_value(0);
577 mrb_int len, len1, len2;
578 char buf1[8], buf2[8];
580 p1 = sym2name_len(mrb, sym1, buf1, &len1);
581 p2 = sym2name_len(mrb, sym2, buf2, &len2);
582 len = lesser(len1, len2);
583 retval = memcmp(p1, p2, len);
585 if (len1 == len2) return mrb_fixnum_value(0);
586 if (len1 > len2) return mrb_fixnum_value(1);
587 return mrb_fixnum_value(-1);
589 if (retval > 0) return mrb_fixnum_value(1);
590 return mrb_fixnum_value(-1);
595 mrb_init_symbol(mrb_state *mrb)
599 mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */
600 MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL);
601 mrb_undef_class_method(mrb, sym, "new");
603 mrb_define_method(mrb, sym, "id2name", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */
604 mrb_define_method(mrb, sym, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */
605 mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
606 mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */
607 mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1));