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