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