Ruby 3.5.0dev (2025-08-06 revision 92688f7d570c9c37ccb05b80577e1032aae908b7)
symbol.c (92688f7d570c9c37ccb05b80577e1032aae908b7)
1/**********************************************************************
2
3 symbol.h -
4
5 $Author$
6 created at: Tue Jul 8 15:49:54 JST 2014
7
8 Copyright (C) 2014 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "internal.h"
13#include "internal/concurrent_set.h"
14#include "internal/error.h"
15#include "internal/gc.h"
16#include "internal/hash.h"
17#include "internal/object.h"
18#include "internal/symbol.h"
19#include "internal/vm.h"
20#include "probes.h"
21#include "ruby/encoding.h"
22#include "ruby/st.h"
23#include "symbol.h"
24#include "vm_sync.h"
25#include "builtin.h"
27
28#if defined(USE_SYMBOL_GC) && !(USE_SYMBOL_GC+0)
29# undef USE_SYMBOL_GC
30# define USE_SYMBOL_GC 0
31#else
32# undef USE_SYMBOL_GC
33# define USE_SYMBOL_GC 1
34#endif
35#if defined(SYMBOL_DEBUG) && (SYMBOL_DEBUG+0)
36# undef SYMBOL_DEBUG
37# define SYMBOL_DEBUG 1
38#else
39# undef SYMBOL_DEBUG
40# define SYMBOL_DEBUG 0
41#endif
42#ifndef CHECK_ID_SERIAL
43# define CHECK_ID_SERIAL SYMBOL_DEBUG
44#endif
45
46#define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST))
47#define IDSET_ATTRSET_FOR_INTERN (~(~0U<<(1<<ID_SCOPE_SHIFT)) & ~(1U<<ID_ATTRSET))
48
49#define SYMBOL_PINNED_P(sym) (RSYMBOL(sym)->id&~ID_SCOPE_MASK)
50
51#define STATIC_SYM2ID(sym) RSHIFT((VALUE)(sym), RUBY_SPECIAL_SHIFT)
52
53static ID register_static_symid(ID, const char *, long, rb_encoding *);
54#define REGISTER_SYMID(id, name) register_static_symid((id), (name), strlen(name), enc)
55#include "id.c"
56
57#define is_identchar(p,e,enc) (ISALNUM((unsigned char)*(p)) || (*(p)) == '_' || !ISASCII(*(p)))
58
59#define op_tbl_count numberof(op_tbl)
60STATIC_ASSERT(op_tbl_name_size, sizeof(op_tbl[0].name) == 3);
61#define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3)
62
63
64#define GLOBAL_SYMBOLS_LOCKING(symbols) \
65 for (rb_symbols_t *symbols = &ruby_global_symbols, **locking = &symbols; \
66 locking; \
67 locking = NULL) \
68 RB_VM_LOCKING()
69
70static void
71Init_op_tbl(void)
72{
73 int i;
74 rb_encoding *const enc = rb_usascii_encoding();
75
76 for (i = '!'; i <= '~'; ++i) {
77 if (!ISALNUM(i) && i != '_') {
78 char c = (char)i;
79 register_static_symid(i, &c, 1, enc);
80 }
81 }
82 for (i = 0; i < op_tbl_count; ++i) {
83 register_static_symid(op_tbl[i].token, op_tbl[i].name, op_tbl_len(i), enc);
84 }
85}
86
87static const int ID_ENTRY_UNIT = 512;
88
89enum id_entry_type {
90 ID_ENTRY_STR,
91 ID_ENTRY_SYM,
92 ID_ENTRY_SIZE
93};
94
95typedef struct {
96 rb_atomic_t next_id;
97 VALUE sym_set;
98
99 VALUE ids;
101
102rb_symbols_t ruby_global_symbols = {tNEXT_ID-1};
103
105 VALUE sym;
106 VALUE str;
107};
108
109#define SYM_SET_SYM_STATIC_TAG 1
110
111static bool
112sym_set_sym_static_p(VALUE sym)
113{
114 return sym & SYM_SET_SYM_STATIC_TAG;
115}
116
117static VALUE
118sym_set_static_sym_tag(struct sym_set_static_sym_entry *sym)
119{
120 VALUE value = (VALUE)sym | SYM_SET_SYM_STATIC_TAG;
121 RUBY_ASSERT(IMMEDIATE_P(value));
122 RUBY_ASSERT(sym_set_sym_static_p(value));
123
124 return value;
125}
126
127static struct sym_set_static_sym_entry *
128sym_set_static_sym_untag(VALUE sym)
129{
130 RUBY_ASSERT(sym_set_sym_static_p(sym));
131
132 return (struct sym_set_static_sym_entry *)(sym & ~((VALUE)SYM_SET_SYM_STATIC_TAG));
133}
134
135static VALUE
136sym_set_sym_get_str(VALUE sym)
137{
138 VALUE str;
139 if (sym_set_sym_static_p(sym)) {
140 str = sym_set_static_sym_untag(sym)->str;
141 }
142 else {
144 str = RSYMBOL(sym)->fstr;
145 }
146
148
149 return str;
150}
151
152static VALUE
153sym_set_hash(VALUE sym)
154{
155 if (sym_set_sym_static_p(sym)) {
156 return (VALUE)rb_str_hash(sym_set_static_sym_untag(sym)->str);
157 }
158 else {
159 return (VALUE)RSYMBOL(sym)->hashval;
160 }
161}
162
163static bool
164sym_set_cmp(VALUE a, VALUE b)
165{
166 return rb_str_hash_cmp(sym_set_sym_get_str(a), sym_set_sym_get_str(b)) == false;
167}
168
169
170static int
171sym_check_asciionly(VALUE str, bool fake_str)
172{
173 if (!rb_enc_asciicompat(rb_enc_get(str))) return FALSE;
174 switch (rb_enc_str_coderange(str)) {
176 if (fake_str) {
177 str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
178 }
179 rb_raise(rb_eEncodingError, "invalid symbol in encoding %s :%+"PRIsVALUE,
180 rb_enc_name(rb_enc_get(str)), str);
182 return TRUE;
183 }
184 return FALSE;
185}
186
187static VALUE
188dup_string_for_create(VALUE str)
189{
190 rb_encoding *enc = rb_enc_get(str);
191
192 str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), enc);
193
194 rb_encoding *ascii = rb_usascii_encoding();
195 if (enc != ascii && sym_check_asciionly(str, false)) {
196 rb_enc_associate(str, ascii);
197 }
198 OBJ_FREEZE(str);
199
200 str = rb_fstring(str);
201
202 return str;
203}
204
205static int
206rb_str_symname_type(VALUE name, unsigned int allowed_attrset)
207{
208 const char *ptr = StringValuePtr(name);
209 long len = RSTRING_LEN(name);
210 int type = rb_enc_symname_type(ptr, len, rb_enc_get(name), allowed_attrset);
211 RB_GC_GUARD(name);
212 return type;
213}
214
215static ID
216next_id_base(void)
217{
218 rb_atomic_t serial = RUBY_ATOMIC_FETCH_ADD(ruby_global_symbols.next_id, 1);
219
220 return (ID)serial << ID_SCOPE_SHIFT;
221}
222
223static void
224set_id_entry(rb_symbols_t *symbols, rb_id_serial_t num, VALUE str, VALUE sym)
225{
226 ASSERT_vm_locking();
229
230 size_t idx = num / ID_ENTRY_UNIT;
231
232 VALUE ary, ids = symbols->ids;
233 if (idx >= (size_t)RARRAY_LEN(ids) || NIL_P(ary = rb_ary_entry(ids, (long)idx))) {
234 ary = rb_ary_hidden_new(ID_ENTRY_UNIT * ID_ENTRY_SIZE);
235 rb_ary_store(ids, (long)idx, ary);
236 }
237 idx = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE;
238 rb_ary_store(ary, (long)idx + ID_ENTRY_STR, str);
239 rb_ary_store(ary, (long)idx + ID_ENTRY_SYM, sym);
240}
241
242static VALUE
243sym_set_create(VALUE sym, void *data)
244{
245 bool create_dynamic_symbol = (bool)data;
246
247 struct sym_set_static_sym_entry *static_sym_entry = sym_set_static_sym_untag(sym);
248
249 VALUE str = dup_string_for_create(static_sym_entry->str);
250
251 if (create_dynamic_symbol) {
252 NEWOBJ_OF(obj, struct RSymbol, rb_cSymbol, T_SYMBOL | FL_WB_PROTECTED, sizeof(struct RSymbol), 0);
253
254 rb_encoding *enc = rb_enc_get(str);
255 rb_enc_set_index((VALUE)obj, rb_enc_to_index(enc));
256 OBJ_FREEZE((VALUE)obj);
257 RB_OBJ_WRITE((VALUE)obj, &obj->fstr, str);
258
259 int id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
260 if (id < 0) id = ID_INTERNAL;
261 obj->id = id;
262
263 obj->hashval = rb_str_hash(str);
264 RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(obj->fstr));
265
266 return (VALUE)obj;
267 }
268 else {
269 struct sym_set_static_sym_entry *new_static_sym_entry = xmalloc(sizeof(struct sym_set_static_sym_entry));
270 new_static_sym_entry->str = str;
271
272 VALUE static_sym = static_sym_entry->sym;
273 if (static_sym == 0) {
274 ID id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
275 if (id == (ID)-1) id = ID_INTERNAL;
276
277 id |= next_id_base();
278 id |= ID_STATIC_SYM;
279
280 static_sym = STATIC_ID2SYM(id);
281 }
282 new_static_sym_entry->sym = static_sym;
283
284 RB_VM_LOCKING() {
285 set_id_entry(&ruby_global_symbols, rb_id_to_serial(STATIC_SYM2ID(static_sym)), str, static_sym);
286 }
287
288 return sym_set_static_sym_tag(new_static_sym_entry);
289 }
290}
291
292static void
293sym_set_free(VALUE sym)
294{
295 if (sym_set_sym_static_p(sym)) {
296 xfree(sym_set_static_sym_untag(sym));
297 }
298}
299
300static const struct rb_concurrent_set_funcs sym_set_funcs = {
301 .hash = sym_set_hash,
302 .cmp = sym_set_cmp,
303 .create = sym_set_create,
304 .free = sym_set_free,
305};
306
307static VALUE
308sym_set_entry_to_sym(VALUE entry)
309{
310 if (sym_set_sym_static_p(entry)) {
311 RUBY_ASSERT(STATIC_SYM_P(sym_set_static_sym_untag(entry)->sym));
312
313 if (!STATIC_SYM_P(sym_set_static_sym_untag(entry)->sym)) rb_bug("not sym");
314
315 return sym_set_static_sym_untag(entry)->sym;
316 }
317 else {
319 if (!DYNAMIC_SYM_P(entry)) rb_bug("not sym");
320
321 return entry;
322 }
323}
324
325static VALUE
326sym_find_or_insert_dynamic_symbol(rb_symbols_t *symbols, const VALUE str)
327{
328 struct sym_set_static_sym_entry static_sym = {
329 .str = str
330 };
331 return sym_set_entry_to_sym(
332 rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)true)
333 );
334}
335
336static VALUE
337sym_find_or_insert_static_symbol(rb_symbols_t *symbols, const VALUE str)
338{
339 struct sym_set_static_sym_entry static_sym = {
340 .str = str
341 };
342 return sym_set_entry_to_sym(
343 rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)false)
344 );
345}
346
347static VALUE
348sym_find_or_insert_static_symbol_id(rb_symbols_t *symbols, const VALUE str, ID id)
349{
350 struct sym_set_static_sym_entry static_sym = {
351 .sym = STATIC_ID2SYM(id),
352 .str = str,
353 };
354 return sym_set_entry_to_sym(
355 rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)false)
356 );
357}
358
359void
360Init_sym(void)
361{
362 rb_symbols_t *symbols = &ruby_global_symbols;
363
364 symbols->sym_set = rb_concurrent_set_new(&sym_set_funcs, 1024);
365 symbols->ids = rb_ary_hidden_new(0);
366
367 Init_op_tbl();
368 Init_id();
369}
370
371void
372rb_sym_global_symbols_mark(void)
373{
374 rb_symbols_t *symbols = &ruby_global_symbols;
375
376 rb_gc_mark_movable(symbols->sym_set);
377 rb_gc_mark_movable(symbols->ids);
378}
379
380void
381rb_sym_global_symbols_update_references(void)
382{
383 rb_symbols_t *symbols = &ruby_global_symbols;
384
385 symbols->sym_set = rb_gc_location(symbols->sym_set);
386 symbols->ids = rb_gc_location(symbols->ids);
387}
388
389static int
390rb_free_global_symbol_table_i(VALUE *sym_ptr, void *data)
391{
392 sym_set_free(*sym_ptr);
393
394 return ST_DELETE;
395}
396
397void
398rb_free_global_symbol_table(void)
399{
400 rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_free_global_symbol_table_i, NULL);
401}
402
403WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
404WARN_UNUSED_RESULT(static VALUE lookup_id_str(ID id));
405
406ID
407rb_id_attrset(ID id)
408{
409 int scope;
410
411 if (!is_notop_id(id)) {
412 switch (id) {
413 case tAREF: case tASET:
414 return tASET; /* only exception */
415 }
416 rb_name_error(id, "cannot make operator ID :%"PRIsVALUE" attrset",
417 rb_id2str(id));
418 }
419 else {
420 scope = id_type(id);
421 switch (scope) {
422 case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL:
423 case ID_CONST: case ID_CLASS: case ID_INTERNAL:
424 break;
425 case ID_ATTRSET:
426 return id;
427 default:
428 {
429 VALUE str = lookup_id_str(id);
430 if (str != 0) {
431 rb_name_error(id, "cannot make unknown type ID %d:%"PRIsVALUE" attrset",
432 scope, str);
433 }
434 else {
435 rb_name_error_str(Qnil, "cannot make unknown type anonymous ID %d:%"PRIxVALUE" attrset",
436 scope, (VALUE)id);
437 }
438 }
439 }
440 }
441
442 bool error = false;
443 /* make new symbol and ID */
444 VALUE str = lookup_id_str(id);
445 if (str) {
446 str = rb_str_dup(str);
447 rb_str_cat(str, "=", 1);
448 if (sym_check_asciionly(str, false)) {
449 rb_enc_associate(str, rb_usascii_encoding());
450 }
451
452 VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
453 id = rb_sym2id(sym);
454 }
455 else {
456 error = true;
457 }
458
459 if (error) {
460 RBIMPL_ATTR_NONSTRING_ARRAY() static const char id_types[][8] = {
461 "local",
462 "instance",
463 "invalid",
464 "global",
465 "attrset",
466 "const",
467 "class",
468 "internal",
469 };
470 rb_name_error(id, "cannot make anonymous %.*s ID %"PRIxVALUE" attrset",
471 (int)sizeof(id_types[0]), id_types[scope], (VALUE)id);
472 }
473
474 return id;
475}
476
477static int
478is_special_global_name(const char *m, const char *e, rb_encoding *enc)
479{
480 int mb = 0;
481
482 if (m >= e) return 0;
483 if (is_global_name_punct(*m)) {
484 ++m;
485 }
486 else if (*m == '-') {
487 if (++m >= e) return 0;
488 if (is_identchar(m, e, enc)) {
489 if (!ISASCII(*m)) mb = 1;
490 m += rb_enc_mbclen(m, e, enc);
491 }
492 }
493 else {
494 if (!ISDIGIT(*m)) return 0;
495 do {
496 if (!ISASCII(*m)) mb = 1;
497 ++m;
498 } while (m < e && ISDIGIT(*m));
499 }
500 return m == e ? mb + 1 : 0;
501}
502
503int
504rb_symname_p(const char *name)
505{
506 return rb_enc_symname_p(name, rb_ascii8bit_encoding());
507}
508
509int
510rb_enc_symname_p(const char *name, rb_encoding *enc)
511{
512 return rb_enc_symname2_p(name, strlen(name), enc);
513}
514
515static int
516rb_sym_constant_char_p(const char *name, long nlen, rb_encoding *enc)
517{
518 int c, len;
519 const char *end = name + nlen;
520
521 if (nlen < 1) return FALSE;
522 if (ISASCII(*name)) return ISUPPER(*name);
523 c = rb_enc_precise_mbclen(name, end, enc);
524 if (!MBCLEN_CHARFOUND_P(c)) return FALSE;
526 c = rb_enc_mbc_to_codepoint(name, end, enc);
527 if (rb_enc_isupper(c, enc)) return TRUE;
528 if (rb_enc_islower(c, enc)) return FALSE;
529 if (ONIGENC_IS_UNICODE(enc)) {
530 static int ctype_titlecase = 0;
531 if (!ctype_titlecase) {
532 static const UChar cname[] = "titlecaseletter";
533 static const UChar *const end = cname + sizeof(cname) - 1;
534 ctype_titlecase = ONIGENC_PROPERTY_NAME_TO_CTYPE(enc, cname, end);
535 }
536 if (rb_enc_isctype(c, ctype_titlecase, enc)) return TRUE;
537 }
538 else {
539 /* fallback to case-folding */
540 OnigUChar fold[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
541 const OnigUChar *beg = (const OnigUChar *)name;
542 int r = enc->mbc_case_fold(ONIGENC_CASE_FOLD,
543 &beg, (const OnigUChar *)end,
544 fold, enc);
545 if (r > 0 && (r != len || memcmp(fold, name, r)))
546 return TRUE;
547 }
548 return FALSE;
549}
550
552 const enum { invalid, stophere, needmore, } kind;
553 const enum ruby_id_types type;
554 const long nread;
555};
556
557#define t struct enc_synmane_type_leading_chars_tag
558
560enc_synmane_type_leading_chars(const char *name, long len, rb_encoding *enc, int allowed_attrset)
561{
562 const char *m = name;
563 const char *e = m + len;
564
565 if (! rb_enc_asciicompat(enc)) {
566 return (t) { invalid, 0, 0, };
567 }
568 else if (! m) {
569 return (t) { invalid, 0, 0, };
570 }
571 else if ( len <= 0 ) {
572 return (t) { invalid, 0, 0, };
573 }
574 switch (*m) {
575 case '\0':
576 return (t) { invalid, 0, 0, };
577
578 case '$':
579 if (is_special_global_name(++m, e, enc)) {
580 return (t) { stophere, ID_GLOBAL, len, };
581 }
582 else {
583 return (t) { needmore, ID_GLOBAL, 1, };
584 }
585
586 case '@':
587 switch (*++m) {
588 default: return (t) { needmore, ID_INSTANCE, 1, };
589 case '@': return (t) { needmore, ID_CLASS, 2, };
590 }
591
592 case '<':
593 switch (*++m) {
594 default: return (t) { stophere, ID_INTERNAL, 1, };
595 case '<': return (t) { stophere, ID_INTERNAL, 2, };
596 case '=':
597 switch (*++m) {
598 default: return (t) { stophere, ID_INTERNAL, 2, };
599 case '>': return (t) { stophere, ID_INTERNAL, 3, };
600 }
601 }
602
603 case '>':
604 switch (*++m) {
605 default: return (t) { stophere, ID_INTERNAL, 1, };
606 case '>': case '=': return (t) { stophere, ID_INTERNAL, 2, };
607 }
608
609 case '=':
610 switch (*++m) {
611 default: return (t) { invalid, 0, 1, };
612 case '~': return (t) { stophere, ID_INTERNAL, 2, };
613 case '=':
614 switch (*++m) {
615 default: return (t) { stophere, ID_INTERNAL, 2, };
616 case '=': return (t) { stophere, ID_INTERNAL, 3, };
617 }
618 }
619
620 case '*':
621 switch (*++m) {
622 default: return (t) { stophere, ID_INTERNAL, 1, };
623 case '*': return (t) { stophere, ID_INTERNAL, 2, };
624 }
625
626 case '+': case '-':
627 switch (*++m) {
628 default: return (t) { stophere, ID_INTERNAL, 1, };
629 case '@': return (t) { stophere, ID_INTERNAL, 2, };
630 }
631
632 case '|': case '^': case '&': case '/': case '%': case '~': case '`':
633 return (t) { stophere, ID_INTERNAL, 1, };
634
635 case '[':
636 switch (*++m) {
637 default: return (t) { needmore, ID_INTERNAL, 0, };
638 case ']':
639 switch (*++m) {
640 default: return (t) { stophere, ID_INTERNAL, 2, };
641 case '=': return (t) { stophere, ID_INTERNAL, 3, };
642 }
643 }
644
645 case '!':
646 switch (*++m) {
647 case '=': case '~': return (t) { stophere, ID_INTERNAL, 2, };
648 default:
649 if (allowed_attrset & (1U << ID_INTERNAL)) {
650 return (t) { needmore, ID_INTERNAL, 1, };
651 }
652 else {
653 return (t) { stophere, ID_INTERNAL, 1, };
654 }
655 }
656
657 default:
658 if (rb_sym_constant_char_p(name, len, enc)) {
659 return (t) { needmore, ID_CONST, 0, };
660 }
661 else {
662 return (t) { needmore, ID_LOCAL, 0, };
663 }
664 }
665}
666#undef t
667
668int
669rb_enc_symname_type(const char *name, long len, rb_encoding *enc, unsigned int allowed_attrset)
670{
672 enc_synmane_type_leading_chars(name, len, enc, allowed_attrset);
673 const char *m = name + f.nread;
674 const char *e = name + len;
675 int type = (int)f.type;
676
677 switch (f.kind) {
678 case invalid: return -1;
679 case stophere: break;
680 case needmore:
681
682 if (m >= e || (*m != '_' && !ISALPHA(*m) && ISASCII(*m))) {
683 if (len > 1 && *(e-1) == '=') {
684 type = rb_enc_symname_type(name, len-1, enc, allowed_attrset);
685 if (allowed_attrset & (1U << type)) return ID_ATTRSET;
686 }
687 return -1;
688 }
689 while (m < e && is_identchar(m, e, enc)) m += rb_enc_mbclen(m, e, enc);
690 if (m >= e) break;
691 switch (*m) {
692 case '!': case '?':
693 if (type == ID_GLOBAL || type == ID_CLASS || type == ID_INSTANCE) return -1;
694 type = ID_INTERNAL;
695 ++m;
696 if (m + 1 < e || *m != '=') break;
697 /* fall through */
698 case '=':
699 if (!(allowed_attrset & (1U << type))) return -1;
700 type = ID_ATTRSET;
701 ++m;
702 break;
703 }
704 }
705
706 return m == e ? type : -1;
707}
708
709int
710rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
711{
712 return rb_enc_symname_type(name, len, enc, IDSET_ATTRSET_FOR_SYNTAX) != -1;
713}
714
715static VALUE
716get_id_serial_entry(rb_id_serial_t num, ID id, const enum id_entry_type t)
717{
718 VALUE result = 0;
719
720 GLOBAL_SYMBOLS_LOCKING(symbols) {
721 if (num && num < RUBY_ATOMIC_LOAD(symbols->next_id)) {
722 size_t idx = num / ID_ENTRY_UNIT;
723 VALUE ids = symbols->ids;
724 VALUE ary;
725 if (idx < (size_t)RARRAY_LEN(ids) && !NIL_P(ary = rb_ary_entry(ids, (long)idx))) {
726 long pos = (long)(num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE;
727 result = rb_ary_entry(ary, pos + t);
728
729 if (NIL_P(result)) {
730 result = 0;
731 }
732 else if (CHECK_ID_SERIAL) {
733 if (id) {
734 VALUE sym = result;
735 if (t != ID_ENTRY_SYM)
736 sym = rb_ary_entry(ary, pos + ID_ENTRY_SYM);
737 if (STATIC_SYM_P(sym)) {
738 if (STATIC_SYM2ID(sym) != id) result = 0;
739 }
740 else {
741 if (RSYMBOL(sym)->id != id) result = 0;
742 }
743 }
744 }
745 }
746 }
747 }
748
749 if (result) {
750 switch (t) {
751 case ID_ENTRY_STR:
753 break;
754 case ID_ENTRY_SYM:
756 break;
757 default:
758 break;
759 }
760 }
761
762 return result;
763}
764
765static VALUE
766get_id_entry(ID id, const enum id_entry_type t)
767{
768 return get_id_serial_entry(rb_id_to_serial(id), id, t);
769}
770
771int
772rb_static_id_valid_p(ID id)
773{
774 return STATIC_ID2SYM(id) == get_id_entry(id, ID_ENTRY_SYM);
775}
776
777static inline ID
778rb_id_serial_to_id(rb_id_serial_t num)
779{
780 if (is_notop_id((ID)num)) {
781 VALUE sym = get_id_serial_entry(num, 0, ID_ENTRY_SYM);
782 if (sym) return SYM2ID(sym);
783 return ((ID)num << ID_SCOPE_SHIFT) | ID_INTERNAL | ID_STATIC_SYM;
784 }
785 else {
786 return (ID)num;
787 }
788}
789
790static ID
791register_static_symid(ID id, const char *name, long len, rb_encoding *enc)
792{
793 VALUE str = rb_enc_str_new(name, len, enc);
794 OBJ_FREEZE(str);
795 str = rb_fstring(str);
796
797 RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(str));
798
799 sym_find_or_insert_static_symbol_id(&ruby_global_symbols, str, id);
800
801 return id;
802}
803
804static VALUE
805sym_find(VALUE str)
806{
807 VALUE sym;
808
809 struct sym_set_static_sym_entry static_sym = {
810 .str = str
811 };
812 sym = rb_concurrent_set_find(&ruby_global_symbols.sym_set, sym_set_static_sym_tag(&static_sym));
813
814 if (sym) {
815 return sym_set_entry_to_sym(sym);
816 }
817 else {
818 return 0;
819 }
820}
821
822static ID
823lookup_str_id(VALUE str)
824{
825 VALUE sym = sym_find(str);
826
827 if (sym == 0) {
828 return (ID)0;
829 }
830
831 if (STATIC_SYM_P(sym)) {
832 return STATIC_SYM2ID(sym);
833 }
834 else if (DYNAMIC_SYM_P(sym)) {
835 ID id = RSYMBOL(sym)->id;
836 if (id & ~ID_SCOPE_MASK) return id;
837 }
838 else {
839 rb_bug("non-symbol object %s:%"PRIxVALUE" for %"PRIsVALUE" in symbol table",
840 rb_builtin_class_name(sym), sym, str);
841 }
842
843 return (ID)0;
844}
845
846static VALUE
847lookup_id_str(ID id)
848{
849 return get_id_entry(id, ID_ENTRY_STR);
850}
851
852ID
853rb_intern3(const char *name, long len, rb_encoding *enc)
854{
855 struct RString fake_str;
856 VALUE str = rb_setup_fake_str(&fake_str, name, len, enc);
857 OBJ_FREEZE(str);
858
859 VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
860 return rb_sym2id(sym);
861}
862
863ID
864rb_intern2(const char *name, long len)
865{
866 return rb_intern3(name, len, rb_usascii_encoding());
867}
868
869#undef rb_intern
870ID
871rb_intern(const char *name)
872{
873 return rb_intern2(name, strlen(name));
874}
875
876ID
877rb_intern_str(VALUE str)
878{
879 VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
880 return SYM2ID(sym);
881}
882
883bool
884rb_obj_is_symbol_table(VALUE obj)
885{
886 return obj == ruby_global_symbols.sym_set;
887}
888
890 int (*callback)(VALUE *key, void *data);
891 void *data;
892};
893
894static int
895rb_sym_global_symbol_table_foreach_weak_reference_i(VALUE *key, void *d)
896{
898 VALUE sym = *key;
899
900 if (sym_set_sym_static_p(sym)) {
901 struct sym_set_static_sym_entry *static_sym = sym_set_static_sym_untag(sym);
902
903 return data->callback(&static_sym->str, data->data);
904 }
905 else {
906 return data->callback(key, data->data);
907 }
908}
909
910void
911rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data)
912{
913 if (!ruby_global_symbols.sym_set) return;
914
916 .callback = callback,
917 .data = data,
918 };
919
920 rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_sym_global_symbol_table_foreach_weak_reference_i, &foreach_data);
921}
922
923void
924rb_gc_free_dsymbol(VALUE sym)
925{
926 VALUE str = RSYMBOL(sym)->fstr;
927
928 if (str) {
929 rb_concurrent_set_delete_by_identity(ruby_global_symbols.sym_set, sym);
930
931 RSYMBOL(sym)->fstr = 0;
932 }
933}
934
935/*
936 * call-seq:
937 * str.intern -> symbol
938 * str.to_sym -> symbol
939 *
940 * Returns the +Symbol+ corresponding to <i>str</i>, creating the
941 * symbol if it did not previously exist. See Symbol#id2name.
942 *
943 * "Koala".intern #=> :Koala
944 * s = 'cat'.to_sym #=> :cat
945 * s == :cat #=> true
946 * s = '@cat'.to_sym #=> :@cat
947 * s == :@cat #=> true
948 *
949 * This can also be used to create symbols that cannot be represented using the
950 * <code>:xxx</code> notation.
951 *
952 * 'cat and dog'.to_sym #=> :"cat and dog"
953 */
954
955VALUE
957{
958 return sym_find_or_insert_dynamic_symbol(&ruby_global_symbols, str);
959}
960
961ID
963{
964 ID id = 0;
965 if (STATIC_SYM_P(sym)) {
966 id = STATIC_SYM2ID(sym);
967 }
968 else if (DYNAMIC_SYM_P(sym)) {
969 GLOBAL_SYMBOLS_LOCKING(symbols) {
970 RUBY_ASSERT(!rb_objspace_garbage_object_p(sym));
971 id = RSYMBOL(sym)->id;
972
973 if (UNLIKELY(!(id & ~ID_SCOPE_MASK))) {
974 VALUE fstr = RSYMBOL(sym)->fstr;
975 ID num = next_id_base();
976
977 RSYMBOL(sym)->id = id |= num;
978 /* make it permanent object */
979
980 set_id_entry(symbols, rb_id_to_serial(num), fstr, sym);
981 }
982 }
983 }
984 else {
985 rb_raise(rb_eTypeError, "wrong argument type %s (expected Symbol)",
986 rb_builtin_class_name(sym));
987 }
988 return id;
989}
990
991#undef rb_id2sym
992VALUE
994{
995 if (!DYNAMIC_ID_P(x)) return STATIC_ID2SYM(x);
996 return get_id_entry(x, ID_ENTRY_SYM);
997}
998
999/*
1000 * call-seq:
1001 * name -> string
1002 *
1003 * Returns a frozen string representation of +self+ (not including the leading colon):
1004 *
1005 * :foo.name # => "foo"
1006 * :foo.name.frozen? # => true
1007 *
1008 * Related: Symbol#to_s, Symbol#inspect.
1009 */
1010
1011VALUE
1013{
1014 VALUE str;
1015 if (DYNAMIC_SYM_P(sym)) {
1016 str = RSYMBOL(sym)->fstr;
1018 }
1019 else {
1020 str = rb_id2str(STATIC_SYM2ID(sym));
1021 if (str) RUBY_ASSERT_BUILTIN_TYPE(str, T_STRING);
1022 }
1023
1024 return str;
1025}
1026
1027VALUE
1028rb_id2str(ID id)
1029{
1030 return lookup_id_str(id);
1031}
1032
1033const char *
1034rb_id2name(ID id)
1035{
1036 VALUE str = rb_id2str(id);
1037
1038 if (!str) return 0;
1039 return RSTRING_PTR(str);
1040}
1041
1042ID
1043rb_make_internal_id(void)
1044{
1045 return next_id_base() | ID_INTERNAL | ID_STATIC_SYM;
1046}
1047
1048ID
1049rb_make_temporary_id(size_t n)
1050{
1051 const ID max_id = RB_ID_SERIAL_MAX & ~0xffff;
1052 const ID id = max_id - (ID)n;
1053 if (id < RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id)) {
1054 rb_raise(rb_eRuntimeError, "too big to make temporary ID: %" PRIdSIZE, n);
1055 }
1056 return (id << ID_SCOPE_SHIFT) | ID_STATIC_SYM | ID_INTERNAL;
1057}
1058
1059static int
1060symbols_i(VALUE *key, void *data)
1061{
1062 VALUE ary = (VALUE)data;
1063 VALUE sym = (VALUE)*key;
1064
1065 if (sym_set_sym_static_p(sym)) {
1066 rb_ary_push(ary, sym_set_static_sym_untag(sym)->sym);
1067 }
1068 else if (rb_objspace_garbage_object_p(sym)) {
1069 return ST_DELETE;
1070 }
1071 else {
1072 rb_ary_push(ary, sym);
1073 }
1074
1075 return ST_CONTINUE;
1076}
1077
1078VALUE
1080{
1081 VALUE ary;
1082
1083 GLOBAL_SYMBOLS_LOCKING(symbols) {
1084 ary = rb_ary_new2(rb_concurrent_set_size(symbols->sym_set));
1085 rb_concurrent_set_foreach_with_replace(symbols->sym_set, symbols_i, (void *)ary);
1086 }
1087
1088 return ary;
1089}
1090
1091size_t
1092rb_sym_immortal_count(void)
1093{
1094 return (size_t)(RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id) - 1);
1095}
1096
1097int
1099{
1100 return is_const_id(id);
1101}
1102
1103int
1105{
1106 return is_class_id(id);
1107}
1108
1109int
1111{
1112 return is_global_id(id);
1113}
1114
1115int
1117{
1118 return is_instance_id(id);
1119}
1120
1121int
1123{
1124 return is_attrset_id(id);
1125}
1126
1127int
1129{
1130 return is_local_id(id);
1131}
1132
1133int
1135{
1136 return is_internal_id(id);
1137}
1138
1139int
1140rb_is_const_sym(VALUE sym)
1141{
1142 return is_const_sym(sym);
1143}
1144
1145int
1146rb_is_attrset_sym(VALUE sym)
1147{
1148 return is_attrset_sym(sym);
1149}
1150
1151ID
1152rb_check_id(volatile VALUE *namep)
1153{
1154 VALUE tmp;
1155 VALUE name = *namep;
1156
1157 if (STATIC_SYM_P(name)) {
1158 return STATIC_SYM2ID(name);
1159 }
1160 else if (DYNAMIC_SYM_P(name)) {
1161 if (SYMBOL_PINNED_P(name)) {
1162 return RSYMBOL(name)->id;
1163 }
1164 else {
1165 *namep = RSYMBOL(name)->fstr;
1166 return 0;
1167 }
1168 }
1169 else if (!RB_TYPE_P(name, T_STRING)) {
1170 tmp = rb_check_string_type(name);
1171 if (NIL_P(tmp)) {
1172 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
1173 name);
1174 }
1175 name = tmp;
1176 *namep = name;
1177 }
1178
1179 sym_check_asciionly(name, false);
1180
1181 return lookup_str_id(name);
1182}
1183
1184// Used by yjit for handling .send without throwing exceptions
1185ID
1186rb_get_symbol_id(VALUE name)
1187{
1188 if (STATIC_SYM_P(name)) {
1189 return STATIC_SYM2ID(name);
1190 }
1191 else if (DYNAMIC_SYM_P(name)) {
1192 if (SYMBOL_PINNED_P(name)) {
1193 return RSYMBOL(name)->id;
1194 }
1195 else {
1196 return 0;
1197 }
1198 }
1199 else if (RB_TYPE_P(name, T_STRING)) {
1200 return lookup_str_id(name);
1201 }
1202 else {
1203 return 0;
1204 }
1205}
1206
1207
1208VALUE
1209rb_check_symbol(volatile VALUE *namep)
1210{
1211 VALUE sym;
1212 VALUE tmp;
1213 VALUE name = *namep;
1214
1215 if (STATIC_SYM_P(name)) {
1216 return name;
1217 }
1218 else if (DYNAMIC_SYM_P(name)) {
1219 RUBY_ASSERT(!rb_objspace_garbage_object_p(name));
1220 return name;
1221 }
1222 else if (!RB_TYPE_P(name, T_STRING)) {
1223 tmp = rb_check_string_type(name);
1224 if (NIL_P(tmp)) {
1225 rb_raise(rb_eTypeError, "%+"PRIsVALUE" is not a symbol nor a string",
1226 name);
1227 }
1228 name = tmp;
1229 *namep = name;
1230 }
1231
1232 sym_check_asciionly(name, false);
1233
1234 if ((sym = sym_find(name)) != 0) {
1235 return sym;
1236 }
1237
1238 return Qnil;
1239}
1240
1241ID
1242rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
1243{
1244 struct RString fake_str;
1245 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1246
1247 sym_check_asciionly(name, true);
1248
1249 return lookup_str_id(name);
1250}
1251
1252VALUE
1253rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
1254{
1255 VALUE sym;
1256 struct RString fake_str;
1257 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1258
1259 sym_check_asciionly(name, true);
1260
1261 if ((sym = sym_find(name)) != 0) {
1262 return sym;
1263 }
1264
1265 return Qnil;
1266}
1267
1268#undef rb_sym_intern_ascii_cstr
1269#ifdef __clang__
1270NOINLINE(VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc));
1271#else
1272FUNC_MINIMIZED(VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc));
1273FUNC_MINIMIZED(VALUE rb_sym_intern_ascii(const char *ptr, long len));
1274FUNC_MINIMIZED(VALUE rb_sym_intern_ascii_cstr(const char *ptr));
1275#endif
1276
1277VALUE
1278rb_sym_intern(const char *ptr, long len, rb_encoding *enc)
1279{
1280 struct RString fake_str;
1281 const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
1282 return rb_str_intern(name);
1283}
1284
1285VALUE
1286rb_sym_intern_ascii(const char *ptr, long len)
1287{
1288 return rb_sym_intern(ptr, len, rb_usascii_encoding());
1289}
1290
1291VALUE
1292rb_sym_intern_ascii_cstr(const char *ptr)
1293{
1294 return rb_sym_intern_ascii(ptr, strlen(ptr));
1295}
1296
1297VALUE
1298rb_to_symbol_type(VALUE obj)
1299{
1300 return rb_convert_type_with_id(obj, T_SYMBOL, "Symbol", idTo_sym);
1301}
1302
1303int
1304rb_is_const_name(VALUE name)
1305{
1306 return rb_str_symname_type(name, 0) == ID_CONST;
1307}
1308
1309int
1310rb_is_class_name(VALUE name)
1311{
1312 return rb_str_symname_type(name, 0) == ID_CLASS;
1313}
1314
1315int
1316rb_is_instance_name(VALUE name)
1317{
1318 return rb_str_symname_type(name, 0) == ID_INSTANCE;
1319}
1320
1321int
1322rb_is_local_name(VALUE name)
1323{
1324 return rb_str_symname_type(name, 0) == ID_LOCAL;
1325}
1326
1327#include "id_table.c"
1328#include "symbol.rbinc"
#define RUBY_ASSERT_BUILTIN_TYPE(obj, type)
A variant of RUBY_ASSERT that asserts when either RUBY_DEBUG or built-in type of obj is type.
Definition assert.h:291
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
#define RUBY_ATOMIC_FETCH_ADD(var, val)
Atomically replaces the value pointed by var with the result of addition of val to the old value of v...
Definition atomic.h:96
#define RUBY_ATOMIC_LOAD(var)
Atomic load.
Definition atomic.h:153
static bool rb_enc_isupper(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isupper(), except it additionally takes an encoding.
Definition ctype.h:124
static bool rb_enc_isctype(OnigCodePoint c, OnigCtype t, rb_encoding *enc)
Queries if the passed code point is of passed character type in the passed encoding.
Definition ctype.h:63
static bool rb_enc_islower(OnigCodePoint c, rb_encoding *enc)
Identical to rb_islower(), except it additionally takes an encoding.
Definition ctype.h:110
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define ISUPPER
Old name of rb_isupper.
Definition ctype.h:89
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define ISDIGIT
Old name of rb_isdigit.
Definition ctype.h:93
#define STATIC_SYM_P
Old name of RB_STATIC_SYM_P.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define ISALPHA
Old name of rb_isalpha.
Definition ctype.h:92
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define DYNAMIC_SYM_P
Old name of RB_DYNAMIC_SYM_P.
Definition value_type.h:86
#define Qnil
Old name of RUBY_Qnil.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define NIL_P
Old name of RB_NIL_P.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
Definition fl_type.h:59
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define IMMEDIATE_P
Old name of RB_IMMEDIATE_P.
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define ISALNUM
Old name of rb_isalnum.
Definition ctype.h:91
void rb_name_error(ID id, const char *fmt,...)
Raises an instance of rb_eNameError.
Definition error.c:2344
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
void rb_name_error_str(VALUE str, const char *fmt,...)
Identical to rb_name_error(), except it takes a VALUE instead of ID.
Definition error.c:2359
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
VALUE rb_eEncodingError
EncodingError exception.
Definition error.c:1436
VALUE rb_cSymbol
Symbol class.
Definition string.c:84
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
Encoding relates APIs.
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:932
int rb_enc_symname_p(const char *str, rb_encoding *enc)
Identical to rb_symname_p(), except it additionally takes an encoding.
Definition symbol.c:510
VALUE rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id_cstr(), except for the return type.
Definition symbol.c:1253
int rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
Identical to rb_enc_symname_p(), except it additionally takes the passed string's length.
Definition symbol.c:710
ID rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id(), except it takes a pointer to a memory region instead of Ruby's string.
Definition symbol.c:1242
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_sym_all_symbols(void)
Collects every single bits of symbols that have ever interned in the entire history of the current pr...
Definition symbol.c:1079
int rb_is_global_id(ID id)
Classifies the given ID, then sees if it is a global variable.
Definition symbol.c:1110
int rb_is_instance_id(ID id)
Classifies the given ID, then sees if it is an instance variable.
Definition symbol.c:1116
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1098
int rb_is_junk_id(ID)
Classifies the given ID, then sees if it is a junk ID.
Definition symbol.c:1134
int rb_symname_p(const char *str)
Sees if the passed C string constructs a valid syntactic symbol.
Definition symbol.c:504
int rb_is_class_id(ID id)
Classifies the given ID, then sees if it is a class variable.
Definition symbol.c:1104
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1122
int rb_is_local_id(ID id)
Classifies the given ID, then sees if it is a local variable.
Definition symbol.c:1128
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4121
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1956
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4107
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3525
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2910
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
Definition symbol.c:956
VALUE rb_check_symbol(volatile VALUE *namep)
Identical to rb_check_id(), except it returns an instance of rb_cSymbol instead.
Definition symbol.c:1209
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:993
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1152
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1012
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:962
int len
Length of the buffer.
Definition io.h:8
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
VALUE type(ANYARGS)
ANYARGS-ed function type.
Defines RBIMPL_ATTR_NONSTRING.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
Ruby's String.
Definition rstring.h:196
char * ptr
Pointer to the contents of the string.
Definition rstring.h:222
Definition symbol.c:104
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376