Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# struct.c

Go to the documentation of this file.

    00001 /**********************************************************************
    00002
    00003   struct.c -
    00004
    00005   $Author: marcandre $
    00006   created at: Tue Mar 22 18:44:30 JST 1995
    00007
    00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
    00009
    00010 **********************************************************************/
    00011
    00012 #include "ruby/ruby.h"
    00013
    00014 VALUE rb_cStruct;
    00015 static ID id_members;
    00016
    00017 static VALUE struct_alloc(VALUE);
    00018
    00019 static inline VALUE
    00020 struct_ivar_get(VALUE c, ID id)
    00021 {
    00022     for (;;) {
    00023         if (rb_ivar_defined(c, id))
    00024             return rb_ivar_get(c, id);
    00025         c = RCLASS_SUPER(c);
    00026         if (c == 0 || c == rb_cStruct)
    00027             return Qnil;
    00028     }
    00029 }
    00030
    00031 VALUE
    00032 rb_struct_iv_get(VALUE c, const char *name)
    00033 {
    00034     return struct_ivar_get(c, rb_intern(name));
    00035 }
    00036
    00037 VALUE
    00038 rb_struct_s_members(VALUE klass)
    00039 {
    00040     VALUE members = struct_ivar_get(klass, id_members);
    00041
    00042     if (NIL_P(members)) {
    00043         rb_raise(rb_eTypeError, "uninitialized struct");
    00044     }
    00045     if (TYPE(members) != T_ARRAY) {
    00046         rb_raise(rb_eTypeError, "corrupted struct");
    00047     }
    00048     return members;
    00049 }
    00050
    00051 VALUE
    00052 rb_struct_members(VALUE s)
    00053 {
    00054     VALUE members = rb_struct_s_members(rb_obj_class(s));
    00055
    00056     if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) {
    00057         rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
    00058                  RARRAY_LEN(members), RSTRUCT_LEN(s));
    00059     }
    00060     return members;
    00061 }
    00062
    00063 static VALUE
    00064 rb_struct_s_members_m(VALUE klass)
    00065 {
    00066     VALUE members, ary;
    00067     VALUE *p, *pend;
    00068
    00069     members = rb_struct_s_members(klass);
    00070     ary = rb_ary_new2(RARRAY_LEN(members));
    00071     p = RARRAY_PTR(members); pend = p + RARRAY_LEN(members);
    00072     while (p < pend) {
    00073         rb_ary_push(ary, *p);
    00074         p++;
    00075     }
    00076
    00077     return ary;
    00078 }
    00079
    00080 /*
    00081  *  call-seq:
    00082  *     struct.members    -> array
    00083  *
    00084  *  Returns an array of strings representing the names of the instance
    00085  *  variables.
    00086  *
    00087  *     Customer = Struct.new(:name, :address, :zip)
    00088  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00089  *     joe.members   #=> [:name, :address, :zip]
    00090  */
    00091
    00092 static VALUE
    00093 rb_struct_members_m(VALUE obj)
    00094 {
    00095     return rb_struct_s_members_m(rb_obj_class(obj));
    00096 }
    00097
    00098 VALUE
    00099 rb_struct_getmember(VALUE obj, ID id)
    00100 {
    00101     VALUE members, slot, *ptr, *ptr_members;
    00102     long i, len;
    00103
    00104     ptr = RSTRUCT_PTR(obj);
    00105     members = rb_struct_members(obj);
    00106     ptr_members = RARRAY_PTR(members);
    00107     slot = ID2SYM(id);
    00108     len = RARRAY_LEN(members);
    00109     for (i=0; i<len; i++) {
    00110         if (ptr_members[i] == slot) {
    00111             return ptr[i];
    00112         }
    00113     }
    00114     rb_name_error(id, "%s is not struct member", rb_id2name(id));
    00115     return Qnil;                /* not reached */
    00116 }
    00117
    00118 static VALUE
    00119 rb_struct_ref(VALUE obj)
    00120 {
    00121     return rb_struct_getmember(obj, rb_frame_this_func());
    00122 }
    00123
    00124 static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_PTR(obj)[0];}
    00125 static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_PTR(obj)[1];}
    00126 static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_PTR(obj)[2];}
    00127 static VALUE rb_struct_ref3(VALUE obj) {return RSTRUCT_PTR(obj)[3];}
    00128 static VALUE rb_struct_ref4(VALUE obj) {return RSTRUCT_PTR(obj)[4];}
    00129 static VALUE rb_struct_ref5(VALUE obj) {return RSTRUCT_PTR(obj)[5];}
    00130 static VALUE rb_struct_ref6(VALUE obj) {return RSTRUCT_PTR(obj)[6];}
    00131 static VALUE rb_struct_ref7(VALUE obj) {return RSTRUCT_PTR(obj)[7];}
    00132 static VALUE rb_struct_ref8(VALUE obj) {return RSTRUCT_PTR(obj)[8];}
    00133 static VALUE rb_struct_ref9(VALUE obj) {return RSTRUCT_PTR(obj)[9];}
    00134
    00135 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
    00136 #define N_REF_FUNC numberof(ref_func)
    00137
    00138 static VALUE (*const ref_func[])(VALUE) = {
    00139     rb_struct_ref0,
    00140     rb_struct_ref1,
    00141     rb_struct_ref2,
    00142     rb_struct_ref3,
    00143     rb_struct_ref4,
    00144     rb_struct_ref5,
    00145     rb_struct_ref6,
    00146     rb_struct_ref7,
    00147     rb_struct_ref8,
    00148     rb_struct_ref9,
    00149 };
    00150
    00151 static void
    00152 rb_struct_modify(VALUE s)
    00153 {
    00154     if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
    00155     if (!OBJ_UNTRUSTED(s) && rb_safe_level() >= 4)
    00156        rb_raise(rb_eSecurityError, "Insecure: can't modify Struct");
    00157 }
    00158
    00159 static VALUE
    00160 rb_struct_set(VALUE obj, VALUE val)
    00161 {
    00162     VALUE members, slot, *ptr, *ptr_members;
    00163     long i, len;
    00164
    00165     members = rb_struct_members(obj);
    00166     ptr_members = RARRAY_PTR(members);
    00167     len = RARRAY_LEN(members);
    00168     rb_struct_modify(obj);
    00169     ptr = RSTRUCT_PTR(obj);
    00170     for (i=0; i<len; i++) {
    00171         slot = ptr_members[i];
    00172         if (rb_id_attrset(SYM2ID(slot)) == rb_frame_this_func()) {
    00173             return ptr[i] = val;
    00174         }
    00175     }
    00176     rb_name_error(rb_frame_this_func(), "`%s' is not a struct member",
    00177                   rb_id2name(rb_frame_this_func()));
    00178     return Qnil;                /* not reached */
    00179 }
    00180
    00181 static VALUE
    00182 make_struct(VALUE name, VALUE members, VALUE klass)
    00183 {
    00184     VALUE nstr, *ptr_members;
    00185     ID id;
    00186     long i, len;
    00187
    00188     OBJ_FREEZE(members);
    00189     if (NIL_P(name)) {
    00190         nstr = rb_class_new(klass);
    00191         rb_make_metaclass(nstr, RBASIC(klass)->klass);
    00192         rb_class_inherited(klass, nstr);
    00193     }
    00194     else {
    00195         /* old style: should we warn? */
    00196         name = rb_str_to_str(name);
    00197         id = rb_to_id(name);
    00198         if (!rb_is_const_id(id)) {
    00199             rb_name_error(id, "identifier %s needs to be constant", StringValuePtr(name));
    00200         }
    00201         if (rb_const_defined_at(klass, id)) {
    00202             rb_warn("redefining constant Struct::%s", StringValuePtr(name));
    00203             rb_mod_remove_const(klass, ID2SYM(id));
    00204         }
    00205         nstr = rb_define_class_id_under(klass, id, klass);
    00206     }
    00207     rb_ivar_set(nstr, id_members, members);
    00208
    00209     rb_define_alloc_func(nstr, struct_alloc);
    00210     rb_define_singleton_method(nstr, "new", rb_class_new_instance, -1);
    00211     rb_define_singleton_method(nstr, "[]", rb_class_new_instance, -1);
    00212     rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0);
    00213     ptr_members = RARRAY_PTR(members);
    00214     len = RARRAY_LEN(members);
    00215     for (i=0; i< len; i++) {
    00216         ID id = SYM2ID(ptr_members[i]);
    00217         if (rb_is_local_id(id) || rb_is_const_id(id)) {
    00218             if (i < N_REF_FUNC) {
    00219                 rb_define_method_id(nstr, id, ref_func[i], 0);
    00220             }
    00221             else {
    00222                 rb_define_method_id(nstr, id, rb_struct_ref, 0);
    00223             }
    00224             rb_define_method_id(nstr, rb_id_attrset(id), rb_struct_set, 1);
    00225         }
    00226     }
    00227
    00228     return nstr;
    00229 }
    00230
    00231 VALUE
    00232 rb_struct_alloc_noinit(VALUE klass)
    00233 {
    00234     return struct_alloc(klass);
    00235 }
    00236
    00237 VALUE
    00238 rb_struct_define_without_accessor(const char *class_name, VALUE super, rb_alloc_func_t alloc, ...)
    00239 {
    00240     VALUE klass;
    00241     va_list ar;
    00242     VALUE members;
    00243     long i;
    00244     char *name;
    00245
    00246     members = rb_ary_new2(0);
    00247     va_start(ar, alloc);
    00248     i = 0;
    00249     while ((name = va_arg(ar, char*)) != NULL) {
    00250         rb_ary_push(members, ID2SYM(rb_intern(name)));
    00251     }
    00252     va_end(ar);
    00253     OBJ_FREEZE(members);
    00254
    00255     if (class_name) {
    00256         klass = rb_define_class(class_name, super);
    00257     }
    00258     else {
    00259         klass = rb_class_new(super);
    00260         rb_make_metaclass(klass, RBASIC(super)->klass);
    00261         rb_class_inherited(super, klass);
    00262     }
    00263
    00264     rb_ivar_set(klass, id_members, members);
    00265
    00266     if (alloc)
    00267         rb_define_alloc_func(klass, alloc);
    00268     else
    00269         rb_define_alloc_func(klass, struct_alloc);
    00270
    00271     return klass;
    00272 }
    00273
    00274 VALUE
    00275 rb_struct_define(const char *name, ...)
    00276 {
    00277     va_list ar;
    00278     VALUE nm, ary;
    00279     char *mem;
    00280
    00281     if (!name) nm = Qnil;
    00282     else nm = rb_str_new2(name);
    00283     ary = rb_ary_new();
    00284
    00285     va_start(ar, name);
    00286     while ((mem = va_arg(ar, char*)) != 0) {
    00287         ID slot = rb_intern(mem);
    00288         rb_ary_push(ary, ID2SYM(slot));
    00289     }
    00290     va_end(ar);
    00291
    00292     return make_struct(nm, ary, rb_cStruct);
    00293 }
    00294
    00295 /*
    00296  *  call-seq:
    00297  *     Struct.new( [aString] [, aSym]+> )    -> StructClass
    00298  *     StructClass.new(arg, ...)             -> obj
    00299  *     StructClass[arg, ...]                 -> obj
    00300  *
    00301  *  Creates a new class, named by <i>aString</i>, containing accessor
    00302  *  methods for the given symbols. If the name <i>aString</i> is
    00303  *  omitted, an anonymous structure class will be created. Otherwise,
    00304  *  the name of this struct will appear as a constant in class
    00305  *  <code>Struct</code>, so it must be unique for all
    00306  *  <code>Struct</code>s in the system and should start with a capital
    00307  *  letter. Assigning a structure class to a constant effectively gives
    00308  *  the class the name of the constant.
    00309  *
    00310  *  <code>Struct::new</code> returns a new <code>Class</code> object,
    00311  *  which can then be used to create specific instances of the new
    00312  *  structure. The number of actual parameters must be
    00313  *  less than or equal to the number of attributes defined for this
    00314  *  class; unset parameters default to <code>nil</code>.  Passing too many
    00315  *  parameters will raise an <code>ArgumentError</code>.
    00316  *
    00317  *  The remaining methods listed in this section (class and instance)
    00318  *  are defined for this generated class.
    00319  *
    00320  *     # Create a structure with a name in Struct
    00321  *     Struct.new("Customer", :name, :address)    #=> Struct::Customer
    00322  *     Struct::Customer.new("Dave", "123 Main")   #=> #<struct Struct::Customer name="Dave", address="123 Main">
    00323  *
    00324  *     # Create a structure named by its constant
    00325  *     Customer = Struct.new(:name, :address)     #=> Customer
    00326  *     Customer.new("Dave", "123 Main")           #=> #<struct Customer name="Dave", address="123 Main">
    00327  */
    00328
    00329 static VALUE
    00330 rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
    00331 {
    00332     VALUE name, rest;
    00333     long i;
    00334     VALUE st;
    00335     ID id;
    00336
    00337     rb_scan_args(argc, argv, "1*", &name, &rest);
    00338     if (!NIL_P(name) && SYMBOL_P(name)) {
    00339         rb_ary_unshift(rest, name);
    00340         name = Qnil;
    00341     }
    00342     for (i=0; i<RARRAY_LEN(rest); i++) {
    00343         id = rb_to_id(RARRAY_PTR(rest)[i]);
    00344         RARRAY_PTR(rest)[i] = ID2SYM(id);
    00345     }
    00346     st = make_struct(name, rest, klass);
    00347     if (rb_block_given_p()) {
    00348         rb_mod_module_eval(0, 0, st);
    00349     }
    00350
    00351     return st;
    00352 }
    00353
    00354 static long
    00355 num_members(VALUE klass)
    00356 {
    00357     VALUE members;
    00358     members = struct_ivar_get(klass, id_members);
    00359     if (TYPE(members) != T_ARRAY) {
    00360         rb_raise(rb_eTypeError, "broken members");
    00361     }
    00362     return RARRAY_LEN(members);
    00363 }
    00364
    00365 /*
    00366  */
    00367
    00368 static VALUE
    00369 rb_struct_initialize_m(int argc, VALUE *argv, VALUE self)
    00370 {
    00371     VALUE klass = rb_obj_class(self);
    00372     long n;
    00373
    00374     rb_struct_modify(self);
    00375     n = num_members(klass);
    00376     if (n < argc) {
    00377         rb_raise(rb_eArgError, "struct size differs");
    00378     }
    00379     MEMCPY(RSTRUCT_PTR(self), argv, VALUE, argc);
    00380     if (n > argc) {
    00381         rb_mem_clear(RSTRUCT_PTR(self)+argc, n-argc);
    00382     }
    00383     return Qnil;
    00384 }
    00385
    00386 VALUE
    00387 rb_struct_initialize(VALUE self, VALUE values)
    00388 {
    00389     return rb_struct_initialize_m(RARRAY_LENINT(values), RARRAY_PTR(values), self);
    00390 }
    00391
    00392 static VALUE
    00393 struct_alloc(VALUE klass)
    00394 {
    00395     long n;
    00396     NEWOBJ(st, struct RStruct);
    00397     OBJSETUP(st, klass, T_STRUCT);
    00398
    00399     n = num_members(klass);
    00400
    00401     if (0 < n && n <= RSTRUCT_EMBED_LEN_MAX) {
    00402         RBASIC(st)->flags &= ~RSTRUCT_EMBED_LEN_MASK;
    00403         RBASIC(st)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
    00404         rb_mem_clear(st->as.ary, n);
    00405     }
    00406     else {
    00407         st->as.heap.ptr = ALLOC_N(VALUE, n);
    00408         rb_mem_clear(st->as.heap.ptr, n);
    00409         st->as.heap.len = n;
    00410     }
    00411
    00412     return (VALUE)st;
    00413 }
    00414
    00415 VALUE
    00416 rb_struct_alloc(VALUE klass, VALUE values)
    00417 {
    00418     return rb_class_new_instance(RARRAY_LENINT(values), RARRAY_PTR(values), klass);
    00419 }
    00420
    00421 VALUE
    00422 rb_struct_new(VALUE klass, ...)
    00423 {
    00424     VALUE tmpargs[N_REF_FUNC], *mem = tmpargs;
    00425     int size, i;
    00426     va_list args;
    00427
    00428     size = rb_long2int(num_members(klass));
    00429     if (size > numberof(tmpargs)) {
    00430         tmpargs[0] = rb_ary_tmp_new(size);
    00431         mem = RARRAY_PTR(tmpargs[0]);
    00432     }
    00433     va_start(args, klass);
    00434     for (i=0; i<size; i++) {
    00435         mem[i] = va_arg(args, VALUE);
    00436     }
    00437     va_end(args);
    00438
    00439     return rb_class_new_instance(size, mem, klass);
    00440 }
    00441
    00442 /*
    00443  *  call-seq:
    00444  *     struct.each {|obj| block }  -> struct
    00445  *     struct.each                 -> an_enumerator
    00446  *
    00447  *  Calls <i>block</i> once for each instance variable, passing the
    00448  *  value as a parameter.
    00449  *
    00450  *  If no block is given, an enumerator is returned instead.
    00451  *
    00452  *     Customer = Struct.new(:name, :address, :zip)
    00453  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00454  *     joe.each {|x| puts(x) }
    00455  *
    00456  *  <em>produces:</em>
    00457  *
    00458  *     Joe Smith
    00459  *     123 Maple, Anytown NC
    00460  *     12345
    00461  */
    00462
    00463 static VALUE
    00464 rb_struct_each(VALUE s)
    00465 {
    00466     long i;
    00467
    00468     RETURN_ENUMERATOR(s, 0, 0);
    00469     for (i=0; i<RSTRUCT_LEN(s); i++) {
    00470         rb_yield(RSTRUCT_PTR(s)[i]);
    00471     }
    00472     return s;
    00473 }
    00474
    00475 /*
    00476  *  call-seq:
    00477  *     struct.each_pair {|sym, obj| block }     -> struct
    00478  *     struct.each_pair                         -> an_enumerator
    00479  *
    00480  *  Calls <i>block</i> once for each instance variable, passing the name
    00481  *  (as a symbol) and the value as parameters.
    00482  *
    00483  *  If no block is given, an enumerator is returned instead.
    00484  *
    00485  *     Customer = Struct.new(:name, :address, :zip)
    00486  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00487  *     joe.each_pair {|name, value| puts("#{name} => #{value}") }
    00488  *
    00489  *  <em>produces:</em>
    00490  *
    00491  *     name => Joe Smith
    00492  *     address => 123 Maple, Anytown NC
    00493  *     zip => 12345
    00494  */
    00495
    00496 static VALUE
    00497 rb_struct_each_pair(VALUE s)
    00498 {
    00499     VALUE members;
    00500     long i;
    00501
    00502     RETURN_ENUMERATOR(s, 0, 0);
    00503     members = rb_struct_members(s);
    00504     for (i=0; i<RSTRUCT_LEN(s); i++) {
    00505         rb_yield_values(2, rb_ary_entry(members, i), RSTRUCT_PTR(s)[i]);
    00506     }
    00507     return s;
    00508 }
    00509
    00510 static VALUE
    00511 inspect_struct(VALUE s, VALUE dummy, int recur)
    00512 {
    00513     VALUE cname = rb_class_name(rb_obj_class(s));
    00514     VALUE members, str = rb_str_new2("#<struct ");
    00515     VALUE *ptr, *ptr_members;
    00516     long i, len;
    00517     char first = RSTRING_PTR(cname)[0];
    00518
    00519     if (recur || first != '#') {
    00520         rb_str_append(str, cname);
    00521     }
    00522     if (recur) {
    00523         return rb_str_cat2(str, ":...>");
    00524     }
    00525
    00526     members = rb_struct_members(s);
    00527     ptr_members = RARRAY_PTR(members);
    00528     ptr = RSTRUCT_PTR(s);
    00529     len = RSTRUCT_LEN(s);
    00530     for (i=0; i<len; i++) {
    00531         VALUE slot;
    00532         ID id;
    00533
    00534         if (i > 0) {
    00535             rb_str_cat2(str, ", ");
    00536         }
    00537         else if (first != '#') {
    00538             rb_str_cat2(str, " ");
    00539         }
    00540         slot = ptr_members[i];
    00541         id = SYM2ID(slot);
    00542         if (rb_is_local_id(id) || rb_is_const_id(id)) {
    00543             rb_str_append(str, rb_id2str(id));
    00544         }
    00545         else {
    00546             rb_str_append(str, rb_inspect(slot));
    00547         }
    00548         rb_str_cat2(str, "=");
    00549         rb_str_append(str, rb_inspect(ptr[i]));
    00550     }
    00551     rb_str_cat2(str, ">");
    00552     OBJ_INFECT(str, s);
    00553
    00554     return str;
    00555 }
    00556
    00557 /*
    00558  * call-seq:
    00559  *   struct.to_s      -> string
    00560  *   struct.inspect   -> string
    00561  *
    00562  * Describe the contents of this struct in a string.
    00563  */
    00564
    00565 static VALUE
    00566 rb_struct_inspect(VALUE s)
    00567 {
    00568     return rb_exec_recursive(inspect_struct, s, 0);
    00569 }
    00570
    00571 /*
    00572  *  call-seq:
    00573  *     struct.to_a     -> array
    00574  *     struct.values   -> array
    00575  *
    00576  *  Returns the values for this instance as an array.
    00577  *
    00578  *     Customer = Struct.new(:name, :address, :zip)
    00579  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00580  *     joe.to_a[1]   #=> "123 Maple, Anytown NC"
    00581  */
    00582
    00583 static VALUE
    00584 rb_struct_to_a(VALUE s)
    00585 {
    00586     return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_PTR(s));
    00587 }
    00588
    00589 /* :nodoc: */
    00590 VALUE
    00591 rb_struct_init_copy(VALUE copy, VALUE s)
    00592 {
    00593     if (copy == s) return copy;
    00594     rb_check_frozen(copy);
    00595     if (!rb_obj_is_instance_of(s, rb_obj_class(copy))) {
    00596         rb_raise(rb_eTypeError, "wrong argument class");
    00597     }
    00598     if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) {
    00599         rb_raise(rb_eTypeError, "struct size mismatch");
    00600     }
    00601     MEMCPY(RSTRUCT_PTR(copy), RSTRUCT_PTR(s), VALUE, RSTRUCT_LEN(copy));
    00602
    00603     return copy;
    00604 }
    00605
    00606 static VALUE
    00607 rb_struct_aref_id(VALUE s, ID id)
    00608 {
    00609     VALUE *ptr, members, *ptr_members;
    00610     long i, len;
    00611
    00612     ptr = RSTRUCT_PTR(s);
    00613     members = rb_struct_members(s);
    00614     ptr_members = RARRAY_PTR(members);
    00615     len = RARRAY_LEN(members);
    00616     for (i=0; i<len; i++) {
    00617         if (SYM2ID(ptr_members[i]) == id) {
    00618             return ptr[i];
    00619         }
    00620     }
    00621     rb_name_error(id, "no member '%s' in struct", rb_id2name(id));
    00622     return Qnil;                /* not reached */
    00623 }
    00624
    00625 /*
    00626  *  call-seq:
    00627  *     struct[symbol]    -> anObject
    00628  *     struct[fixnum]    -> anObject
    00629  *
    00630  *  Attribute Reference---Returns the value of the instance variable
    00631  *  named by <i>symbol</i>, or indexed (0..length-1) by
    00632  *  <i>fixnum</i>. Will raise <code>NameError</code> if the named
    00633  *  variable does not exist, or <code>IndexError</code> if the index is
    00634  *  out of range.
    00635  *
    00636  *     Customer = Struct.new(:name, :address, :zip)
    00637  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00638  *
    00639  *     joe["name"]   #=> "Joe Smith"
    00640  *     joe[:name]    #=> "Joe Smith"
    00641  *     joe[0]        #=> "Joe Smith"
    00642  */
    00643
    00644 VALUE
    00645 rb_struct_aref(VALUE s, VALUE idx)
    00646 {
    00647     long i;
    00648
    00649     if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
    00650         return rb_struct_aref_id(s, rb_to_id(idx));
    00651     }
    00652
    00653     i = NUM2LONG(idx);
    00654     if (i < 0) i = RSTRUCT_LEN(s) + i;
    00655     if (i < 0)
    00656         rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)",
    00657                  i, RSTRUCT_LEN(s));
    00658     if (RSTRUCT_LEN(s) <= i)
    00659         rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)",
    00660                  i, RSTRUCT_LEN(s));
    00661     return RSTRUCT_PTR(s)[i];
    00662 }
    00663
    00664 static VALUE
    00665 rb_struct_aset_id(VALUE s, ID id, VALUE val)
    00666 {
    00667     VALUE members, *ptr, *ptr_members;
    00668     long i, len;
    00669
    00670     members = rb_struct_members(s);
    00671     len = RARRAY_LEN(members);
    00672     rb_struct_modify(s);
    00673     if (RSTRUCT_LEN(s) != len) {
    00674         rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
    00675                  len, RSTRUCT_LEN(s));
    00676     }
    00677     ptr = RSTRUCT_PTR(s);
    00678     ptr_members = RARRAY_PTR(members);
    00679     for (i=0; i<len; i++) {
    00680         if (SYM2ID(ptr_members[i]) == id) {
    00681             ptr[i] = val;
    00682             return val;
    00683         }
    00684     }
    00685     rb_name_error(id, "no member '%s' in struct", rb_id2name(id));
    00686 }
    00687
    00688 /*
    00689  *  call-seq:
    00690  *     struct[symbol] = obj    -> obj
    00691  *     struct[fixnum] = obj    -> obj
    00692  *
    00693  *  Attribute Assignment---Assigns to the instance variable named by
    00694  *  <i>symbol</i> or <i>fixnum</i> the value <i>obj</i> and
    00695  *  returns it. Will raise a <code>NameError</code> if the named
    00696  *  variable does not exist, or an <code>IndexError</code> if the index
    00697  *  is out of range.
    00698  *
    00699  *     Customer = Struct.new(:name, :address, :zip)
    00700  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00701  *
    00702  *     joe["name"] = "Luke"
    00703  *     joe[:zip]   = "90210"
    00704  *
    00705  *     joe.name   #=> "Luke"
    00706  *     joe.zip    #=> "90210"
    00707  */
    00708
    00709 VALUE
    00710 rb_struct_aset(VALUE s, VALUE idx, VALUE val)
    00711 {
    00712     long i;
    00713
    00714     if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
    00715         return rb_struct_aset_id(s, rb_to_id(idx), val);
    00716     }
    00717
    00718     i = NUM2LONG(idx);
    00719     if (i < 0) i = RSTRUCT_LEN(s) + i;
    00720     if (i < 0) {
    00721         rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)",
    00722                  i, RSTRUCT_LEN(s));
    00723     }
    00724     if (RSTRUCT_LEN(s) <= i) {
    00725         rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)",
    00726                  i, RSTRUCT_LEN(s));
    00727     }
    00728     rb_struct_modify(s);
    00729     return RSTRUCT_PTR(s)[i] = val;
    00730 }
    00731
    00732 static VALUE
    00733 struct_entry(VALUE s, long n)
    00734 {
    00735     return rb_struct_aref(s, LONG2NUM(n));
    00736 }
    00737
    00738 /*
    00739  * call-seq:
    00740  *   struct.values_at(selector,... )  -> an_array
    00741  *
    00742  *   Returns an array containing the elements in
    00743  *   +self+ corresponding to the given selector(s). The selectors
    00744  *   may be either integer indices or ranges.
    00745  *   See also </code>.select<code>.
    00746  *
    00747  *      a = %w{ a b c d e f }
    00748  *      a.values_at(1, 3, 5)
    00749  *      a.values_at(1, 3, 5, 7)
    00750  *      a.values_at(-1, -3, -5, -7)
    00751  *      a.values_at(1..3, 2...5)
    00752  */
    00753
    00754 static VALUE
    00755 rb_struct_values_at(int argc, VALUE *argv, VALUE s)
    00756 {
    00757     return rb_get_values_at(s, RSTRUCT_LEN(s), argc, argv, struct_entry);
    00758 }
    00759
    00760 /*
    00761  *  call-seq:
    00762  *     struct.select {|i| block }    -> array
    00763  *     struct.select                 -> an_enumerator
    00764  *
    00765  *  Invokes the block passing in successive elements from
    00766  *  <i>struct</i>, returning an array containing those elements
    00767  *  for which the block returns a true value (equivalent to
    00768  *  <code>Enumerable#select</code>).
    00769  *
    00770  *     Lots = Struct.new(:a, :b, :c, :d, :e, :f)
    00771  *     l = Lots.new(11, 22, 33, 44, 55, 66)
    00772  *     l.select {|v| (v % 2).zero? }   #=> [22, 44, 66]
    00773  */
    00774
    00775 static VALUE
    00776 rb_struct_select(int argc, VALUE *argv, VALUE s)
    00777 {
    00778     VALUE result;
    00779     long i;
    00780
    00781     if (argc > 0) {
    00782         rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
    00783     }
    00784     RETURN_ENUMERATOR(s, 0, 0);
    00785     result = rb_ary_new();
    00786     for (i = 0; i < RSTRUCT_LEN(s); i++) {
    00787         if (RTEST(rb_yield(RSTRUCT_PTR(s)[i]))) {
    00788             rb_ary_push(result, RSTRUCT_PTR(s)[i]);
    00789         }
    00790     }
    00791
    00792     return result;
    00793 }
    00794
    00795 static VALUE
    00796 recursive_equal(VALUE s, VALUE s2, int recur)
    00797 {
    00798     VALUE *ptr, *ptr2;
    00799     long i, len;
    00800
    00801     if (recur) return Qtrue; /* Subtle! */
    00802     ptr = RSTRUCT_PTR(s);
    00803     ptr2 = RSTRUCT_PTR(s2);
    00804     len = RSTRUCT_LEN(s);
    00805     for (i=0; i<len; i++) {
    00806         if (!rb_equal(ptr[i], ptr2[i])) return Qfalse;
    00807     }
    00808     return Qtrue;
    00809 }
    00810
    00811 /*
    00812  *  call-seq:
    00813  *     struct == other_struct     -> true or false
    00814  *
    00815  *  Equality---Returns <code>true</code> if <i>other_struct</i> is
    00816  *  equal to this one: they must be of the same class as generated by
    00817  *  <code>Struct::new</code>, and the values of all instance variables
    00818  *  must be equal (according to <code>Object#==</code>).
    00819  *
    00820  *     Customer = Struct.new(:name, :address, :zip)
    00821  *     joe   = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00822  *     joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00823  *     jane  = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345)
    00824  *     joe == joejr   #=> true
    00825  *     joe == jane    #=> false
    00826  */
    00827
    00828 static VALUE
    00829 rb_struct_equal(VALUE s, VALUE s2)
    00830 {
    00831     if (s == s2) return Qtrue;
    00832     if (TYPE(s2) != T_STRUCT) return Qfalse;
    00833     if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
    00834     if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
    00835         rb_bug("inconsistent struct"); /* should never happen */
    00836     }
    00837
    00838     return rb_exec_recursive_paired(recursive_equal, s, s2, s2);
    00839 }
    00840
    00841 static VALUE
    00842 recursive_hash(VALUE s, VALUE dummy, int recur)
    00843 {
    00844     long i, len;
    00845     st_index_t h;
    00846     VALUE n, *ptr;
    00847
    00848     h = rb_hash_start(rb_hash(rb_obj_class(s)));
    00849     if (!recur) {
    00850         ptr = RSTRUCT_PTR(s);
    00851         len = RSTRUCT_LEN(s);
    00852         for (i = 0; i < len; i++) {
    00853             n = rb_hash(ptr[i]);
    00854             h = rb_hash_uint(h, NUM2LONG(n));
    00855         }
    00856     }
    00857     h = rb_hash_end(h);
    00858     return INT2FIX(h);
    00859 }
    00860
    00861 /*
    00862  * call-seq:
    00863  *   struct.hash   -> fixnum
    00864  *
    00865  * Return a hash value based on this struct's contents.
    00866  */
    00867
    00868 static VALUE
    00869 rb_struct_hash(VALUE s)
    00870 {
    00871     return rb_exec_recursive_outer(recursive_hash, s, 0);
    00872 }
    00873
    00874 static VALUE
    00875 recursive_eql(VALUE s, VALUE s2, int recur)
    00876 {
    00877     VALUE *ptr, *ptr2;
    00878     long i, len;
    00879
    00880     if (recur) return Qtrue; /* Subtle! */
    00881     ptr = RSTRUCT_PTR(s);
    00882     ptr2 = RSTRUCT_PTR(s2);
    00883     len = RSTRUCT_LEN(s);
    00884     for (i=0; i<len; i++) {
    00885         if (!rb_eql(ptr[i], ptr2[i])) return Qfalse;
    00886     }
    00887     return Qtrue;
    00888 }
    00889
    00890 /*
    00891  * code-seq:
    00892  *   struct.eql?(other)   -> true or false
    00893  *
    00894  * Two structures are equal if they are the same object, or if all their
    00895  * fields are equal (using <code>eql?</code>).
    00896  */
    00897
    00898 static VALUE
    00899 rb_struct_eql(VALUE s, VALUE s2)
    00900 {
    00901     if (s == s2) return Qtrue;
    00902     if (TYPE(s2) != T_STRUCT) return Qfalse;
    00903     if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
    00904     if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
    00905         rb_bug("inconsistent struct"); /* should never happen */
    00906     }
    00907
    00908     return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
    00909 }
    00910
    00911 /*
    00912  *  call-seq:
    00913  *     struct.length    -> fixnum
    00914  *     struct.size      -> fixnum
    00915  *
    00916  *  Returns the number of instance variables.
    00917  *
    00918  *     Customer = Struct.new(:name, :address, :zip)
    00919  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
    00920  *     joe.length   #=> 3
    00921  */
    00922
    00923 static VALUE
    00924 rb_struct_size(VALUE s)
    00925 {
    00926     return LONG2FIX(RSTRUCT_LEN(s));
    00927 }
    00928
    00929 /*
    00930  *  A <code>Struct</code> is a convenient way to bundle a number of
    00931  *  attributes together, using accessor methods, without having to write
    00932  *  an explicit class.
    00933  *
    00934  *  The <code>Struct</code> class is a generator of specific classes,
    00935  *  each one of which is defined to hold a set of variables and their
    00936  *  accessors. In these examples, we'll call the generated class
    00937  *  ``<i>Customer</i>Class,'' and we'll show an example instance of that
    00938  *  class as ``<i>Customer</i>Inst.''
    00939  *
    00940  *  In the descriptions that follow, the parameter <i>symbol</i> refers
    00941  *  to a symbol, which is either a quoted string or a
    00942  *  <code>Symbol</code> (such as <code>:name</code>).
    00943  */
    00944 void
    00945 Init_Struct(void)
    00946 {
    00947     rb_cStruct = rb_define_class("Struct", rb_cObject);
    00948     rb_include_module(rb_cStruct, rb_mEnumerable);
    00949
    00950     rb_undef_alloc_func(rb_cStruct);
    00951     rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1);
    00952
    00953     rb_define_method(rb_cStruct, "initialize", rb_struct_initialize_m, -1);
    00954     rb_define_method(rb_cStruct, "initialize_copy", rb_struct_init_copy, 1);
    00955
    00956     rb_define_method(rb_cStruct, "==", rb_struct_equal, 1);
    00957     rb_define_method(rb_cStruct, "eql?", rb_struct_eql, 1);
    00958     rb_define_method(rb_cStruct, "hash", rb_struct_hash, 0);
    00959
    00960     rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0);
    00961     rb_define_alias(rb_cStruct,  "to_s", "inspect");
    00962     rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0);
    00963     rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0);
    00964     rb_define_method(rb_cStruct, "size", rb_struct_size, 0);
    00965     rb_define_method(rb_cStruct, "length", rb_struct_size, 0);
    00966
    00967     rb_define_method(rb_cStruct, "each", rb_struct_each, 0);
    00968     rb_define_method(rb_cStruct, "each_pair", rb_struct_each_pair, 0);
    00969     rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1);
    00970     rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2);
    00971     rb_define_method(rb_cStruct, "select", rb_struct_select, -1);
    00972     rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1);
    00973
    00974     rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0);
    00975     id_members = rb_intern("__members__");
    00976 }
    00977