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 (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
00083
00084
00085
00086
00087
00088
00089
00090
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;
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;
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
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
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
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
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
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
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
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
00558
00559
00560
00561
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
00572
00573
00574
00575
00576
00577
00578
00579
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
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;
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
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
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
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
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
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
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
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;
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
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
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");
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
00862
00863
00864
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;
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
00891
00892
00893
00894
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");
00905 }
00906
00907 return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922 static VALUE
00923 rb_struct_size(VALUE s)
00924 {
00925 return LONG2FIX(RSTRUCT_LEN(s));
00926 }
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
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