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