Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

struct.c

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

Generated on Wed Jan 18 23:32:07 2006 for Ruby by doxygen 1.3.5