|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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
1.7.3