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