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