Ruby: struct.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

struct.c
Go to the documentation of this file.
1/**********************************************************************
2
3 struct.c -
4
5 $Author$
6 created at: Tue Mar 22 18:44:30 JST 1995
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "id.h"
13#include "internal.h"
14#include "internal/class.h"
15#include "internal/error.h"
16#include "internal/hash.h"
17#include "internal/object.h"
18#include "internal/proc.h"
19#include "internal/struct.h"
20#include "internal/symbol.h"
21#include "transient_heap.h"
22#include "vm_core.h"
23#include "builtin.h"
24
25/* only for struct[:field] access */
26enum {
27 AREF_HASH_UNIT = 5,
28 AREF_HASH_THRESHOLD = 10
29};
30
31const rb_iseq_t *rb_method_for_self_aref(VALUE name, VALUE arg, const struct rb_builtin_function *func);
32const rb_iseq_t *rb_method_for_self_aset(VALUE name, VALUE arg, const struct rb_builtin_function *func);
33
34 VALUE rb_cStruct;
35static ID id_members, id_back_members, id_keyword_init;
36
37static VALUE struct_alloc(VALUE);
38
39static inline VALUE
40struct_ivar_get(VALUE c, ID id)
41{
42 VALUE orig = c;
43 VALUE ivar = rb_attr_get(c, id);
44
45 if (!NIL_P(ivar))
46 return ivar;
47
48 for (;;) {
49 c = RCLASS_SUPER(c);
50 if (c == 0 || c == rb_cStruct)
51 return Qnil;
52 ivar = rb_attr_get(c, id);
53 if (!NIL_P(ivar)) {
54 return rb_ivar_set(orig, id, ivar);
55 }
56 }
57}
58
59 VALUE
60 rb_struct_s_keyword_init(VALUE klass)
61{
62 return struct_ivar_get(klass, id_keyword_init);
63}
64
65 VALUE
66 rb_struct_s_members(VALUE klass)
67{
68 VALUE members = struct_ivar_get(klass, id_members);
69
70 if (NIL_P(members)) {
71 rb_raise(rb_eTypeError, "uninitialized struct");
72 }
73 if (!RB_TYPE_P(members, T_ARRAY)) {
74 rb_raise(rb_eTypeError, "corrupted struct");
75 }
76 return members;
77}
78
79 VALUE
80 rb_struct_members(VALUE s)
81{
82 VALUE members = rb_struct_s_members(rb_obj_class(s));
83
84 if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) {
85 rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
86 RARRAY_LEN(members), RSTRUCT_LEN(s));
87 }
88 return members;
89}
90
91static long
92struct_member_pos_ideal(VALUE name, long mask)
93{
94 /* (id & (mask/2)) * 2 */
95 return (SYM2ID(name) >> (ID_SCOPE_SHIFT - 1)) & mask;
96}
97
98static long
99struct_member_pos_probe(long prev, long mask)
100{
101 /* (((prev/2) * AREF_HASH_UNIT + 1) & (mask/2)) * 2 */
102 return (prev * AREF_HASH_UNIT + 2) & mask;
103}
104
105static VALUE
106struct_set_members(VALUE klass, VALUE /* frozen hidden array */ members)
107{
108 VALUE back;
109 const long members_length = RARRAY_LEN(members);
110
111 if (members_length <= AREF_HASH_THRESHOLD) {
112 back = members;
113 }
114 else {
115 long i, j, mask = 64;
116 VALUE name;
117
118 while (mask < members_length * AREF_HASH_UNIT) mask *= 2;
119
120 back = rb_ary_tmp_new(mask + 1);
121 rb_ary_store(back, mask, INT2FIX(members_length));
122 mask -= 2; /* mask = (2**k-1)*2 */
123
124 for (i=0; i < members_length; i++) {
125 name = RARRAY_AREF(members, i);
126
127 j = struct_member_pos_ideal(name, mask);
128
129 for (;;) {
130 if (!RTEST(RARRAY_AREF(back, j))) {
131 rb_ary_store(back, j, name);
132 rb_ary_store(back, j + 1, INT2FIX(i));
133 break;
134 }
135 j = struct_member_pos_probe(j, mask);
136 }
137 }
138 OBJ_FREEZE_RAW(back);
139 }
140 rb_ivar_set(klass, id_members, members);
141 rb_ivar_set(klass, id_back_members, back);
142
143 return members;
144}
145
146static inline int
147struct_member_pos(VALUE s, VALUE name)
148{
149 VALUE back = struct_ivar_get(rb_obj_class(s), id_back_members);
150 long j, mask;
151
152 if (UNLIKELY(NIL_P(back))) {
153 rb_raise(rb_eTypeError, "uninitialized struct");
154 }
155 if (UNLIKELY(!RB_TYPE_P(back, T_ARRAY))) {
156 rb_raise(rb_eTypeError, "corrupted struct");
157 }
158
159 mask = RARRAY_LEN(back);
160
161 if (mask <= AREF_HASH_THRESHOLD) {
162 if (UNLIKELY(RSTRUCT_LEN(s) != mask)) {
163 rb_raise(rb_eTypeError,
164 "struct size differs (%ld required %ld given)",
165 mask, RSTRUCT_LEN(s));
166 }
167 for (j = 0; j < mask; j++) {
168 if (RARRAY_AREF(back, j) == name)
169 return (int)j;
170 }
171 return -1;
172 }
173
174 if (UNLIKELY(RSTRUCT_LEN(s) != FIX2INT(RARRAY_AREF(back, mask-1)))) {
175 rb_raise(rb_eTypeError, "struct size differs (%d required %ld given)",
176 FIX2INT(RARRAY_AREF(back, mask-1)), RSTRUCT_LEN(s));
177 }
178
179 mask -= 3;
180 j = struct_member_pos_ideal(name, mask);
181
182 for (;;) {
183 VALUE e = RARRAY_AREF(back, j);
184 if (e == name)
185 return FIX2INT(RARRAY_AREF(back, j + 1));
186 if (!RTEST(e)) {
187 return -1;
188 }
189 j = struct_member_pos_probe(j, mask);
190 }
191}
192
193static VALUE
194rb_struct_s_members_m(VALUE klass)
195{
196 VALUE members = rb_struct_s_members(klass);
197
198 return rb_ary_dup(members);
199}
200
201/*
202 * call-seq:
203 * struct.members -> array
204 *
205 * Returns the struct members as an array of symbols:
206 *
207 * Customer = Struct.new(:name, :address, :zip)
208 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
209 * joe.members #=> [:name, :address, :zip]
210 */
211
212static VALUE
213rb_struct_members_m(VALUE obj)
214{
215 return rb_struct_s_members_m(rb_obj_class(obj));
216}
217
218 VALUE
219 rb_struct_getmember(VALUE obj, ID id)
220{
221 VALUE slot = ID2SYM(id);
222 int i = struct_member_pos(obj, slot);
223 if (i != -1) {
224 return RSTRUCT_GET(obj, i);
225 }
226 rb_name_err_raise("`%1$s' is not a struct member", obj, ID2SYM(id));
227
228 UNREACHABLE_RETURN(Qnil);
229}
230
231static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_GET(obj, 0);}
232static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_GET(obj, 1);}
233static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_GET(obj, 2);}
234static VALUE rb_struct_ref3(VALUE obj) {return RSTRUCT_GET(obj, 3);}
235static VALUE rb_struct_ref4(VALUE obj) {return RSTRUCT_GET(obj, 4);}
236static VALUE rb_struct_ref5(VALUE obj) {return RSTRUCT_GET(obj, 5);}
237static VALUE rb_struct_ref6(VALUE obj) {return RSTRUCT_GET(obj, 6);}
238static VALUE rb_struct_ref7(VALUE obj) {return RSTRUCT_GET(obj, 7);}
239static VALUE rb_struct_ref8(VALUE obj) {return RSTRUCT_GET(obj, 8);}
240static VALUE rb_struct_ref9(VALUE obj) {return RSTRUCT_GET(obj, 9);}
241
242#define N_REF_FUNC numberof(ref_func)
243
244static VALUE (*const ref_func[])(VALUE) = {
245 rb_struct_ref0,
246 rb_struct_ref1,
247 rb_struct_ref2,
248 rb_struct_ref3,
249 rb_struct_ref4,
250 rb_struct_ref5,
251 rb_struct_ref6,
252 rb_struct_ref7,
253 rb_struct_ref8,
254 rb_struct_ref9,
255};
256
257static void
258rb_struct_modify(VALUE s)
259{
260 rb_check_frozen(s);
261}
262
263static VALUE
264anonymous_struct(VALUE klass)
265{
266 VALUE nstr;
267
268 nstr = rb_class_new(klass);
269 rb_make_metaclass(nstr, RBASIC(klass)->klass);
270 rb_class_inherited(klass, nstr);
271 return nstr;
272}
273
274static VALUE
275new_struct(VALUE name, VALUE super)
276{
277 /* old style: should we warn? */
278 ID id;
279 name = rb_str_to_str(name);
280 if (!rb_is_const_name(name)) {
281 rb_name_err_raise("identifier %1$s needs to be constant",
282 super, name);
283 }
284 id = rb_to_id(name);
285 if (rb_const_defined_at(super, id)) {
286 rb_warn("redefining constant %"PRIsVALUE"::%"PRIsVALUE, super, name);
287 rb_mod_remove_const(super, ID2SYM(id));
288 }
289 return rb_define_class_id_under(super, id, super);
290}
291
292 NORETURN(static void invalid_struct_pos(VALUE s, VALUE idx));
293
294static inline long
295struct_pos_num(VALUE s, VALUE idx)
296{
297 long i = NUM2INT(idx);
298 if (i < 0 || i >= RSTRUCT_LEN(s)) invalid_struct_pos(s, idx);
299 return i;
300}
301
302static VALUE
303opt_struct_aref(rb_execution_context_t *ec, VALUE self, VALUE idx)
304{
305 long i = struct_pos_num(self, idx);
306 return RSTRUCT_GET(self, i);
307}
308
309static VALUE
310opt_struct_aset(rb_execution_context_t *ec, VALUE self, VALUE val, VALUE idx)
311{
312 long i = struct_pos_num(self, idx);
313 rb_struct_modify(self);
314 RSTRUCT_SET(self, i, val);
315 return val;
316}
317
318static const struct rb_builtin_function struct_aref_builtin =
319 RB_BUILTIN_FUNCTION(0, struct_aref, opt_struct_aref, 1, 0);
320static const struct rb_builtin_function struct_aset_builtin =
321 RB_BUILTIN_FUNCTION(1, struct_aref, opt_struct_aset, 2, 0);
322
323static void
324define_aref_method(VALUE nstr, VALUE name, VALUE off)
325{
326 const rb_iseq_t *iseq = rb_method_for_self_aref(name, off, &struct_aref_builtin);
327 iseq->body->builtin_inline_p = true;
328
329 rb_add_method_iseq(nstr, SYM2ID(name), iseq, NULL, METHOD_VISI_PUBLIC);
330}
331
332static void
333define_aset_method(VALUE nstr, VALUE name, VALUE off)
334{
335 const rb_iseq_t *iseq = rb_method_for_self_aset(name, off, &struct_aset_builtin);
336
337 rb_add_method_iseq(nstr, SYM2ID(name), iseq, NULL, METHOD_VISI_PUBLIC);
338}
339
340static VALUE
341rb_struct_s_inspect(VALUE klass)
342{
343 VALUE inspect = rb_class_name(klass);
344 if (RTEST(rb_struct_s_keyword_init(klass))) {
345 rb_str_cat_cstr(inspect, "(keyword_init: true)");
346 }
347 return inspect;
348}
349
350static VALUE
351setup_struct(VALUE nstr, VALUE members)
352{
353 long i, len;
354
355 members = struct_set_members(nstr, members);
356
357 rb_define_alloc_func(nstr, struct_alloc);
358 rb_define_singleton_method(nstr, "new", rb_class_new_instance_pass_kw, -1);
359 rb_define_singleton_method(nstr, "[]", rb_class_new_instance_pass_kw, -1);
360 rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0);
361 rb_define_singleton_method(nstr, "inspect", rb_struct_s_inspect, 0);
362 len = RARRAY_LEN(members);
363 for (i=0; i< len; i++) {
364 VALUE sym = RARRAY_AREF(members, i);
365 ID id = SYM2ID(sym);
366 VALUE off = LONG2NUM(i);
367
368 if (i < N_REF_FUNC) {
369 rb_define_method_id(nstr, id, ref_func[i], 0);
370 }
371 else {
372 define_aref_method(nstr, sym, off);
373 }
374 define_aset_method(nstr, ID2SYM(rb_id_attrset(id)), off);
375 }
376
377 return nstr;
378}
379
380 VALUE
381 rb_struct_alloc_noinit(VALUE klass)
382{
383 return struct_alloc(klass);
384}
385
386static VALUE
387struct_make_members_list(va_list ar)
388{
389 char *mem;
390 VALUE ary, list = rb_ident_hash_new();
391 st_table *tbl = RHASH_TBL_RAW(list);
392
393 RBASIC_CLEAR_CLASS(list);
394 OBJ_WB_UNPROTECT(list);
395 while ((mem = va_arg(ar, char*)) != 0) {
396 VALUE sym = rb_sym_intern_ascii_cstr(mem);
397 if (st_insert(tbl, sym, Qtrue)) {
398 rb_raise(rb_eArgError, "duplicate member: %s", mem);
399 }
400 }
401 ary = rb_hash_keys(list);
402 st_clear(tbl);
403 RBASIC_CLEAR_CLASS(ary);
404 OBJ_FREEZE_RAW(ary);
405 return ary;
406}
407
408static VALUE
409struct_define_without_accessor(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, VALUE members)
410{
411 VALUE klass;
412
413 if (class_name) {
414 if (outer) {
415 klass = rb_define_class_under(outer, class_name, super);
416 }
417 else {
418 klass = rb_define_class(class_name, super);
419 }
420 }
421 else {
422 klass = anonymous_struct(super);
423 }
424
425 struct_set_members(klass, members);
426
427 if (alloc) {
428 rb_define_alloc_func(klass, alloc);
429 }
430 else {
431 rb_define_alloc_func(klass, struct_alloc);
432 }
433
434 return klass;
435}
436
437 VALUE
438 rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, ...)
439{
440 va_list ar;
441 VALUE members;
442
443 va_start(ar, alloc);
444 members = struct_make_members_list(ar);
445 va_end(ar);
446
447 return struct_define_without_accessor(outer, class_name, super, alloc, members);
448}
449
450 VALUE
451 rb_struct_define_without_accessor(const char *class_name, VALUE super, rb_alloc_func_t alloc, ...)
452{
453 va_list ar;
454 VALUE members;
455
456 va_start(ar, alloc);
457 members = struct_make_members_list(ar);
458 va_end(ar);
459
460 return struct_define_without_accessor(0, class_name, super, alloc, members);
461}
462
463 VALUE
464 rb_struct_define(const char *name, ...)
465{
466 va_list ar;
467 VALUE st, ary;
468
469 va_start(ar, name);
470 ary = struct_make_members_list(ar);
471 va_end(ar);
472
473 if (!name) st = anonymous_struct(rb_cStruct);
474 else st = new_struct(rb_str_new2(name), rb_cStruct);
475 return setup_struct(st, ary);
476}
477
478 VALUE
479 rb_struct_define_under(VALUE outer, const char *name, ...)
480{
481 va_list ar;
482 VALUE ary;
483
484 va_start(ar, name);
485 ary = struct_make_members_list(ar);
486 va_end(ar);
487
488 return setup_struct(rb_define_class_under(outer, name, rb_cStruct), ary);
489}
490
491/*
492 * call-seq:
493 * Struct.new([class_name] [, member_name]+) -> StructClass
494 * Struct.new([class_name] [, member_name]+, keyword_init: true) -> StructClass
495 * Struct.new([class_name] [, member_name]+) {|StructClass| block } -> StructClass
496 * StructClass.new(value, ...) -> object
497 * StructClass[value, ...] -> object
498 *
499 * The first two forms are used to create a new Struct subclass +class_name+
500 * that can contain a value for each +member_name+. This subclass can be
501 * used to create instances of the structure like any other Class.
502 *
503 * If the +class_name+ is omitted an anonymous structure class will be
504 * created. Otherwise, the name of this struct will appear as a constant in
505 * class Struct, so it must be unique for all Structs in the system and
506 * must start with a capital letter. Assigning a structure class to a
507 * constant also gives the class the name of the constant.
508 *
509 * # Create a structure with a name under Struct
510 * Struct.new("Customer", :name, :address)
511 * #=> Struct::Customer
512 * Struct::Customer.new("Dave", "123 Main")
513 * #=> #<struct Struct::Customer name="Dave", address="123 Main">
514 *
515 * # Create a structure named by its constant
516 * Customer = Struct.new(:name, :address)
517 * #=> Customer
518 * Customer.new("Dave", "123 Main")
519 * #=> #<struct Customer name="Dave", address="123 Main">
520 *
521 * If the optional +keyword_init+ keyword argument is set to +true+,
522 * .new takes keyword arguments instead of normal arguments.
523 *
524 * Customer = Struct.new(:name, :address, keyword_init: true)
525 * Customer.new(name: "Dave", address: "123 Main")
526 * #=> #<struct Customer name="Dave", address="123 Main">
527 *
528 * If a block is given it will be evaluated in the context of
529 * +StructClass+, passing the created class as a parameter:
530 *
531 * Customer = Struct.new(:name, :address) do
532 * def greeting
533 * "Hello #{name}!"
534 * end
535 * end
536 * Customer.new("Dave", "123 Main").greeting #=> "Hello Dave!"
537 *
538 * This is the recommended way to customize a struct. Subclassing an
539 * anonymous struct creates an extra anonymous class that will never be used.
540 *
541 * The last two forms create a new instance of a struct subclass. The number
542 * of +value+ parameters must be less than or equal to the number of
543 * attributes defined for the structure. Unset parameters default to +nil+.
544 * Passing more parameters than number of attributes will raise
545 * an ArgumentError.
546 *
547 * Customer = Struct.new(:name, :address)
548 * Customer.new("Dave", "123 Main")
549 * #=> #<struct Customer name="Dave", address="123 Main">
550 * Customer["Dave"]
551 * #=> #<struct Customer name="Dave", address=nil>
552 */
553
554static VALUE
555rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
556{
557 VALUE name, rest, keyword_init = Qfalse;
558 long i;
559 VALUE st;
560 st_table *tbl;
561
562 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
563 name = argv[0];
564 if (SYMBOL_P(name)) {
565 name = Qnil;
566 }
567 else {
568 --argc;
569 ++argv;
570 }
571
572 if (RB_TYPE_P(argv[argc-1], T_HASH)) {
573 static ID keyword_ids[1];
574
575 if (!keyword_ids[0]) {
576 keyword_ids[0] = rb_intern("keyword_init");
577 }
578 rb_get_kwargs(argv[argc-1], keyword_ids, 0, 1, &keyword_init);
579 if (keyword_init == Qundef) {
580 keyword_init = Qfalse;
581 }
582 --argc;
583 }
584
585 rest = rb_ident_hash_new();
586 RBASIC_CLEAR_CLASS(rest);
587 OBJ_WB_UNPROTECT(rest);
588 tbl = RHASH_TBL_RAW(rest);
589 for (i=0; i<argc; i++) {
590 VALUE mem = rb_to_symbol(argv[i]);
591 if (rb_is_attrset_sym(mem)) {
592 rb_raise(rb_eArgError, "invalid struct member: %"PRIsVALUE, mem);
593 }
594 if (st_insert(tbl, mem, Qtrue)) {
595 rb_raise(rb_eArgError, "duplicate member: %"PRIsVALUE, mem);
596 }
597 }
598 rest = rb_hash_keys(rest);
599 st_clear(tbl);
600 RBASIC_CLEAR_CLASS(rest);
601 OBJ_FREEZE_RAW(rest);
602 if (NIL_P(name)) {
603 st = anonymous_struct(klass);
604 }
605 else {
606 st = new_struct(name, klass);
607 }
608 setup_struct(st, rest);
609 rb_ivar_set(st, id_keyword_init, keyword_init);
610 if (rb_block_given_p()) {
611 rb_mod_module_eval(0, 0, st);
612 }
613
614 return st;
615}
616
617static long
618num_members(VALUE klass)
619{
620 VALUE members;
621 members = struct_ivar_get(klass, id_members);
622 if (!RB_TYPE_P(members, T_ARRAY)) {
623 rb_raise(rb_eTypeError, "broken members");
624 }
625 return RARRAY_LEN(members);
626}
627
628/*
629 */
630
631 struct struct_hash_set_arg {
632 VALUE self;
633 VALUE unknown_keywords;
634};
635
636static int rb_struct_pos(VALUE s, VALUE *name);
637
638static int
639struct_hash_set_i(VALUE key, VALUE val, VALUE arg)
640{
641 struct struct_hash_set_arg *args = (struct struct_hash_set_arg *)arg;
642 int i = rb_struct_pos(args->self, &key);
643 if (i < 0) {
644 if (args->unknown_keywords == Qnil) {
645 args->unknown_keywords = rb_ary_new();
646 }
647 rb_ary_push(args->unknown_keywords, key);
648 }
649 else {
650 rb_struct_modify(args->self);
651 RSTRUCT_SET(args->self, i, val);
652 }
653 return ST_CONTINUE;
654}
655
656static VALUE
657rb_struct_initialize_m(int argc, const VALUE *argv, VALUE self)
658{
659 VALUE klass = rb_obj_class(self);
660 long i, n;
661
662 rb_struct_modify(self);
663 n = num_members(klass);
664 if (argc > 0 && RTEST(rb_struct_s_keyword_init(klass))) {
665 struct struct_hash_set_arg arg;
666 if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
667 rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0)", argc);
668 }
669 rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), n);
670 arg.self = self;
671 arg.unknown_keywords = Qnil;
672 rb_hash_foreach(argv[0], struct_hash_set_i, (VALUE)&arg);
673 if (arg.unknown_keywords != Qnil) {
674 rb_raise(rb_eArgError, "unknown keywords: %s",
675 RSTRING_PTR(rb_ary_join(arg.unknown_keywords, rb_str_new2(", "))));
676 }
677 }
678 else {
679 if (n < argc) {
680 rb_raise(rb_eArgError, "struct size differs");
681 }
682 for (i=0; i<argc; i++) {
683 RSTRUCT_SET(self, i, argv[i]);
684 }
685 if (n > argc) {
686 rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self)+argc, n-argc);
687 }
688 }
689 return Qnil;
690}
691
692 VALUE
693 rb_struct_initialize(VALUE self, VALUE values)
694{
695 rb_struct_initialize_m(RARRAY_LENINT(values), RARRAY_CONST_PTR(values), self);
696 RB_GC_GUARD(values);
697 return Qnil;
698}
699
700static VALUE *
701struct_heap_alloc(VALUE st, size_t len)
702{
703 VALUE *ptr = rb_transient_heap_alloc((VALUE)st, sizeof(VALUE) * len);
704
705 if (ptr) {
706 RSTRUCT_TRANSIENT_SET(st);
707 return ptr;
708 }
709 else {
710 RSTRUCT_TRANSIENT_UNSET(st);
711 return ALLOC_N(VALUE, len);
712 }
713}
714
715#if USE_TRANSIENT_HEAP
716void
717 rb_struct_transient_heap_evacuate(VALUE obj, int promote)
718{
719 if (RSTRUCT_TRANSIENT_P(obj)) {
720 const VALUE *old_ptr = rb_struct_const_heap_ptr(obj);
721 VALUE *new_ptr;
722 long len = RSTRUCT_LEN(obj);
723
724 if (promote) {
725 new_ptr = ALLOC_N(VALUE, len);
726 FL_UNSET_RAW(obj, RSTRUCT_TRANSIENT_FLAG);
727 }
728 else {
729 new_ptr = struct_heap_alloc(obj, len);
730 }
731 MEMCPY(new_ptr, old_ptr, VALUE, len);
732 RSTRUCT(obj)->as.heap.ptr = new_ptr;
733 }
734}
735#endif
736
737static VALUE
738struct_alloc(VALUE klass)
739{
740 long n;
741 NEWOBJ_OF(st, struct RStruct, klass, T_STRUCT | (RGENGC_WB_PROTECTED_STRUCT ? FL_WB_PROTECTED : 0));
742
743 n = num_members(klass);
744
745 if (0 < n && n <= RSTRUCT_EMBED_LEN_MAX) {
746 RBASIC(st)->flags &= ~RSTRUCT_EMBED_LEN_MASK;
747 RBASIC(st)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
748 rb_mem_clear((VALUE *)st->as.ary, n);
749 }
750 else {
751 st->as.heap.ptr = struct_heap_alloc((VALUE)st, n);
752 rb_mem_clear((VALUE *)st->as.heap.ptr, n);
753 st->as.heap.len = n;
754 }
755
756 return (VALUE)st;
757}
758
759 VALUE
760 rb_struct_alloc(VALUE klass, VALUE values)
761{
762 return rb_class_new_instance(RARRAY_LENINT(values), RARRAY_CONST_PTR(values), klass);
763}
764
765 VALUE
766 rb_struct_new(VALUE klass, ...)
767{
768 VALUE tmpargs[N_REF_FUNC], *mem = tmpargs;
769 int size, i;
770 va_list args;
771
772 size = rb_long2int(num_members(klass));
773 if (size > numberof(tmpargs)) {
774 tmpargs[0] = rb_ary_tmp_new(size);
775 mem = RARRAY_PTR(tmpargs[0]);
776 }
777 va_start(args, klass);
778 for (i=0; i<size; i++) {
779 mem[i] = va_arg(args, VALUE);
780 }
781 va_end(args);
782
783 return rb_class_new_instance(size, mem, klass);
784}
785
786static VALUE
787struct_enum_size(VALUE s, VALUE args, VALUE eobj)
788{
789 return rb_struct_size(s);
790}
791
792/*
793 * call-seq:
794 * struct.each {|obj| block } -> struct
795 * struct.each -> enumerator
796 *
797 * Yields the value of each struct member in order. If no block is given an
798 * enumerator is returned.
799 *
800 * Customer = Struct.new(:name, :address, :zip)
801 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
802 * joe.each {|x| puts(x) }
803 *
804 * Produces:
805 *
806 * Joe Smith
807 * 123 Maple, Anytown NC
808 * 12345
809 */
810
811static VALUE
812rb_struct_each(VALUE s)
813{
814 long i;
815
816 RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
817 for (i=0; i<RSTRUCT_LEN(s); i++) {
818 rb_yield(RSTRUCT_GET(s, i));
819 }
820 return s;
821}
822
823/*
824 * call-seq:
825 * struct.each_pair {|sym, obj| block } -> struct
826 * struct.each_pair -> enumerator
827 *
828 * Yields the name and value of each struct member in order. If no block is
829 * given an enumerator is returned.
830 *
831 * Customer = Struct.new(:name, :address, :zip)
832 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
833 * joe.each_pair {|name, value| puts("#{name} => #{value}") }
834 *
835 * Produces:
836 *
837 * name => Joe Smith
838 * address => 123 Maple, Anytown NC
839 * zip => 12345
840 */
841
842static VALUE
843rb_struct_each_pair(VALUE s)
844{
845 VALUE members;
846 long i;
847
848 RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
849 members = rb_struct_members(s);
850 if (rb_block_pair_yield_optimizable()) {
851 for (i=0; i<RSTRUCT_LEN(s); i++) {
852 VALUE key = rb_ary_entry(members, i);
853 VALUE value = RSTRUCT_GET(s, i);
854 rb_yield_values(2, key, value);
855 }
856 }
857 else {
858 for (i=0; i<RSTRUCT_LEN(s); i++) {
859 VALUE key = rb_ary_entry(members, i);
860 VALUE value = RSTRUCT_GET(s, i);
861 rb_yield(rb_assoc_new(key, value));
862 }
863 }
864 return s;
865}
866
867static VALUE
868inspect_struct(VALUE s, VALUE dummy, int recur)
869{
870 VALUE cname = rb_class_path(rb_obj_class(s));
871 VALUE members, str = rb_str_new2("#<struct ");
872 long i, len;
873 char first = RSTRING_PTR(cname)[0];
874
875 if (recur || first != '#') {
876 rb_str_append(str, cname);
877 }
878 if (recur) {
879 return rb_str_cat2(str, ":...>");
880 }
881
882 members = rb_struct_members(s);
883 len = RSTRUCT_LEN(s);
884
885 for (i=0; i<len; i++) {
886 VALUE slot;
887 ID id;
888
889 if (i > 0) {
890 rb_str_cat2(str, ", ");
891 }
892 else if (first != '#') {
893 rb_str_cat2(str, " ");
894 }
895 slot = RARRAY_AREF(members, i);
896 id = SYM2ID(slot);
897 if (rb_is_local_id(id) || rb_is_const_id(id)) {
898 rb_str_append(str, rb_id2str(id));
899 }
900 else {
901 rb_str_append(str, rb_inspect(slot));
902 }
903 rb_str_cat2(str, "=");
904 rb_str_append(str, rb_inspect(RSTRUCT_GET(s, i)));
905 }
906 rb_str_cat2(str, ">");
907
908 return str;
909}
910
911/*
912 * call-seq:
913 * struct.to_s -> string
914 * struct.inspect -> string
915 *
916 * Returns a description of this struct as a string.
917 */
918
919static VALUE
920rb_struct_inspect(VALUE s)
921{
922 return rb_exec_recursive(inspect_struct, s, 0);
923}
924
925/*
926 * call-seq:
927 * struct.to_a -> array
928 * struct.values -> array
929 *
930 * Returns the values for this struct as an Array.
931 *
932 * Customer = Struct.new(:name, :address, :zip)
933 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
934 * joe.to_a[1] #=> "123 Maple, Anytown NC"
935 */
936
937static VALUE
938rb_struct_to_a(VALUE s)
939{
940 return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
941}
942
943/*
944 * call-seq:
945 * struct.to_h -> hash
946 * struct.to_h {|name, value| block } -> hash
947 *
948 * Returns a Hash containing the names and values for the struct's members.
949 *
950 * If a block is given, the results of the block on each pair of the receiver
951 * will be used as pairs.
952 *
953 * Customer = Struct.new(:name, :address, :zip)
954 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
955 * joe.to_h[:address] #=> "123 Maple, Anytown NC"
956 * joe.to_h{|name, value| [name.upcase, value.to_s.upcase]}[:ADDRESS]
957 * #=> "123 MAPLE, ANYTOWN NC"
958 */
959
960static VALUE
961rb_struct_to_h(VALUE s)
962{
963 VALUE h = rb_hash_new_with_size(RSTRUCT_LEN(s));
964 VALUE members = rb_struct_members(s);
965 long i;
966 int block_given = rb_block_given_p();
967
968 for (i=0; i<RSTRUCT_LEN(s); i++) {
969 VALUE k = rb_ary_entry(members, i), v = RSTRUCT_GET(s, i);
970 if (block_given)
971 rb_hash_set_pair(h, rb_yield_values(2, k, v));
972 else
973 rb_hash_aset(h, k, v);
974 }
975 return h;
976}
977
978static VALUE
979rb_struct_deconstruct_keys(VALUE s, VALUE keys)
980{
981 VALUE h;
982 long i;
983
984 if (NIL_P(keys)) {
985 return rb_struct_to_h(s);
986 }
987 if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) {
988 rb_raise(rb_eTypeError,
989 "wrong argument type %"PRIsVALUE" (expected Array or nil)",
990 rb_obj_class(keys));
991
992 }
993 if (RSTRUCT_LEN(s) < RARRAY_LEN(keys)) {
994 return rb_hash_new_with_size(0);
995 }
996 h = rb_hash_new_with_size(RARRAY_LEN(keys));
997 for (i=0; i<RARRAY_LEN(keys); i++) {
998 VALUE key = RARRAY_AREF(keys, i);
999 int i = rb_struct_pos(s, &key);
1000 if (i < 0) {
1001 return h;
1002 }
1003 rb_hash_aset(h, key, RSTRUCT_GET(s, i));
1004 }
1005 return h;
1006}
1007
1008/* :nodoc: */
1009 VALUE
1010 rb_struct_init_copy(VALUE copy, VALUE s)
1011{
1012 long i, len;
1013
1014 if (!OBJ_INIT_COPY(copy, s)) return copy;
1015 if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) {
1016 rb_raise(rb_eTypeError, "struct size mismatch");
1017 }
1018
1019 for (i=0, len=RSTRUCT_LEN(copy); i<len; i++) {
1020 RSTRUCT_SET(copy, i, RSTRUCT_GET(s, i));
1021 }
1022
1023 return copy;
1024}
1025
1026static int
1027rb_struct_pos(VALUE s, VALUE *name)
1028{
1029 long i;
1030 VALUE idx = *name;
1031
1032 if (RB_TYPE_P(idx, T_SYMBOL)) {
1033 return struct_member_pos(s, idx);
1034 }
1035 else if (RB_TYPE_P(idx, T_STRING)) {
1036 idx = rb_check_symbol(name);
1037 if (NIL_P(idx)) return -1;
1038 return struct_member_pos(s, idx);
1039 }
1040 else {
1041 long len;
1042 i = NUM2LONG(idx);
1043 len = RSTRUCT_LEN(s);
1044 if (i < 0) {
1045 if (i + len < 0) {
1046 *name = LONG2FIX(i);
1047 return -1;
1048 }
1049 i += len;
1050 }
1051 else if (len <= i) {
1052 *name = LONG2FIX(i);
1053 return -1;
1054 }
1055 return (int)i;
1056 }
1057}
1058
1059static void
1060invalid_struct_pos(VALUE s, VALUE idx)
1061{
1062 if (FIXNUM_P(idx)) {
1063 long i = FIX2INT(idx), len = RSTRUCT_LEN(s);
1064 if (i < 0) {
1065 rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)",
1066 i, len);
1067 }
1068 else {
1069 rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)",
1070 i, len);
1071 }
1072 }
1073 else {
1074 rb_name_err_raise("no member '%1$s' in struct", s, idx);
1075 }
1076}
1077
1078/*
1079 * call-seq:
1080 * struct[member] -> object
1081 * struct[index] -> object
1082 *
1083 * Attribute Reference---Returns the value of the given struct +member+ or
1084 * the member at the given +index+. Raises NameError if the +member+ does
1085 * not exist and IndexError if the +index+ is out of range.
1086 *
1087 * Customer = Struct.new(:name, :address, :zip)
1088 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1089 *
1090 * joe["name"] #=> "Joe Smith"
1091 * joe[:name] #=> "Joe Smith"
1092 * joe[0] #=> "Joe Smith"
1093 */
1094
1095 VALUE
1096 rb_struct_aref(VALUE s, VALUE idx)
1097{
1098 int i = rb_struct_pos(s, &idx);
1099 if (i < 0) invalid_struct_pos(s, idx);
1100 return RSTRUCT_GET(s, i);
1101}
1102
1103/*
1104 * call-seq:
1105 * struct[member] = obj -> obj
1106 * struct[index] = obj -> obj
1107 *
1108 * Attribute Assignment---Sets the value of the given struct +member+ or
1109 * the member at the given +index+. Raises NameError if the +member+ does not
1110 * exist and IndexError if the +index+ is out of range.
1111 *
1112 * Customer = Struct.new(:name, :address, :zip)
1113 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1114 *
1115 * joe["name"] = "Luke"
1116 * joe[:zip] = "90210"
1117 *
1118 * joe.name #=> "Luke"
1119 * joe.zip #=> "90210"
1120 */
1121
1122 VALUE
1123 rb_struct_aset(VALUE s, VALUE idx, VALUE val)
1124{
1125 int i = rb_struct_pos(s, &idx);
1126 if (i < 0) invalid_struct_pos(s, idx);
1127 rb_struct_modify(s);
1128 RSTRUCT_SET(s, i, val);
1129 return val;
1130}
1131
1132 FUNC_MINIMIZED(VALUE rb_struct_lookup(VALUE s, VALUE idx));
1133 NOINLINE(static VALUE rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound));
1134
1135 VALUE
1136 rb_struct_lookup(VALUE s, VALUE idx)
1137{
1138 return rb_struct_lookup_default(s, idx, Qnil);
1139}
1140
1141static VALUE
1142rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound)
1143{
1144 int i = rb_struct_pos(s, &idx);
1145 if (i < 0) return notfound;
1146 return RSTRUCT_GET(s, i);
1147}
1148
1149static VALUE
1150struct_entry(VALUE s, long n)
1151{
1152 return rb_struct_aref(s, LONG2NUM(n));
1153}
1154
1155/*
1156 * call-seq:
1157 * struct.values_at(selector, ...) -> array
1158 *
1159 * Returns the struct member values for each +selector+ as an Array. A
1160 * +selector+ may be either an Integer offset or a Range of offsets (as in
1161 * Array#values_at).
1162 *
1163 * Customer = Struct.new(:name, :address, :zip)
1164 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1165 * joe.values_at(0, 2) #=> ["Joe Smith", 12345]
1166 *
1167 */
1168
1169static VALUE
1170rb_struct_values_at(int argc, VALUE *argv, VALUE s)
1171{
1172 return rb_get_values_at(s, RSTRUCT_LEN(s), argc, argv, struct_entry);
1173}
1174
1175/*
1176 * call-seq:
1177 * struct.select {|obj| block } -> array
1178 * struct.select -> enumerator
1179 * struct.filter {|obj| block } -> array
1180 * struct.filter -> enumerator
1181 *
1182 * Yields each member value from the struct to the block and returns an Array
1183 * containing the member values from the +struct+ for which the given block
1184 * returns a true value (equivalent to Enumerable#select).
1185 *
1186 * Lots = Struct.new(:a, :b, :c, :d, :e, :f)
1187 * l = Lots.new(11, 22, 33, 44, 55, 66)
1188 * l.select {|v| v.even? } #=> [22, 44, 66]
1189 *
1190 * Struct#filter is an alias for Struct#select.
1191 */
1192
1193static VALUE
1194rb_struct_select(int argc, VALUE *argv, VALUE s)
1195{
1196 VALUE result;
1197 long i;
1198
1199 rb_check_arity(argc, 0, 0);
1200 RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
1201 result = rb_ary_new();
1202 for (i = 0; i < RSTRUCT_LEN(s); i++) {
1203 if (RTEST(rb_yield(RSTRUCT_GET(s, i)))) {
1204 rb_ary_push(result, RSTRUCT_GET(s, i));
1205 }
1206 }
1207
1208 return result;
1209}
1210
1211static VALUE
1212recursive_equal(VALUE s, VALUE s2, int recur)
1213{
1214 long i, len;
1215
1216 if (recur) return Qtrue; /* Subtle! */
1217 len = RSTRUCT_LEN(s);
1218 for (i=0; i<len; i++) {
1219 if (!rb_equal(RSTRUCT_GET(s, i), RSTRUCT_GET(s2, i))) return Qfalse;
1220 }
1221 return Qtrue;
1222}
1223
1224/*
1225 * call-seq:
1226 * struct == other -> true or false
1227 *
1228 * Equality---Returns +true+ if +other+ has the same struct subclass and has
1229 * equal member values (according to Object#==).
1230 *
1231 * Customer = Struct.new(:name, :address, :zip)
1232 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1233 * joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1234 * jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345)
1235 * joe == joejr #=> true
1236 * joe == jane #=> false
1237 */
1238
1239static VALUE
1240rb_struct_equal(VALUE s, VALUE s2)
1241{
1242 if (s == s2) return Qtrue;
1243 if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
1244 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
1245 if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
1246 rb_bug("inconsistent struct"); /* should never happen */
1247 }
1248
1249 return rb_exec_recursive_paired(recursive_equal, s, s2, s2);
1250}
1251
1252/*
1253 * call-seq:
1254 * struct.hash -> integer
1255 *
1256 * Returns a hash value based on this struct's contents.
1257 *
1258 * See also Object#hash.
1259 */
1260
1261static VALUE
1262rb_struct_hash(VALUE s)
1263{
1264 long i, len;
1265 st_index_t h;
1266 VALUE n;
1267
1268 h = rb_hash_start(rb_hash(rb_obj_class(s)));
1269 len = RSTRUCT_LEN(s);
1270 for (i = 0; i < len; i++) {
1271 n = rb_hash(RSTRUCT_GET(s, i));
1272 h = rb_hash_uint(h, NUM2LONG(n));
1273 }
1274 h = rb_hash_end(h);
1275 return ST2FIX(h);
1276}
1277
1278static VALUE
1279recursive_eql(VALUE s, VALUE s2, int recur)
1280{
1281 long i, len;
1282
1283 if (recur) return Qtrue; /* Subtle! */
1284 len = RSTRUCT_LEN(s);
1285 for (i=0; i<len; i++) {
1286 if (!rb_eql(RSTRUCT_GET(s, i), RSTRUCT_GET(s2, i))) return Qfalse;
1287 }
1288 return Qtrue;
1289}
1290
1291/*
1292 * call-seq:
1293 * struct.eql?(other) -> true or false
1294 *
1295 * Hash equality---+other+ and +struct+ refer to the same hash key if they
1296 * have the same struct subclass and have equal member values (according to
1297 * Object#eql?).
1298 */
1299
1300static VALUE
1301rb_struct_eql(VALUE s, VALUE s2)
1302{
1303 if (s == s2) return Qtrue;
1304 if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
1305 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
1306 if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
1307 rb_bug("inconsistent struct"); /* should never happen */
1308 }
1309
1310 return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
1311}
1312
1313/*
1314 * call-seq:
1315 * struct.length -> integer
1316 * struct.size -> integer
1317 *
1318 * Returns the number of struct members.
1319 *
1320 * Customer = Struct.new(:name, :address, :zip)
1321 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1322 * joe.length #=> 3
1323 */
1324
1325 VALUE
1326 rb_struct_size(VALUE s)
1327{
1328 return LONG2FIX(RSTRUCT_LEN(s));
1329}
1330
1331/*
1332 * call-seq:
1333 * struct.dig(key, *identifiers) -> object
1334 *
1335 * Finds and returns the object in nested objects
1336 * that is specified by +key+ and +identifiers+.
1337 * The nested objects may be instances of various classes.
1338 * See {Dig Methods}[rdoc-ref:doc/dig_methods.rdoc].
1339 *
1340 * Examples:
1341 * Foo = Struct.new(:a)
1342 * f = Foo.new(Foo.new({b: [1, 2, 3]}))
1343 * f.dig(:a) # => #<struct Foo a={:b=>[1, 2, 3]}>
1344 * f.dig(:a, :a) # => {:b=>[1, 2, 3]}
1345 * f.dig(:a, :a, :b) # => [1, 2, 3]
1346 * f.dig(:a, :a, :b, 0) # => 1
1347 * f.dig(:b, 0) # => nil
1348 */
1349
1350static VALUE
1351rb_struct_dig(int argc, VALUE *argv, VALUE self)
1352{
1353 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
1354 self = rb_struct_lookup(self, *argv);
1355 if (!--argc) return self;
1356 ++argv;
1357 return rb_obj_dig(argc, argv, self, Qnil);
1358}
1359
1360/*
1361 * Document-class: Struct
1362 *
1363 * A Struct is a convenient way to bundle a number of attributes together,
1364 * using accessor methods, without having to write an explicit class.
1365 *
1366 * The Struct class generates new subclasses that hold a set of members and
1367 * their values. For each member a reader and writer method is created
1368 * similar to Module#attr_accessor.
1369 *
1370 * Customer = Struct.new(:name, :address) do
1371 * def greeting
1372 * "Hello #{name}!"
1373 * end
1374 * end
1375 *
1376 * dave = Customer.new("Dave", "123 Main")
1377 * dave.name #=> "Dave"
1378 * dave.greeting #=> "Hello Dave!"
1379 *
1380 * See Struct::new for further examples of creating struct subclasses and
1381 * instances.
1382 *
1383 * In the method descriptions that follow, a "member" parameter refers to a
1384 * struct member which is either a quoted string (<code>"name"</code>) or a
1385 * Symbol (<code>:name</code>).
1386 */
1387void
1388InitVM_Struct(void)
1389{
1390 rb_cStruct = rb_define_class("Struct", rb_cObject);
1391 rb_include_module(rb_cStruct, rb_mEnumerable);
1392
1393 rb_undef_alloc_func(rb_cStruct);
1394 rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1);
1395
1396 rb_define_method(rb_cStruct, "initialize", rb_struct_initialize_m, -1);
1397 rb_define_method(rb_cStruct, "initialize_copy", rb_struct_init_copy, 1);
1398
1399 rb_define_method(rb_cStruct, "==", rb_struct_equal, 1);
1400 rb_define_method(rb_cStruct, "eql?", rb_struct_eql, 1);
1401 rb_define_method(rb_cStruct, "hash", rb_struct_hash, 0);
1402
1403 rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0);
1404 rb_define_alias(rb_cStruct, "to_s", "inspect");
1405 rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0);
1406 rb_define_method(rb_cStruct, "to_h", rb_struct_to_h, 0);
1407 rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0);
1408 rb_define_method(rb_cStruct, "size", rb_struct_size, 0);
1409 rb_define_method(rb_cStruct, "length", rb_struct_size, 0);
1410
1411 rb_define_method(rb_cStruct, "each", rb_struct_each, 0);
1412 rb_define_method(rb_cStruct, "each_pair", rb_struct_each_pair, 0);
1413 rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1);
1414 rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2);
1415 rb_define_method(rb_cStruct, "select", rb_struct_select, -1);
1416 rb_define_method(rb_cStruct, "filter", rb_struct_select, -1);
1417 rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1);
1418
1419 rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0);
1420 rb_define_method(rb_cStruct, "dig", rb_struct_dig, -1);
1421
1422 rb_define_method(rb_cStruct, "deconstruct", rb_struct_to_a, 0);
1423 rb_define_method(rb_cStruct, "deconstruct_keys", rb_struct_deconstruct_keys, 1);
1424}
1425
1426#undef rb_intern
1427void
1428Init_Struct(void)
1429{
1430 id_members = rb_intern("__members__");
1431 id_back_members = rb_intern("__members_back__");
1432 id_keyword_init = rb_intern("__keyword_init__");
1433
1434 InitVM(Struct);
1435}
rb_mem_clear
void rb_mem_clear(VALUE *mem, long size)
Definition: array.c:260
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1141
rb_get_values_at
VALUE rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE(*func)(VALUE, long))
Definition: array.c:3673
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:2666
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:749
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:846
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1672
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
rb_ary_join
VALUE rb_ary_join(VALUE ary, VALUE sep)
Definition: array.c:2780
NOINLINE
#define NOINLINE(x)
Definition: attributes.h:82
NORETURN
#define NORETURN(x)
Definition: attributes.h:152
FUNC_MINIMIZED
#define FUNC_MINIMIZED(x)
Definition: attributes.h:126
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Definition: assume.h:31
RB_BUILTIN_FUNCTION
#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity, _compiler)
Definition: builtin.h:19
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
rb_define_method_id
#define rb_define_method_id(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:656
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
recur
#define recur(fmt)
Definition: date_strptime.c:152
mask
enum @11::@13::@14 mask
ptr
struct RIMemo * ptr
Definition: debug.c:88
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:27
sym
#define sym(name)
Definition: enumerator.c:4007
len
uint8_t len
Definition: escape.c:17
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
numberof
#define numberof(array)
Definition: etc.c:649
RSTRING_PTR
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
UNLIKELY
#define UNLIKELY(x)
Definition: ffi_common.h:126
FL_WB_PROTECTED
#define FL_WB_PROTECTED
Definition: fl_type.h:50
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:962
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:748
rb_class_new
VALUE rb_class_new(VALUE super)
Creates a new class.
Definition: class.c:253
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:797
rb_define_class_id_under
VALUE rb_define_class_id_under(VALUE outer, ID id, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:820
rb_class_inherited
VALUE rb_class_inherited(VALUE super, VALUE klass)
Calls Class::inherited.
Definition: class.c:722
rb_make_metaclass
VALUE rb_make_metaclass(VALUE obj, VALUE unused)
Definition: class.c:679
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1999
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:2085
FL_UNSET_RAW
#define FL_UNSET_RAW
Definition: fl_type.h:133
OBJ_FREEZE_RAW
#define OBJ_FREEZE_RAW
Definition: fl_type.h:135
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:768
rb_ident_hash_new
VALUE rb_ident_hash_new(void)
Definition: hash.c:4443
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:1057
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:408
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:1059
rb_obj_dig
VALUE rb_obj_dig(int argc, VALUE *argv, VALUE self, VALUE notfound)
Definition: object.c:3812
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:49
rb_class_new_instance
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
Definition: object.c:1953
rb_class_new_instance_pass_kw
VALUE rb_class_new_instance_pass_kw(int, const VALUE *, VALUE)
Definition: object.c:1918
rb_eql
int rb_eql(VALUE, VALUE)
Determines if obj1 and obj2 are equal in terms of Object::eql?.
Definition: object.c:180
rb_obj_class
VALUE rb_obj_class(VALUE)
Definition: object.c:245
rb_inspect
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:585
rb_equal
VALUE rb_equal(VALUE, VALUE)
This function is an optimized version of calling #==.
Definition: object.c:157
rb_hash_set_pair
VALUE rb_hash_set_pair(VALUE hash, VALUE arg)
Definition: hash.c:3468
rb_hash_foreach
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1498
rb_hash_new_with_size
VALUE rb_hash_new_with_size(st_index_t size)
Definition: hash.c:1544
rb_hash_keys
VALUE rb_hash_keys(VALUE hash)
Definition: hash.c:3549
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
rb_hash
VALUE rb_hash(VALUE obj)
Definition: hash.c:143
id.h
ID_SCOPE_SHIFT
#define ID_SCOPE_SHIFT
Definition: id.h:31
builtin.h
Defines RBIMPL_HAS_BUILTIN.
rb_ary_new4
#define rb_ary_new4
Definition: array.h:74
RETURN_SIZED_ENUMERATOR
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
Definition: enumerator.h:64
UNLIMITED_ARGUMENTS
#define UNLIMITED_ARGUMENTS
Definition: error.h:29
rb_check_frozen
#define rb_check_frozen
Definition: error.h:72
rb_check_arity
#define rb_check_arity
Definition: error.h:34
OBJ_INIT_COPY
#define OBJ_INIT_COPY(obj, orig)
Definition: object.h:31
rb_is_local_id
int rb_is_local_id(ID)
Definition: symbol.c:1034
rb_is_const_id
int rb_is_const_id(ID)
Definition: symbol.c:1004
rb_id_attrset
ID rb_id_attrset(ID)
Definition: symbol.c:113
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_hash_uint
#define rb_hash_uint(h, i)
Definition: string.h:117
rb_hash_end
#define rb_hash_end(h)
Definition: string.h:118
rb_str_cat2
#define rb_str_cat2
Definition: string.h:285
rb_hash_start
st_index_t rb_hash_start(st_index_t)
Definition: random.c:1623
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
rb_str_cat_cstr
#define rb_str_cat_cstr(buf, str)
Definition: string.h:266
rb_exec_recursive_paired
VALUE rb_exec_recursive_paired(VALUE(*)(VALUE, VALUE, int), VALUE, VALUE, VALUE)
Definition: thread.c:5371
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int), VALUE, VALUE)
Definition: thread.c:5360
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:293
rb_const_defined_at
int rb_const_defined_at(VALUE, ID)
Definition: variable.c:2934
rb_class_path
VALUE rb_class_path(VALUE)
Definition: variable.c:169
rb_mod_remove_const
VALUE rb_mod_remove_const(VALUE, VALUE)
Definition: variable.c:2716
rb_attr_get
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1242
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1493
rb_mod_module_eval
VALUE rb_mod_module_eval(int, const VALUE *, VALUE)
Definition: vm_eval.c:2164
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_undef_alloc_func
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:954
rb_alloc_func_t
VALUE(* rb_alloc_func_t)(VALUE)
Definition: vm.h:50
ID2SYM
#define ID2SYM
Definition: symbol.h:44
rb_check_symbol
VALUE rb_check_symbol(volatile VALUE *namep)
Returns Symbol for the given name if it is interned already, or nil.
Definition: symbol.c:1114
SYM2ID
#define SYM2ID
Definition: symbol.h:45
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
rb_to_symbol
VALUE rb_to_symbol(VALUE name)
Definition: string.c:11511
rb_to_id
ID rb_to_id(VALUE)
Definition: string.c:11501
FIX2INT
#define FIX2INT
Definition: int.h:41
NUM2INT
#define NUM2INT
Definition: int.h:44
class.h
Internal header for Class.
hash.h
Internal header for Hash.
RHASH_TBL_RAW
#define RHASH_TBL_RAW(h)
Definition: hash.h:118
object.h
Internal header for Object.
proc.h
Internal header for Proc.
rb_block_pair_yield_optimizable
int rb_block_pair_yield_optimizable(void)
Definition: proc.c:1158
struct.h
Internal header for Struct.
RSTRUCT_GET
#define RSTRUCT_GET
Definition: struct.h:54
RSTRUCT_LEN
#define RSTRUCT_LEN
Definition: struct.h:52
RSTRUCT
#define RSTRUCT(obj)
Definition: struct.h:34
RSTRUCT_SET
#define RSTRUCT_SET
Definition: struct.h:53
RSTRUCT_EMBED_LEN_MAX
@ RSTRUCT_EMBED_LEN_MAX
Definition: struct.h:17
RSTRUCT_TRANSIENT_FLAG
@ RSTRUCT_TRANSIENT_FLAG
Definition: struct.h:20
RSTRUCT_EMBED_LEN_SHIFT
@ RSTRUCT_EMBED_LEN_SHIFT
Definition: struct.h:19
rb_is_attrset_sym
int rb_is_attrset_sym(VALUE sym)
Definition: symbol.c:1052
rb_is_const_name
int rb_is_const_name(VALUE name)
Definition: symbol.c:1217
internal.h
rb_sym_intern_ascii_cstr
#define rb_sym_intern_ascii_cstr(...)
Definition: internal.h:74
size
voidpf void uLong size
Definition: ioapi.h:138
rb_yield_values
VALUE rb_yield_values(int n,...)
Definition: vm_eval.c:1353
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
INT2FIX
#define INT2FIX
Definition: long.h:48
LONG2FIX
#define LONG2FIX
Definition: long.h:49
LONG2NUM
#define LONG2NUM
Definition: long.h:50
rb_long2int
#define rb_long2int
Definition: long.h:62
NUM2LONG
#define NUM2LONG
Definition: long.h:51
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
ALLOC_N
#define ALLOC_N
Definition: memory.h:133
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: memory.h:91
rb_add_method_iseq
void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi)
Definition: vm_method.c:910
METHOD_VISI_PUBLIC
@ METHOD_VISI_PUBLIC
Definition: method.h:31
NEWOBJ_OF
#define NEWOBJ_OF
Definition: newobj.h:35
id
const int id
Definition: nkf.c:209
name
const char * name
Definition: nkf.c:208
key
key
Definition: openssl_missing.h:185
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR(s)
Definition: psych_emitter.c:4
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
RARRAY_LEN
#define RARRAY_LEN
Definition: rarray.h:52
RBASIC
#define RBASIC(obj)
Definition: rbasic.h:34
RCLASS_SUPER
#define RCLASS_SUPER
Definition: rclass.h:33
NULL
#define NULL
Definition: regenc.h:69
RGENGC_WB_PROTECTED_STRUCT
#define RGENGC_WB_PROTECTED_STRUCT
Definition: rgengc.h:56
OBJ_WB_UNPROTECT
#define OBJ_WB_UNPROTECT
Definition: rgengc.h:120
rb_str_to_str
VALUE rb_str_to_str(VALUE)
Definition: string.c:1471
InitVM
#define InitVM(ext)
Definition: ruby.h:112
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
ST2FIX
#define ST2FIX(h)
Definition: ruby_missing.h:21
Qundef
#define Qundef
Definition: special_consts.h:53
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
FIXNUM_P
#define FIXNUM_P
Definition: special_consts.h:44
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
st_clear
#define st_clear
Definition: st.h:160
st_insert
#define st_insert
Definition: st.h:124
st_index_t
st_data_t st_index_t
Definition: st.h:50
rb_struct_define_under
VALUE rb_struct_define_under(VALUE outer, const char *name,...)
Definition: struct.c:479
rb_method_for_self_aset
const rb_iseq_t * rb_method_for_self_aset(VALUE name, VALUE arg, const struct rb_builtin_function *func)
Definition: compile.c:9900
InitVM_Struct
void InitVM_Struct(void)
Definition: struct.c:1388
rb_struct_define_without_accessor_under
VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc,...)
Definition: struct.c:438
rb_struct_new
VALUE rb_struct_new(VALUE klass,...)
Definition: struct.c:766
rb_struct_getmember
VALUE rb_struct_getmember(VALUE obj, ID id)
Definition: struct.c:219
rb_struct_init_copy
VALUE rb_struct_init_copy(VALUE copy, VALUE s)
Definition: struct.c:1010
Init_Struct
void Init_Struct(void)
Definition: struct.c:1428
rb_struct_size
VALUE rb_struct_size(VALUE s)
Definition: struct.c:1326
rb_cStruct
VALUE rb_cStruct
Definition: struct.c:34
rb_struct_initialize
VALUE rb_struct_initialize(VALUE self, VALUE values)
Definition: struct.c:693
rb_struct_define_without_accessor
VALUE rb_struct_define_without_accessor(const char *class_name, VALUE super, rb_alloc_func_t alloc,...)
Definition: struct.c:451
rb_struct_define
VALUE rb_struct_define(const char *name,...)
Definition: struct.c:464
rb_struct_alloc
VALUE rb_struct_alloc(VALUE klass, VALUE values)
Definition: struct.c:760
rb_struct_aset
VALUE rb_struct_aset(VALUE s, VALUE idx, VALUE val)
Definition: struct.c:1123
AREF_HASH_THRESHOLD
@ AREF_HASH_THRESHOLD
Definition: struct.c:28
AREF_HASH_UNIT
@ AREF_HASH_UNIT
Definition: struct.c:27
rb_struct_members
VALUE rb_struct_members(VALUE s)
Definition: struct.c:80
rb_struct_alloc_noinit
VALUE rb_struct_alloc_noinit(VALUE klass)
Definition: struct.c:381
rb_struct_s_members
VALUE rb_struct_s_members(VALUE klass)
Definition: struct.c:66
rb_struct_lookup
VALUE rb_struct_lookup(VALUE s, VALUE idx)
Definition: struct.c:1136
rb_struct_aref
VALUE rb_struct_aref(VALUE s, VALUE idx)
Definition: struct.c:1096
rb_method_for_self_aref
const rb_iseq_t * rb_method_for_self_aref(VALUE name, VALUE arg, const struct rb_builtin_function *func)
Definition: compile.c:9891
N_REF_FUNC
#define N_REF_FUNC
Definition: struct.c:242
rb_struct_s_keyword_init
VALUE rb_struct_s_keyword_init(VALUE klass)
Definition: struct.c:60
RStruct
Definition: struct.h:23
rb_builtin_function
Definition: builtin.h:6
rb_execution_context_struct
Definition: vm_core.h:854
rb_iseq_constant_body::builtin_inline_p
bool builtin_inline_p
Definition: vm_core.h:430
rb_iseq_struct
Definition: vm_core.h:444
rb_iseq_struct::body
struct rb_iseq_constant_body * body
Definition: vm_core.h:448
st_table
Definition: st.h:79
struct_hash_set_arg
Definition: struct.c:631
struct_hash_set_arg::unknown_keywords
VALUE unknown_keywords
Definition: struct.c:633
struct_hash_set_arg::self
VALUE self
Definition: struct.c:632
transient_heap.h
rb_struct_transient_heap_evacuate
#define rb_struct_transient_heap_evacuate(x, y)
Definition: transient_heap.h:62
rb_transient_heap_alloc
#define rb_transient_heap_alloc(o, s)
Definition: transient_heap.h:50
VALUE
unsigned long VALUE
Definition: value.h:38
ID
unsigned long ID
Definition: value.h:39
T_STRING
#define T_STRING
Definition: value_type.h:77
T_STRUCT
#define T_STRUCT
Definition: value_type.h:78
T_HASH
#define T_HASH
Definition: value_type.h:64
T_ARRAY
#define T_ARRAY
Definition: value_type.h:55
T_SYMBOL
#define T_SYMBOL
Definition: value_type.h:79
SYMBOL_P
#define SYMBOL_P
Definition: value_type.h:87
rb_id2str
#define rb_id2str(id)
Definition: vm_backtrace.c:30
vm_core.h