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