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