Ruby 3.5.0dev (2025-08-07 revision fccd96cc6c3cc9f500dc87ae9be65aaa212b02fa)
struct.h
1#ifndef INTERNAL_STRUCT_H /*-*-C-*-vi:se ft=c:*/
2#define INTERNAL_STRUCT_H
11#include "ruby/internal/stdbool.h" /* for bool */
12#include "ruby/ruby.h" /* for struct RBasic */
13
14/* Flags of RStruct
15 *
16 * 1-7: RSTRUCT_EMBED_LEN
17 * If non-zero, the struct is embedded (its contents follow the
18 * header, rather than being on a separately allocated buffer) and
19 * these bits are the length of the Struct.
20 * 8: RSTRUCT_GEN_FIELDS
21 * The struct is embedded and has no space left to store the
22 * IMEMO/fields reference. Any ivar this struct may have will be in
23 * the generic_fields_tbl. This flag doesn't imply the struct has
24 * ivars.
25 */
26enum {
27 RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 |
29 RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1),
30 RSTRUCT_GEN_FIELDS = RUBY_FL_USER8,
31};
32
33struct RStruct {
34 struct RBasic basic;
35 union {
36 struct {
37 long len;
38 const VALUE *ptr;
39 VALUE fields_obj;
40 } heap;
41 /* This is a length 1 array because:
42 * 1. GCC has a bug that does not optimize C flexible array members
43 * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
44 * 2. Zero length arrays are not supported by all compilers
45 */
46 const VALUE ary[1];
47 } as;
48};
49
50#define RSTRUCT(obj) ((struct RStruct *)(obj))
51
52#ifdef RSTRUCT_LEN
53# undef RSTRUCT_LEN
54#endif
55
56#ifdef RSTRUCT_PTR
57# undef RSTRUCT_PTR
58#endif
59
60#ifdef RSTRUCT_SET
61# undef RSTRUCT_SET
62#endif
63
64#ifdef RSTRUCT_GET
65# undef RSTRUCT_GET
66#endif
67
68#define RSTRUCT_LEN internal_RSTRUCT_LEN
69#define RSTRUCT_SET internal_RSTRUCT_SET
70#define RSTRUCT_GET internal_RSTRUCT_GET
71
72/* struct.c */
73VALUE rb_struct_init_copy(VALUE copy, VALUE s);
74VALUE rb_struct_lookup(VALUE s, VALUE idx);
75VALUE rb_struct_s_keyword_init(VALUE klass);
76static inline long RSTRUCT_EMBED_LEN(VALUE st);
77static inline long RSTRUCT_LEN(VALUE st);
78static inline int RSTRUCT_LENINT(VALUE st);
79static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st);
80static inline void RSTRUCT_SET(VALUE st, long k, VALUE v);
81static inline VALUE RSTRUCT_GET(VALUE st, long k);
82
83static inline long
84RSTRUCT_EMBED_LEN(VALUE st)
85{
86 long ret = FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK);
87 ret >>= RSTRUCT_EMBED_LEN_SHIFT;
88 return ret;
89}
90
91static inline long
92RSTRUCT_LEN(VALUE st)
93{
94 if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
95 return RSTRUCT_EMBED_LEN(st);
96 }
97 else {
98 return RSTRUCT(st)->as.heap.len;
99 }
100}
101
102static inline int
103RSTRUCT_LENINT(VALUE st)
104{
105 return rb_long2int(RSTRUCT_LEN(st));
106}
107
108static inline const VALUE *
109RSTRUCT_CONST_PTR(VALUE st)
110{
111 const struct RStruct *p = RSTRUCT(st);
112
113 if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
114 return p->as.ary;
115 }
116 else {
117 return p->as.heap.ptr;
118 }
119}
120
121static inline void
122RSTRUCT_SET(VALUE st, long k, VALUE v)
123{
124 RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v);
125}
126
127static inline VALUE
128RSTRUCT_GET(VALUE st, long k)
129{
130 return RSTRUCT_CONST_PTR(st)[k];
131}
132
133static inline VALUE
134RSTRUCT_FIELDS_OBJ(VALUE st)
135{
136 const long embed_len = RSTRUCT_EMBED_LEN(st);
137 VALUE fields_obj;
138 if (embed_len) {
139 RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
140 fields_obj = RSTRUCT_GET(st, embed_len);
141 }
142 else {
143 fields_obj = RSTRUCT(st)->as.heap.fields_obj;
144 }
145 return fields_obj;
146}
147
148static inline void
149RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj)
150{
151 const long embed_len = RSTRUCT_EMBED_LEN(st);
152 if (embed_len) {
153 RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
154 RSTRUCT_SET(st, embed_len, fields_obj);
155 }
156 else {
157 RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj);
158 }
159}
160#endif /* INTERNAL_STRUCT_H */
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
@ RUBY_FL_USHIFT
Number of bits in ruby_fl_type that are not open to users.
Definition fl_type.h:158
@ RUBY_FL_USER8
User-defined flag.
Definition fl_type.h:332
@ RUBY_FL_USER5
User-defined flag.
Definition fl_type.h:329
@ RUBY_FL_USER3
User-defined flag.
Definition fl_type.h:327
@ RUBY_FL_USER7
User-defined flag.
Definition fl_type.h:331
@ RUBY_FL_USER6
User-defined flag.
Definition fl_type.h:330
@ RUBY_FL_USER2
User-defined flag.
Definition fl_type.h:326
@ RUBY_FL_USER4
User-defined flag.
Definition fl_type.h:328
@ RUBY_FL_USER1
User-defined flag.
Definition fl_type.h:325
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
Definition fl_type.h:131
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
int len
Length of the buffer.
Definition io.h:8
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
C99 shim for <stdbool.h>
Ruby object's base components.
Definition rbasic.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40