• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

struct.c

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

Generated on Thu Sep 8 2011 03:50:47 for Ruby by  doxygen 1.7.1