Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
struct.c
Go to the documentation of this file.
1 /*
2 ** struct.c - Struct class
3 **
4 ** See Copyright Notice in mruby.h
5 */
6 
7 #include <string.h>
8 #include <stdarg.h>
9 #include "mruby.h"
10 #include "mruby/array.h"
11 #include "mruby/string.h"
12 #include "mruby/class.h"
13 #include "mruby/data.h"
14 #include "mruby/variable.h"
15 
16 #define RSTRUCT_ARY(st) mrb_ary_ptr(st)
17 #define RSTRUCT_LEN(st) RSTRUCT_ARY(st)->len
18 #define RSTRUCT_PTR(st) RSTRUCT_ARY(st)->ptr
19 
20 static struct RClass *
21 struct_class(mrb_state *mrb)
22 {
23  return mrb_class_get(mrb, "Struct");
24 }
25 
26 static inline mrb_value
27 struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id)
28 {
29  struct RClass* kclass;
30  struct RClass* sclass = struct_class(mrb);
31  mrb_value ans;
32 
33  for (;;) {
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);
40  }
41 }
42 
44 mrb_struct_iv_get(mrb_state *mrb, mrb_value c, const char *name)
45 {
46  return struct_ivar_get(mrb, c, mrb_intern_cstr(mrb, name));
47 }
48 
51 {
52  mrb_value members = struct_ivar_get(mrb, klass, mrb_intern2(mrb, "__members__", 11));
53 
54  if (mrb_nil_p(members)) {
55  mrb_raise(mrb, E_TYPE_ERROR, "uninitialized struct");
56  }
57  if (!mrb_array_p(members)) {
58  mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct");
59  }
60  return members;
61 }
62 
65 {
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)) {
70  "struct size differs (%S required %S given)",
71  mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s)));
72  }
73  }
74  return members;
75 }
76 
77 static mrb_value
78 mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass)
79 {
80  mrb_value members, ary;
81  mrb_value *p, *pend;
82 
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);
86  while (p < pend) {
87  mrb_ary_push(mrb, ary, *p);
88  p++;
89  }
90  return ary;
91 }
92 
93 /* 15.2.18.4.6 */
94 /*
95  * call-seq:
96  * struct.members -> array
97  *
98  * Returns an array of strings representing the names of the instance
99  * variables.
100  *
101  * Customer = Struct.new(:name, :address, :zip)
102  * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
103  * joe.members #=> [:name, :address, :zip]
104  */
105 
106 static mrb_value
107 mrb_struct_members_m(mrb_state *mrb, mrb_value obj)
108 {
109  return mrb_struct_s_members_m(mrb, mrb_obj_value(mrb_obj_class(mrb, obj)));
110 }
111 
112 mrb_value
114 {
115  mrb_value members, slot, *ptr, *ptr_members;
116  mrb_int i, len;
117 
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)) {
125  return ptr[i];
126  }
127  }
128  mrb_raisef(mrb, E_INDEX_ERROR, "%S is not struct member", mrb_sym2str(mrb, id));
129  return mrb_nil_value(); /* not reached */
130 }
131 
132 static mrb_value
133 mrb_struct_ref(mrb_state *mrb, mrb_value obj)
134 {
135  return mrb_struct_getmember(mrb, obj, mrb->c->ci->mid);
136 }
137 
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];}
148 
149 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
150 #define N_REF_FUNC numberof(ref_func)
151 
152 static mrb_value (*const ref_func[])(mrb_state*, mrb_value) = {
153  mrb_struct_ref0,
154  mrb_struct_ref1,
155  mrb_struct_ref2,
156  mrb_struct_ref3,
157  mrb_struct_ref4,
158  mrb_struct_ref5,
159  mrb_struct_ref6,
160  mrb_struct_ref7,
161  mrb_struct_ref8,
162  mrb_struct_ref9,
163 };
164 
165 mrb_sym
167 {
168  const char *name;
169  char *buf;
170  size_t len;
171  mrb_sym mid;
172 
173  name = mrb_sym2name_len(mrb, id, &len);
174  buf = (char *)mrb_malloc(mrb, len+2);
175  memcpy(buf, name, len);
176  buf[len] = '=';
177  buf[len+1] = '\0';
178 
179  mid = mrb_intern2(mrb, buf, len+1);
180  mrb_free(mrb, buf);
181  return mid;
182 }
183 
184 static mrb_value
185 mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val)
186 {
187  const char *name;
188  size_t i, len;
189  mrb_sym mid;
190  mrb_value members, slot, *ptr, *ptr_members;
191 
192  /* get base id */
193  name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &len);
194  mid = mrb_intern2(mrb, name, len-1); /* omit last "=" */
195 
196  members = mrb_struct_members(mrb, obj);
197  ptr_members = RARRAY_PTR(members);
198  len = RARRAY_LEN(members);
199  ptr = RSTRUCT_PTR(obj);
200  for (i=0; i<len; i++) {
201  slot = ptr_members[i];
202  if (mrb_symbol(slot) == mid) {
203  return ptr[i] = val;
204  }
205  }
206  mrb_raisef(mrb, E_INDEX_ERROR, "`%S' is not a struct member",
207  mrb_sym2str(mrb, mid));
208  return mrb_nil_value(); /* not reached */
209 }
210 
211 static mrb_value
212 mrb_struct_set_m(mrb_state *mrb, mrb_value obj)
213 {
214  mrb_value val;
215 
216  mrb_get_args(mrb, "o", &val);
217  return mrb_struct_set(mrb, obj, val);
218 }
219 
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)
222 int
224 {
225  return is_local_id(id);
226 }
227 
228 #define is_const_id(id) (is_notop_id(id))//&&((id)&ID_SCOPE_MASK)==ID_CONST)
229 int
231 {
232  return is_const_id(id);
233 }
234 
235 static mrb_value
236 make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * klass)
237 {
238  mrb_value nstr, *ptr_members;
239  mrb_sym id;
240  mrb_int i, len;
241  struct RClass *c;
242 
243  if (mrb_nil_p(name)) {
244  c = mrb_class_new(mrb, klass);
245  }
246  else {
247  /* old style: should we warn? */
248  name = mrb_str_to_str(mrb, name);
249  id = mrb_obj_to_sym(mrb, name);
250  if (!mrb_is_const_id(id)) {
251  mrb_name_error(mrb, id, "identifier %S needs to be constant", name);
252  }
253  if (mrb_const_defined_at(mrb, klass, id)) {
254  mrb_warn(mrb, "redefining constant Struct::%S", name);
255  //?rb_mod_remove_const(klass, mrb_sym2name(mrb, id));
256  }
257  c = mrb_define_class_under(mrb, klass, RSTRING_PTR(name), klass);
258  }
260  nstr = mrb_obj_value(c);
261  mrb_iv_set(mrb, nstr, mrb_intern2(mrb, "__members__", 11), members);
262 
265  mrb_define_class_method(mrb, c, "members", mrb_struct_s_members_m, MRB_ARGS_NONE());
266  //RSTRUCT(nstr)->basic.c->super = c->c;
267  ptr_members = RARRAY_PTR(members);
268  len = RARRAY_LEN(members);
269  for (i=0; i< len; i++) {
270  mrb_sym id = mrb_symbol(ptr_members[i]);
271  if (mrb_is_local_id(id) || mrb_is_const_id(id)) {
272  if (i < N_REF_FUNC) {
273  mrb_define_method_id(mrb, c, id, ref_func[i], MRB_ARGS_NONE());
274  }
275  else {
276  mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE());
277  }
278  mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1));
279  }
280  }
281  return nstr;
282 }
283 
284 mrb_value
285 mrb_struct_define(mrb_state *mrb, const char *name, ...)
286 {
287  va_list ar;
288  mrb_value nm, ary;
289  char *mem;
290 
291  if (!name) nm = mrb_nil_value();
292  else nm = mrb_str_new_cstr(mrb, name);
293  ary = mrb_ary_new(mrb);
294 
295  va_start(ar, name);
296  while ((mem = va_arg(ar, char*)) != 0) {
297  mrb_sym slot = mrb_intern(mrb, mem);
298  mrb_ary_push(mrb, ary, mrb_symbol_value(slot));
299  }
300  va_end(ar);
301 
302  return make_struct(mrb, nm, ary, struct_class(mrb));
303 }
304 
305 /* 15.2.18.3.1 */
306 /*
307  * call-seq:
308  * Struct.new( [aString] [, aSym]+> ) -> StructClass
309  * StructClass.new(arg, ...) -> obj
310  * StructClass[arg, ...] -> obj
311  *
312  * Creates a new class, named by <i>aString</i>, containing accessor
313  * methods for the given symbols. If the name <i>aString</i> is
314  * omitted, an anonymous structure class will be created. Otherwise,
315  * the name of this struct will appear as a constant in class
316  * <code>Struct</code>, so it must be unique for all
317  * <code>Struct</code>s in the system and should start with a capital
318  * letter. Assigning a structure class to a constant effectively gives
319  * the class the name of the constant.
320  *
321  * <code>Struct::new</code> returns a new <code>Class</code> object,
322  * which can then be used to create specific instances of the new
323  * structure. The number of actual parameters must be
324  * less than or equal to the number of attributes defined for this
325  * class; unset parameters default to <code>nil</code>. Passing too many
326  * parameters will raise an <code>ArgumentError</code>.
327  *
328  * The remaining methods listed in this section (class and instance)
329  * are defined for this generated class.
330  *
331  * # Create a structure with a name in Struct
332  * Struct.new("Customer", :name, :address) #=> Struct::Customer
333  * Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main">
334  *
335  * # Create a structure named by its constant
336  * Customer = Struct.new(:name, :address) #=> Customer
337  * Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main">
338  */
339 static mrb_value
340 mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
341 {
342  mrb_value name, rest;
343  mrb_value *pargv;
344  int argcnt;
345  mrb_int i;
346  mrb_value b, st;
347  mrb_sym id;
348  mrb_value *argv;
349  int argc;
350 
351  name = mrb_nil_value();
352  rest = mrb_nil_value();
353  mrb_get_args(mrb, "*&", &argv, &argc, &b);
354  if (argc == 0) { /* special case to avoid crash */
355  rest = mrb_ary_new(mrb);
356  }
357  else {
358  if (argc > 0) name = argv[0];
359  if (argc > 1) rest = argv[1];
360  if (mrb_array_p(rest)) {
361  if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
362  /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
363  mrb_ary_unshift(mrb, rest, name);
364  name = mrb_nil_value();
365  }
366  }
367  else {
368  pargv = &argv[1];
369  argcnt = argc-1;
370  if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
371  /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
372  name = mrb_nil_value();
373  pargv = &argv[0];
374  argcnt++;
375  }
376  rest = mrb_ary_new_from_values(mrb, argcnt, pargv);
377  }
378  for (i=0; i<RARRAY_LEN(rest); i++) {
379  id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]);
380  RARRAY_PTR(rest)[i] = mrb_symbol_value(id);
381  }
382  }
383  st = make_struct(mrb, name, rest, struct_class(mrb));
384  if (!mrb_nil_p(b)) {
385  mrb_funcall(mrb, b, "call", 1, &st);
386  }
387 
388  return st;
389 }
390 
391 static int
392 num_members(mrb_state *mrb, struct RClass *klass)
393 {
394  mrb_value members;
395 
396  members = struct_ivar_get(mrb, mrb_obj_value(klass), mrb_intern2(mrb, "__members__", 11));
397  if (!mrb_array_p(members)) {
398  mrb_raise(mrb, E_TYPE_ERROR, "broken members");
399  }
400  return RARRAY_LEN(members);
401 }
402 
403 /* 15.2.18.4.8 */
404 /*
405  */
406 static mrb_value
407 mrb_struct_initialize_withArg(mrb_state *mrb, int argc, mrb_value *argv, mrb_value self)
408 {
409  struct RClass *klass = mrb_obj_class(mrb, self);
410  int i, n;
411 
412  n = num_members(mrb, klass);
413  if (n < argc) {
414  mrb_raise(mrb, E_ARGUMENT_ERROR, "struct size differs");
415  }
416 
417  for (i = 0; i < argc; i++) {
418  mrb_ary_set(mrb, self, i, argv[i]);
419  }
420  for (i = argc; i < n; i++) {
421  mrb_ary_set(mrb, self, i, mrb_nil_value());
422  }
423  return self;
424 }
425 
426 static mrb_value
427 mrb_struct_initialize_m(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value self)
428 {
429  mrb_value *argv;
430  int argc;
431 
432  mrb_get_args(mrb, "*", &argv, &argc);
433  return mrb_struct_initialize_withArg(mrb, argc, argv, self);
434 }
435 
436 mrb_value
438 {
439  return mrb_struct_initialize_withArg(mrb, RARRAY_LEN(values), RARRAY_PTR(values), self);
440 }
441 
442 static mrb_value
443 inspect_struct(mrb_state *mrb, mrb_value s, int recur)
444 {
445  const char *cn = mrb_class_name(mrb, mrb_obj_class(mrb, s));
446  mrb_value members, str = mrb_str_new(mrb, "#<struct ", 9);
447  mrb_value *ptr, *ptr_members;
448  mrb_int i, len;
449 
450  if (cn) {
451  mrb_str_append(mrb, str, mrb_str_new_cstr(mrb, cn));
452  }
453  if (recur) {
454  return mrb_str_cat2(mrb, str, ":...>");
455  }
456 
457  members = mrb_struct_members(mrb, s);
458  ptr_members = RARRAY_PTR(members);
459  ptr = RSTRUCT_PTR(s);
460  len = RSTRUCT_LEN(s);
461  for (i=0; i<len; i++) {
462  mrb_value slot;
463  mrb_sym id;
464 
465  if (i > 0) {
466  mrb_str_cat2(mrb, str, ", ");
467  }
468  else if (cn) {
469  mrb_str_cat2(mrb, str, " ");
470  }
471  slot = ptr_members[i];
472  id = mrb_symbol(slot);
473  if (mrb_is_local_id(id) || mrb_is_const_id(id)) {
474  const char *name;
475  size_t len;
476 
477  name = mrb_sym2name_len(mrb, id, &len);
478  mrb_str_append(mrb, str, mrb_str_new(mrb, name, len));
479  }
480  else {
481  mrb_str_append(mrb, str, mrb_inspect(mrb, slot));
482  }
483  mrb_str_cat2(mrb, str, "=");
484  mrb_str_append(mrb, str, mrb_inspect(mrb, ptr[i]));
485  }
486  mrb_str_cat2(mrb, str, ">");
487 
488  return str;
489 }
490 
491 /*
492  * call-seq:
493  * struct.to_s -> string
494  * struct.inspect -> string
495  *
496  * Describe the contents of this struct in a string.
497  */
498 static mrb_value
499 mrb_struct_inspect(mrb_state *mrb, mrb_value s)
500 {
501  return inspect_struct(mrb, s, 0);
502 }
503 
504 /* 15.2.18.4.9 */
505 /* :nodoc: */
506 mrb_value
508 {
509  mrb_value s;
510  int i, len;
511 
512  mrb_get_args(mrb, "o", &s);
513 
514  if (mrb_obj_equal(mrb, copy, s)) return copy;
515  if (!mrb_obj_is_instance_of(mrb, s, mrb_obj_class(mrb, copy))) {
516  mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
517  }
518  if (!mrb_array_p(s)) {
519  mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct");
520  }
521  if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) {
522  mrb_raise(mrb, E_TYPE_ERROR, "struct size mismatch");
523  }
524  len = RSTRUCT_LEN(copy);
525  for (i = 0; i < len; i++) {
526  mrb_ary_set(mrb, copy, i, RSTRUCT_PTR(s)[i]);
527  }
528  return copy;
529 }
530 
531 static mrb_value
532 mrb_struct_aref_id(mrb_state *mrb, mrb_value s, mrb_sym id)
533 {
534  mrb_value *ptr, members, *ptr_members;
535  mrb_int i, len;
536 
537  ptr = RSTRUCT_PTR(s);
538  members = mrb_struct_members(mrb, s);
539  ptr_members = RARRAY_PTR(members);
540  len = RARRAY_LEN(members);
541  for (i=0; i<len; i++) {
542  if (mrb_symbol(ptr_members[i]) == id) {
543  return ptr[i];
544  }
545  }
546  mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", mrb_sym2str(mrb, id));
547  return mrb_nil_value(); /* not reached */
548 }
549 
550 /* 15.2.18.4.2 */
551 /*
552  * call-seq:
553  * struct[symbol] -> anObject
554  * struct[fixnum] -> anObject
555  *
556  * Attribute Reference---Returns the value of the instance variable
557  * named by <i>symbol</i>, or indexed (0..length-1) by
558  * <i>fixnum</i>. Will raise <code>NameError</code> if the named
559  * variable does not exist, or <code>IndexError</code> if the index is
560  * out of range.
561  *
562  * Customer = Struct.new(:name, :address, :zip)
563  * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
564  *
565  * joe["name"] #=> "Joe Smith"
566  * joe[:name] #=> "Joe Smith"
567  * joe[0] #=> "Joe Smith"
568  */
569 mrb_value
571 {
572  mrb_int i;
573 
574  if (mrb_string_p(idx)) {
575  mrb_value sym = mrb_check_intern_str(mrb, idx);
576 
577  if (mrb_nil_p(sym)) {
578  mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", idx);
579  }
580  idx = sym;
581  }
582  if (mrb_symbol_p(idx)) {
583  return mrb_struct_aref_id(mrb, s, mrb_symbol(idx));
584  }
585 
586  i = mrb_fixnum(idx);
587  if (i < 0) i = RSTRUCT_LEN(s) + i;
588  if (i < 0)
590  "offset %S too small for struct(size:%S)",
591  mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
592  if (RSTRUCT_LEN(s) <= i)
594  "offset %S too large for struct(size:%S)",
595  mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
596  return RSTRUCT_PTR(s)[i];
597 }
598 
599 mrb_value
601 {
602  mrb_value idx;
603 
604  mrb_get_args(mrb, "o", &idx);
605  return mrb_struct_aref_n(mrb, s, idx);
606 }
607 
608 static mrb_value
609 mrb_struct_aset_id(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val)
610 {
611  mrb_value members, *ptr, *ptr_members;
612  mrb_int i, len;
613 
614  members = mrb_struct_members(mrb, s);
615  len = RARRAY_LEN(members);
616  if (RSTRUCT_LEN(s) != len) {
618  "struct size differs (%S required %S given)",
619  mrb_fixnum_value(len), mrb_fixnum_value(RSTRUCT_LEN(s)));
620  }
621  ptr = RSTRUCT_PTR(s);
622  ptr_members = RARRAY_PTR(members);
623  for (i=0; i<len; i++) {
624  if (mrb_symbol(ptr_members[i]) == id) {
625  ptr[i] = val;
626  return val;
627  }
628  }
629  mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", mrb_sym2str(mrb, id));
630  return val; /* not reach */
631 }
632 
633 /* 15.2.18.4.3 */
634 /*
635  * call-seq:
636  * struct[symbol] = obj -> obj
637  * struct[fixnum] = obj -> obj
638  *
639  * Attribute Assignment---Assigns to the instance variable named by
640  * <i>symbol</i> or <i>fixnum</i> the value <i>obj</i> and
641  * returns it. Will raise a <code>NameError</code> if the named
642  * variable does not exist, or an <code>IndexError</code> if the index
643  * is out of range.
644  *
645  * Customer = Struct.new(:name, :address, :zip)
646  * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
647  *
648  * joe["name"] = "Luke"
649  * joe[:zip] = "90210"
650  *
651  * joe.name #=> "Luke"
652  * joe.zip #=> "90210"
653  */
654 
655 mrb_value
657 {
658  mrb_int i;
659  mrb_value idx;
660  mrb_value val;
661 
662  mrb_get_args(mrb, "oo", &idx, &val);
663 
664  if (mrb_string_p(idx) || mrb_symbol_p(idx)) {
665  return mrb_struct_aset_id(mrb, s, mrb_obj_to_sym(mrb, idx), val);
666  }
667 
668  i = mrb_fixnum(idx);
669  if (i < 0) i = RSTRUCT_LEN(s) + i;
670  if (i < 0) {
672  "offset %S too small for struct(size:%S)",
673  mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
674  }
675  if (RSTRUCT_LEN(s) <= i) {
677  "offset %S too large for struct(size:%S)",
678  mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
679  }
680  return RSTRUCT_PTR(s)[i] = val;
681 }
682 
683 /* 15.2.18.4.1 */
684 /*
685  * call-seq:
686  * struct == other_struct -> true or false
687  *
688  * Equality---Returns <code>true</code> if <i>other_struct</i> is
689  * equal to this one: they must be of the same class as generated by
690  * <code>Struct::new</code>, and the values of all instance variables
691  * must be equal (according to <code>Object#==</code>).
692  *
693  * Customer = Struct.new(:name, :address, :zip)
694  * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
695  * joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
696  * jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345)
697  * joe == joejr #=> true
698  * joe == jane #=> false
699  */
700 
701 static mrb_value
702 mrb_struct_equal(mrb_state *mrb, mrb_value s)
703 {
704  mrb_value s2;
705  mrb_value *ptr, *ptr2;
706  mrb_int i, len;
707  mrb_bool equal_p;
708 
709  mrb_get_args(mrb, "o", &s2);
710  if (mrb_obj_equal(mrb, s, s2)) {
711  equal_p = 1;
712  }
713  else if (!strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s)), "Struct") ||
714  mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) {
715  equal_p = 0;
716  }
717  else if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
718  mrb_bug(mrb, "inconsistent struct"); /* should never happen */
719  equal_p = 0; /* This substuture is just to suppress warnings. never called. */
720  }
721  else {
722  ptr = RSTRUCT_PTR(s);
723  ptr2 = RSTRUCT_PTR(s2);
724  len = RSTRUCT_LEN(s);
725  equal_p = 1;
726  for (i=0; i<len; i++) {
727  if (!mrb_equal(mrb, ptr[i], ptr2[i])) {
728  equal_p = 0;
729  break;
730  }
731  }
732  }
733 
734  return mrb_bool_value(equal_p);
735 }
736 
737 /* 15.2.18.4.12(x) */
738 /*
739  * code-seq:
740  * struct.eql?(other) -> true or false
741  *
742  * Two structures are equal if they are the same object, or if all their
743  * fields are equal (using <code>eql?</code>).
744  */
745 static mrb_value
746 mrb_struct_eql(mrb_state *mrb, mrb_value s)
747 {
748  mrb_value s2;
749  mrb_value *ptr, *ptr2;
750  mrb_int i, len;
751  mrb_bool eql_p;
752 
753  mrb_get_args(mrb, "o", &s2);
754  if (mrb_obj_equal(mrb, s, s2)) {
755  eql_p = 1;
756  }
757  else if (strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s2)), "Struct") ||
758  mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) {
759  eql_p = 0;
760  }
761  else if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
762  mrb_bug(mrb, "inconsistent struct"); /* should never happen */
763  eql_p = 0; /* This substuture is just to suppress warnings. never called. */
764  }
765  else {
766  ptr = RSTRUCT_PTR(s);
767  ptr2 = RSTRUCT_PTR(s2);
768  len = RSTRUCT_LEN(s);
769  eql_p = 1;
770  for (i=0; i<len; i++) {
771  if (!mrb_eql(mrb, ptr[i], ptr2[i])) {
772  eql_p = 0;
773  break;
774  }
775  }
776  }
777 
778  return mrb_bool_value(eql_p);
779 }
780 
781 /*
782  * A <code>Struct</code> is a convenient way to bundle a number of
783  * attributes together, using accessor methods, without having to write
784  * an explicit class.
785  *
786  * The <code>Struct</code> class is a generator of specific classes,
787  * each one of which is defined to hold a set of variables and their
788  * accessors. In these examples, we'll call the generated class
789  * ``<i>Customer</i>Class,'' and we'll show an example instance of that
790  * class as ``<i>Customer</i>Inst.''
791  *
792  * In the descriptions that follow, the parameter <i>symbol</i> refers
793  * to a symbol, which is either a quoted string or a
794  * <code>Symbol</code> (such as <code>:name</code>).
795  */
796 void
798 {
799  struct RClass *st;
800  st = mrb_define_class(mrb, "Struct", mrb->object_class);
801 
802  mrb_define_class_method(mrb, st, "new", mrb_struct_s_def, MRB_ARGS_ANY()); /* 15.2.18.3.1 */
803 
804  mrb_define_method(mrb, st, "==", mrb_struct_equal, MRB_ARGS_REQ(1)); /* 15.2.18.4.1 */
805  mrb_define_method(mrb, st, "[]", mrb_struct_aref, MRB_ARGS_REQ(1)); /* 15.2.18.4.2 */
806  mrb_define_method(mrb, st, "[]=", mrb_struct_aset, MRB_ARGS_REQ(2)); /* 15.2.18.4.3 */
807  mrb_define_method(mrb, st, "members", mrb_struct_members_m, MRB_ARGS_NONE()); /* 15.2.18.4.6 */
808  mrb_define_method(mrb, st, "initialize", mrb_struct_initialize_m,MRB_ARGS_ANY()); /* 15.2.18.4.8 */
809  mrb_define_method(mrb, st, "initialize_copy", mrb_struct_init_copy, MRB_ARGS_REQ(1)); /* 15.2.18.4.9 */
810  mrb_define_method(mrb, st, "inspect", mrb_struct_inspect, MRB_ARGS_NONE()); /* 15.2.18.4.10(x) */
811  mrb_define_alias(mrb, st, "to_s", "inspect"); /* 15.2.18.4.11(x) */
812  mrb_define_method(mrb, st, "eql?", mrb_struct_eql, MRB_ARGS_REQ(1)); /* 15.2.18.4.12(x) */
813 }
814 
815 void
817 {
818 }