2 ** struct.c - Struct class
4 ** See Copyright Notice in mruby.h
10 #include "mruby/array.h"
11 #include "mruby/string.h"
12 #include "mruby/class.h"
13 #include "mruby/variable.h"
14 #include "mruby/hash.h"
15 #include "mruby/range.h"
17 #define RSTRUCT_LEN(st) RARRAY_LEN(st)
18 #define RSTRUCT_PTR(st) RARRAY_PTR(st)
20 static struct RClass
*
21 struct_class(mrb_state
*mrb
)
23 return mrb_class_get(mrb
, "Struct");
26 static inline mrb_value
27 struct_ivar_get(mrb_state
*mrb
, mrb_value c
, mrb_sym id
)
29 struct RClass
* kclass
;
30 struct RClass
* sclass
= struct_class(mrb
);
34 ans
= mrb_iv_get(mrb
, c
, id
);
35 if (!mrb_nil_p(ans
)) return ans
;
36 kclass
= RCLASS_SUPER(c
);
37 if (kclass
== 0 || kclass
== sclass
)
38 return mrb_nil_value();
39 c
= mrb_obj_value(kclass
);
44 mrb_struct_iv_get(mrb_state
*mrb
, mrb_value c
, const char *name
)
46 return struct_ivar_get(mrb
, c
, mrb_intern_cstr(mrb
, name
));
50 mrb_struct_s_members(mrb_state
*mrb
, mrb_value klass
)
52 mrb_value members
= struct_ivar_get(mrb
, klass
, mrb_intern_lit(mrb
, "__members__"));
54 if (mrb_nil_p(members
)) {
55 mrb_raise(mrb
, E_TYPE_ERROR
, "uninitialized struct");
57 if (!mrb_array_p(members
)) {
58 mrb_raise(mrb
, E_TYPE_ERROR
, "corrupted struct");
64 mrb_struct_members(mrb_state
*mrb
, mrb_value s
)
66 mrb_value members
= mrb_struct_s_members(mrb
, mrb_obj_value(mrb_obj_class(mrb
, s
)));
67 if (!strcmp(mrb_class_name(mrb
, mrb_obj_class(mrb
, s
)), "Struct")) {
68 if (RSTRUCT_LEN(s
) != RARRAY_LEN(members
)) {
69 mrb_raisef(mrb
, E_TYPE_ERROR
,
70 "struct size differs (%S required %S given)",
71 mrb_fixnum_value(RARRAY_LEN(members
)), mrb_fixnum_value(RSTRUCT_LEN(s
)));
78 mrb_struct_s_members_m(mrb_state
*mrb
, mrb_value klass
)
80 mrb_value members
, ary
;
83 members
= mrb_struct_s_members(mrb
, klass
);
84 ary
= mrb_ary_new_capa(mrb
, RARRAY_LEN(members
));
85 p
= RARRAY_PTR(members
); pend
= p
+ RARRAY_LEN(members
);
87 mrb_ary_push(mrb
, ary
, *p
);
96 * struct.members -> array
98 * Returns an array of strings representing the names of the instance
101 * Customer = Struct.new(:name, :address, :zip)
102 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
103 * joe.members #=> [:name, :address, :zip]
107 mrb_struct_members_m(mrb_state
*mrb
, mrb_value obj
)
109 return mrb_struct_s_members_m(mrb
, mrb_obj_value(mrb_obj_class(mrb
, obj
)));
113 mrb_struct_getmember(mrb_state
*mrb
, mrb_value obj
, mrb_sym id
)
115 mrb_value members
, slot
, *ptr
, *ptr_members
;
118 ptr
= RSTRUCT_PTR(obj
);
119 members
= mrb_struct_members(mrb
, obj
);
120 ptr_members
= RARRAY_PTR(members
);
121 slot
= mrb_symbol_value(id
);
122 len
= RARRAY_LEN(members
);
123 for (i
=0; i
<len
; i
++) {
124 if (mrb_obj_equal(mrb
, ptr_members
[i
], slot
)) {
128 mrb_raisef(mrb
, E_INDEX_ERROR
, "`%S' is not a struct member", mrb_sym2str(mrb
, id
));
129 return mrb_nil_value(); /* not reached */
133 mrb_struct_ref(mrb_state
*mrb
, mrb_value obj
)
135 return mrb_struct_getmember(mrb
, obj
, mrb
->c
->ci
->mid
);
138 static mrb_value
mrb_struct_ref0(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[0];}
139 static mrb_value
mrb_struct_ref1(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[1];}
140 static mrb_value
mrb_struct_ref2(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[2];}
141 static mrb_value
mrb_struct_ref3(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[3];}
142 static mrb_value
mrb_struct_ref4(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[4];}
143 static mrb_value
mrb_struct_ref5(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[5];}
144 static mrb_value
mrb_struct_ref6(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[6];}
145 static mrb_value
mrb_struct_ref7(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[7];}
146 static mrb_value
mrb_struct_ref8(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[8];}
147 static mrb_value
mrb_struct_ref9(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[9];}
149 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
150 #define N_REF_FUNC numberof(ref_func)
152 static mrb_value (*const ref_func
[])(mrb_state
*, mrb_value
) = {
166 mrb_id_attrset(mrb_state
*mrb
, mrb_sym id
)
173 name
= mrb_sym2name_len(mrb
, id
, &len
);
174 buf
= (char *)mrb_malloc(mrb
, (size_t)len
+2);
175 memcpy(buf
, name
, (size_t)len
);
179 mid
= mrb_intern(mrb
, buf
, len
+1);
185 mrb_struct_set(mrb_state
*mrb
, mrb_value obj
, mrb_value val
)
191 mrb_value members
, slot
, *ptr
, *ptr_members
;
194 name
= mrb_sym2name_len(mrb
, mrb
->c
->ci
->mid
, &slen
);
195 mid
= mrb_intern(mrb
, name
, slen
-1); /* omit last "=" */
197 members
= mrb_struct_members(mrb
, obj
);
198 ptr_members
= RARRAY_PTR(members
);
199 len
= RARRAY_LEN(members
);
200 ptr
= RSTRUCT_PTR(obj
);
201 for (i
=0; i
<len
; i
++) {
202 slot
= ptr_members
[i
];
203 if (mrb_symbol(slot
) == mid
) {
207 mrb_raisef(mrb
, E_INDEX_ERROR
, "`%S' is not a struct member", mrb_sym2str(mrb
, mid
));
208 return mrb_nil_value(); /* not reached */
212 mrb_struct_set_m(mrb_state
*mrb
, mrb_value obj
)
216 mrb_get_args(mrb
, "o", &val
);
217 return mrb_struct_set(mrb
, obj
, val
);
220 #define is_notop_id(id) (id) /* ((id)>tLAST_TOKEN) */
221 #define is_local_id(id) (is_notop_id(id)) /* &&((id)&ID_SCOPE_MASK)==ID_LOCAL) */
223 mrb_is_local_id(mrb_sym id
)
225 return is_local_id(id
);
228 #define is_const_id(id) (is_notop_id(id)) /* &&((id)&ID_SCOPE_MASK)==ID_CONST) */
230 mrb_is_const_id(mrb_sym id
)
232 return is_const_id(id
);
236 make_struct(mrb_state
*mrb
, mrb_value name
, mrb_value members
, struct RClass
* klass
)
238 mrb_value nstr
, *ptr_members
;
244 if (mrb_nil_p(name
)) {
245 c
= mrb_class_new(mrb
, klass
);
248 /* old style: should we warn? */
249 name
= mrb_str_to_str(mrb
, name
);
250 id
= mrb_obj_to_sym(mrb
, name
);
251 if (!mrb_is_const_id(id
)) {
252 mrb_name_error(mrb
, id
, "identifier %S needs to be constant", name
);
254 if (mrb_const_defined_at(mrb
, klass
, id
)) {
255 mrb_warn(mrb
, "redefining constant Struct::%S", name
);
256 /* ?rb_mod_remove_const(klass, mrb_sym2name(mrb, id)); */
258 c
= mrb_define_class_under(mrb
, klass
, RSTRING_PTR(name
), klass
);
260 MRB_SET_INSTANCE_TT(c
, MRB_TT_ARRAY
);
261 nstr
= mrb_obj_value(c
);
262 mrb_iv_set(mrb
, nstr
, mrb_intern_lit(mrb
, "__members__"), members
);
264 mrb_define_class_method(mrb
, c
, "new", mrb_instance_new
, MRB_ARGS_ANY());
265 mrb_define_class_method(mrb
, c
, "[]", mrb_instance_new
, MRB_ARGS_ANY());
266 mrb_define_class_method(mrb
, c
, "members", mrb_struct_s_members_m
, MRB_ARGS_NONE());
267 /* RSTRUCT(nstr)->basic.c->super = c->c; */
268 ptr_members
= RARRAY_PTR(members
);
269 len
= RARRAY_LEN(members
);
270 ai
= mrb_gc_arena_save(mrb
);
271 for (i
=0; i
< len
; i
++) {
272 mrb_sym id
= mrb_symbol(ptr_members
[i
]);
273 if (mrb_is_local_id(id
) || mrb_is_const_id(id
)) {
274 if (i
< N_REF_FUNC
) {
275 mrb_define_method_id(mrb
, c
, id
, ref_func
[i
], MRB_ARGS_NONE());
278 mrb_define_method_id(mrb
, c
, id
, mrb_struct_ref
, MRB_ARGS_NONE());
280 mrb_define_method_id(mrb
, c
, mrb_id_attrset(mrb
, id
), mrb_struct_set_m
, MRB_ARGS_REQ(1));
281 mrb_gc_arena_restore(mrb
, ai
);
288 mrb_struct_define(mrb_state
*mrb
, const char *name
, ...)
294 if (!name
) nm
= mrb_nil_value();
295 else nm
= mrb_str_new_cstr(mrb
, name
);
296 ary
= mrb_ary_new(mrb
);
299 while ((mem
= va_arg(ar
, char*)) != 0) {
300 mrb_sym slot
= mrb_intern_cstr(mrb
, mem
);
301 mrb_ary_push(mrb
, ary
, mrb_symbol_value(slot
));
305 return make_struct(mrb
, nm
, ary
, struct_class(mrb
));
311 * Struct.new( [aString] [, aSym]+> ) -> StructClass
312 * StructClass.new(arg, ...) -> obj
313 * StructClass[arg, ...] -> obj
315 * Creates a new class, named by <i>aString</i>, containing accessor
316 * methods for the given symbols. If the name <i>aString</i> is
317 * omitted, an anonymous structure class will be created. Otherwise,
318 * the name of this struct will appear as a constant in class
319 * <code>Struct</code>, so it must be unique for all
320 * <code>Struct</code>s in the system and should start with a capital
321 * letter. Assigning a structure class to a constant effectively gives
322 * the class the name of the constant.
324 * <code>Struct::new</code> returns a new <code>Class</code> object,
325 * which can then be used to create specific instances of the new
326 * structure. The number of actual parameters must be
327 * less than or equal to the number of attributes defined for this
328 * class; unset parameters default to <code>nil</code>. Passing too many
329 * parameters will raise an <code>ArgumentError</code>.
331 * The remaining methods listed in this section (class and instance)
332 * are defined for this generated class.
334 * # Create a structure with a name in Struct
335 * Struct.new("Customer", :name, :address) #=> Struct::Customer
336 * Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main">
338 * # Create a structure named by its constant
339 * Customer = Struct.new(:name, :address) #=> Customer
340 * Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main">
343 mrb_struct_s_def(mrb_state
*mrb
, mrb_value klass
)
345 mrb_value name
, rest
;
354 name
= mrb_nil_value();
355 rest
= mrb_nil_value();
356 mrb_get_args(mrb
, "*&", &argv
, &argc
, &b
);
357 if (argc
== 0) { /* special case to avoid crash */
358 rest
= mrb_ary_new(mrb
);
361 if (argc
> 0) name
= argv
[0];
362 if (argc
> 1) rest
= argv
[1];
363 if (mrb_array_p(rest
)) {
364 if (!mrb_nil_p(name
) && mrb_symbol_p(name
)) {
365 /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
366 mrb_ary_unshift(mrb
, rest
, name
);
367 name
= mrb_nil_value();
373 if (!mrb_nil_p(name
) && mrb_symbol_p(name
)) {
374 /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
375 name
= mrb_nil_value();
379 rest
= mrb_ary_new_from_values(mrb
, argcnt
, pargv
);
381 for (i
=0; i
<RARRAY_LEN(rest
); i
++) {
382 id
= mrb_obj_to_sym(mrb
, RARRAY_PTR(rest
)[i
]);
383 RARRAY_PTR(rest
)[i
] = mrb_symbol_value(id
);
386 st
= make_struct(mrb
, name
, rest
, struct_class(mrb
));
388 mrb_yield_with_class(mrb
, b
, 1, &st
, st
, mrb_class_ptr(klass
));
395 num_members(mrb_state
*mrb
, struct RClass
*klass
)
399 members
= struct_ivar_get(mrb
, mrb_obj_value(klass
), mrb_intern_lit(mrb
, "__members__"));
400 if (!mrb_array_p(members
)) {
401 mrb_raise(mrb
, E_TYPE_ERROR
, "broken members");
403 return RARRAY_LEN(members
);
410 mrb_struct_initialize_withArg(mrb_state
*mrb
, int argc
, mrb_value
*argv
, mrb_value self
)
412 struct RClass
*klass
= mrb_obj_class(mrb
, self
);
415 n
= num_members(mrb
, klass
);
417 mrb_raise(mrb
, E_ARGUMENT_ERROR
, "struct size differs");
420 for (i
= 0; i
< argc
; i
++) {
421 mrb_ary_set(mrb
, self
, i
, argv
[i
]);
423 for (i
= argc
; i
< n
; i
++) {
424 mrb_ary_set(mrb
, self
, i
, mrb_nil_value());
430 mrb_struct_initialize_m(mrb_state
*mrb
, /*int argc, mrb_value *argv,*/ mrb_value self
)
435 mrb_get_args(mrb
, "*", &argv
, &argc
);
436 return mrb_struct_initialize_withArg(mrb
, argc
, argv
, self
);
440 mrb_struct_initialize(mrb_state
*mrb
, mrb_value self
, mrb_value values
)
442 return mrb_struct_initialize_withArg(mrb
, RARRAY_LEN(values
), RARRAY_PTR(values
), self
);
446 inspect_struct(mrb_state
*mrb
, mrb_value s
, int recur
)
448 const char *cn
= mrb_class_name(mrb
, mrb_obj_class(mrb
, s
));
449 mrb_value members
, str
= mrb_str_new_lit(mrb
, "#<struct ");
450 mrb_value
*ptr
, *ptr_members
;
454 mrb_str_append(mrb
, str
, mrb_str_new_cstr(mrb
, cn
));
457 return mrb_str_cat_lit(mrb
, str
, ":...>");
460 members
= mrb_struct_members(mrb
, s
);
461 ptr_members
= RARRAY_PTR(members
);
462 ptr
= RSTRUCT_PTR(s
);
463 len
= RSTRUCT_LEN(s
);
464 for (i
=0; i
<len
; i
++) {
469 mrb_str_cat_lit(mrb
, str
, ", ");
472 mrb_str_cat_lit(mrb
, str
, " ");
474 slot
= ptr_members
[i
];
475 id
= mrb_symbol(slot
);
476 if (mrb_is_local_id(id
) || mrb_is_const_id(id
)) {
480 name
= mrb_sym2name_len(mrb
, id
, &len
);
481 mrb_str_append(mrb
, str
, mrb_str_new(mrb
, name
, len
));
484 mrb_str_append(mrb
, str
, mrb_inspect(mrb
, slot
));
486 mrb_str_cat_lit(mrb
, str
, "=");
487 mrb_str_append(mrb
, str
, mrb_inspect(mrb
, ptr
[i
]));
489 mrb_str_cat_lit(mrb
, str
, ">");
496 * struct.to_s -> string
497 * struct.inspect -> string
499 * Describe the contents of this struct in a string.
502 mrb_struct_inspect(mrb_state
*mrb
, mrb_value s
)
504 return inspect_struct(mrb
, s
, 0);
510 mrb_struct_init_copy(mrb_state
*mrb
, mrb_value copy
)
515 mrb_get_args(mrb
, "o", &s
);
517 if (mrb_obj_equal(mrb
, copy
, s
)) return copy
;
518 if (!mrb_obj_is_instance_of(mrb
, s
, mrb_obj_class(mrb
, copy
))) {
519 mrb_raise(mrb
, E_TYPE_ERROR
, "wrong argument class");
521 if (!mrb_array_p(s
)) {
522 mrb_raise(mrb
, E_TYPE_ERROR
, "corrupted struct");
524 if (RSTRUCT_LEN(copy
) != RSTRUCT_LEN(s
)) {
525 mrb_raise(mrb
, E_TYPE_ERROR
, "struct size mismatch");
527 len
= RSTRUCT_LEN(copy
);
528 for (i
= 0; i
< len
; i
++) {
529 mrb_ary_set(mrb
, copy
, i
, RSTRUCT_PTR(s
)[i
]);
535 struct_aref_sym(mrb_state
*mrb
, mrb_value s
, mrb_sym id
)
537 mrb_value
*ptr
, members
, *ptr_members
;
540 ptr
= RSTRUCT_PTR(s
);
541 members
= mrb_struct_members(mrb
, s
);
542 ptr_members
= RARRAY_PTR(members
);
543 len
= RARRAY_LEN(members
);
544 for (i
=0; i
<len
; i
++) {
545 if (mrb_symbol(ptr_members
[i
]) == id
) {
549 mrb_raisef(mrb
, E_INDEX_ERROR
, "no member '%S' in struct", mrb_sym2str(mrb
, id
));
550 return mrb_nil_value(); /* not reached */
554 struct_aref_int(mrb_state
*mrb
, mrb_value s
, mrb_int i
)
556 if (i
< 0) i
= RSTRUCT_LEN(s
) + i
;
558 mrb_raisef(mrb
, E_INDEX_ERROR
,
559 "offset %S too small for struct(size:%S)",
560 mrb_fixnum_value(i
), mrb_fixnum_value(RSTRUCT_LEN(s
)));
561 if (RSTRUCT_LEN(s
) <= i
)
562 mrb_raisef(mrb
, E_INDEX_ERROR
,
563 "offset %S too large for struct(size:%S)",
564 mrb_fixnum_value(i
), mrb_fixnum_value(RSTRUCT_LEN(s
)));
565 return RSTRUCT_PTR(s
)[i
];
571 * struct[symbol] -> anObject
572 * struct[fixnum] -> anObject
574 * Attribute Reference---Returns the value of the instance variable
575 * named by <i>symbol</i>, or indexed (0..length-1) by
576 * <i>fixnum</i>. Will raise <code>NameError</code> if the named
577 * variable does not exist, or <code>IndexError</code> if the index is
580 * Customer = Struct.new(:name, :address, :zip)
581 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
583 * joe["name"] #=> "Joe Smith"
584 * joe[:name] #=> "Joe Smith"
585 * joe[0] #=> "Joe Smith"
588 mrb_struct_aref(mrb_state
*mrb
, mrb_value s
)
592 mrb_get_args(mrb
, "o", &idx
);
593 if (mrb_string_p(idx
)) {
594 mrb_value sym
= mrb_check_intern_str(mrb
, idx
);
596 if (mrb_nil_p(sym
)) {
597 mrb_raisef(mrb
, E_INDEX_ERROR
, "no member '%S' in struct", idx
);
601 if (mrb_symbol_p(idx
)) {
602 return struct_aref_sym(mrb
, s
, mrb_symbol(idx
));
604 return struct_aref_int(mrb
, s
, mrb_int(mrb
, idx
));
608 mrb_struct_aset_sym(mrb_state
*mrb
, mrb_value s
, mrb_sym id
, mrb_value val
)
610 mrb_value members
, *ptr
, *ptr_members
;
613 members
= mrb_struct_members(mrb
, s
);
614 len
= RARRAY_LEN(members
);
615 if (RSTRUCT_LEN(s
) != len
) {
616 mrb_raisef(mrb
, E_TYPE_ERROR
,
617 "struct size differs (%S required %S given)",
618 mrb_fixnum_value(len
), mrb_fixnum_value(RSTRUCT_LEN(s
)));
620 ptr
= RSTRUCT_PTR(s
);
621 ptr_members
= RARRAY_PTR(members
);
622 for (i
=0; i
<len
; i
++) {
623 if (mrb_symbol(ptr_members
[i
]) == id
) {
628 mrb_raisef(mrb
, E_INDEX_ERROR
, "no member '%S' in struct", mrb_sym2str(mrb
, id
));
629 return val
; /* not reach */
635 * struct[symbol] = obj -> obj
636 * struct[fixnum] = obj -> obj
638 * Attribute Assignment---Assigns to the instance variable named by
639 * <i>symbol</i> or <i>fixnum</i> the value <i>obj</i> and
640 * returns it. Will raise a <code>NameError</code> if the named
641 * variable does not exist, or an <code>IndexError</code> if the index
644 * Customer = Struct.new(:name, :address, :zip)
645 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
647 * joe["name"] = "Luke"
648 * joe[:zip] = "90210"
650 * joe.name #=> "Luke"
651 * joe.zip #=> "90210"
655 mrb_struct_aset(mrb_state
*mrb
, mrb_value s
)
661 mrb_get_args(mrb
, "oo", &idx
, &val
);
663 if (mrb_string_p(idx
)) {
664 mrb_value sym
= mrb_check_intern_str(mrb
, idx
);
666 if (mrb_nil_p(sym
)) {
667 mrb_raisef(mrb
, E_INDEX_ERROR
, "no member '%S' in struct", idx
);
671 if (mrb_symbol_p(idx
)) {
672 return mrb_struct_aset_sym(mrb
, s
, mrb_symbol(idx
), val
);
675 i
= mrb_int(mrb
, idx
);
676 if (i
< 0) i
= RSTRUCT_LEN(s
) + i
;
678 mrb_raisef(mrb
, E_INDEX_ERROR
,
679 "offset %S too small for struct(size:%S)",
680 mrb_fixnum_value(i
), mrb_fixnum_value(RSTRUCT_LEN(s
)));
682 if (RSTRUCT_LEN(s
) <= i
) {
683 mrb_raisef(mrb
, E_INDEX_ERROR
,
684 "offset %S too large for struct(size:%S)",
685 mrb_fixnum_value(i
), mrb_fixnum_value(RSTRUCT_LEN(s
)));
687 return RSTRUCT_PTR(s
)[i
] = val
;
693 * struct == other_struct -> true or false
695 * Equality---Returns <code>true</code> if <i>other_struct</i> is
696 * equal to this one: they must be of the same class as generated by
697 * <code>Struct::new</code>, and the values of all instance variables
698 * must be equal (according to <code>Object#==</code>).
700 * Customer = Struct.new(:name, :address, :zip)
701 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
702 * joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
703 * jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345)
704 * joe == joejr #=> true
705 * joe == jane #=> false
709 mrb_struct_equal(mrb_state
*mrb
, mrb_value s
)
712 mrb_value
*ptr
, *ptr2
;
716 mrb_get_args(mrb
, "o", &s2
);
717 if (mrb_obj_equal(mrb
, s
, s2
)) {
720 else if (!strcmp(mrb_class_name(mrb
, mrb_obj_class(mrb
, s
)), "Struct") ||
721 mrb_obj_class(mrb
, s
) != mrb_obj_class(mrb
, s2
)) {
724 else if (RSTRUCT_LEN(s
) != RSTRUCT_LEN(s2
)) {
725 mrb_bug(mrb
, "inconsistent struct"); /* should never happen */
726 equal_p
= 0; /* This substuture is just to suppress warnings. never called. */
729 ptr
= RSTRUCT_PTR(s
);
730 ptr2
= RSTRUCT_PTR(s2
);
731 len
= RSTRUCT_LEN(s
);
733 for (i
=0; i
<len
; i
++) {
734 if (!mrb_equal(mrb
, ptr
[i
], ptr2
[i
])) {
741 return mrb_bool_value(equal_p
);
744 /* 15.2.18.4.12(x) */
747 * struct.eql?(other) -> true or false
749 * Two structures are equal if they are the same object, or if all their
750 * fields are equal (using <code>eql?</code>).
753 mrb_struct_eql(mrb_state
*mrb
, mrb_value s
)
756 mrb_value
*ptr
, *ptr2
;
760 mrb_get_args(mrb
, "o", &s2
);
761 if (mrb_obj_equal(mrb
, s
, s2
)) {
764 else if (strcmp(mrb_class_name(mrb
, mrb_obj_class(mrb
, s2
)), "Struct") ||
765 mrb_obj_class(mrb
, s
) != mrb_obj_class(mrb
, s2
)) {
768 else if (RSTRUCT_LEN(s
) != RSTRUCT_LEN(s2
)) {
769 mrb_bug(mrb
, "inconsistent struct"); /* should never happen */
770 eql_p
= 0; /* This substuture is just to suppress warnings. never called. */
773 ptr
= RSTRUCT_PTR(s
);
774 ptr2
= RSTRUCT_PTR(s2
);
775 len
= RSTRUCT_LEN(s
);
777 for (i
=0; i
<len
; i
++) {
778 if (!mrb_eql(mrb
, ptr
[i
], ptr2
[i
])) {
785 return mrb_bool_value(eql_p
);
790 * struct.length -> Fixnum
791 * struct.size -> Fixnum
793 * Returns number of struct members.
796 mrb_struct_len(mrb_state
*mrb
, mrb_value self
)
798 return mrb_fixnum_value(RSTRUCT_LEN(self
));
803 * struct.to_a -> array
804 * struct.values -> array
806 * Create an array from struct values.
809 mrb_struct_to_a(mrb_state
*mrb
, mrb_value self
)
811 return mrb_ary_new_from_values(mrb
, RSTRUCT_LEN(self
), RSTRUCT_PTR(self
));
816 * struct.to_h -> hash
818 * Create a hash from member names and struct values.
821 mrb_struct_to_h(mrb_state
*mrb
, mrb_value self
)
823 mrb_value members
, ret
;
826 members
= mrb_struct_s_members(mrb
, mrb_obj_value(mrb_class(mrb
, self
)));
827 ret
= mrb_hash_new_capa(mrb
, RARRAY_LEN(members
));
829 for (i
= 0; i
< RARRAY_LEN(members
); ++i
) {
830 mrb_hash_set(mrb
, ret
, RARRAY_PTR(members
)[i
], RSTRUCT_PTR(self
)[i
]);
837 mrb_struct_values_at(mrb_state
*mrb
, mrb_value self
)
842 mrb_get_args(mrb
, "*", &argv
, &argc
);
844 return mrb_get_values_at(mrb
, self
, RSTRUCT_LEN(self
), argc
, argv
, struct_aref_int
);
848 * A <code>Struct</code> is a convenient way to bundle a number of
849 * attributes together, using accessor methods, without having to write
852 * The <code>Struct</code> class is a generator of specific classes,
853 * each one of which is defined to hold a set of variables and their
854 * accessors. In these examples, we'll call the generated class
855 * ``<i>Customer</i>Class,'' and we'll show an example instance of that
856 * class as ``<i>Customer</i>Inst.''
858 * In the descriptions that follow, the parameter <i>symbol</i> refers
859 * to a symbol, which is either a quoted string or a
860 * <code>Symbol</code> (such as <code>:name</code>).
863 mrb_mruby_struct_gem_init(mrb_state
* mrb
)
866 st
= mrb_define_class(mrb
, "Struct", mrb
->object_class
);
868 mrb_define_class_method(mrb
, st
, "new", mrb_struct_s_def
, MRB_ARGS_ANY()); /* 15.2.18.3.1 */
870 mrb_define_method(mrb
, st
, "==", mrb_struct_equal
, MRB_ARGS_REQ(1)); /* 15.2.18.4.1 */
871 mrb_define_method(mrb
, st
, "[]", mrb_struct_aref
, MRB_ARGS_REQ(1)); /* 15.2.18.4.2 */
872 mrb_define_method(mrb
, st
, "[]=", mrb_struct_aset
, MRB_ARGS_REQ(2)); /* 15.2.18.4.3 */
873 mrb_define_method(mrb
, st
, "members", mrb_struct_members_m
, MRB_ARGS_NONE()); /* 15.2.18.4.6 */
874 mrb_define_method(mrb
, st
, "initialize", mrb_struct_initialize_m
,MRB_ARGS_ANY()); /* 15.2.18.4.8 */
875 mrb_define_method(mrb
, st
, "initialize_copy", mrb_struct_init_copy
, MRB_ARGS_REQ(1)); /* 15.2.18.4.9 */
876 mrb_define_method(mrb
, st
, "inspect", mrb_struct_inspect
, MRB_ARGS_NONE()); /* 15.2.18.4.10(x) */
877 mrb_define_alias(mrb
, st
, "to_s", "inspect"); /* 15.2.18.4.11(x) */
878 mrb_define_method(mrb
, st
, "eql?", mrb_struct_eql
, MRB_ARGS_REQ(1)); /* 15.2.18.4.12(x) */
880 mrb_define_method(mrb
, st
, "size", mrb_struct_len
, MRB_ARGS_NONE());
881 mrb_define_method(mrb
, st
, "length", mrb_struct_len
, MRB_ARGS_NONE());
882 mrb_define_method(mrb
, st
, "to_a", mrb_struct_to_a
, MRB_ARGS_NONE());
883 mrb_define_method(mrb
, st
, "values", mrb_struct_to_a
, MRB_ARGS_NONE());
884 mrb_define_method(mrb
, st
, "to_h", mrb_struct_to_h
, MRB_ARGS_NONE());
885 mrb_define_method(mrb
, st
, "values_at", mrb_struct_values_at
, MRB_ARGS_NONE());
889 mrb_mruby_struct_gem_final(mrb_state
* mrb
)