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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7