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