00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013
00014 VALUE rb_cStruct;
00015 static ID id_members;
00016
00017 static VALUE struct_alloc(VALUE);
00018
00019 static inline VALUE
00020 struct_ivar_get(VALUE c, ID id)
00021 {
00022 for (;;) {
00023 if (rb_ivar_defined(c, id))
00024 return rb_ivar_get(c, id);
00025 c = RCLASS_SUPER(c);
00026 if (c == 0 || c == rb_cStruct)
00027 return Qnil;
00028 }
00029 }
00030
00031 VALUE
00032 rb_struct_iv_get(VALUE c, const char *name)
00033 {
00034 return struct_ivar_get(c, rb_intern(name));
00035 }
00036
00037 VALUE
00038 rb_struct_s_members(VALUE klass)
00039 {
00040 VALUE members = struct_ivar_get(klass, id_members);
00041
00042 if (NIL_P(members)) {
00043 rb_raise(rb_eTypeError, "uninitialized struct");
00044 }
00045 if (TYPE(members) != T_ARRAY) {
00046 rb_raise(rb_eTypeError, "corrupted struct");
00047 }
00048 return members;
00049 }
00050
00051 VALUE
00052 rb_struct_members(VALUE s)
00053 {
00054 VALUE members = rb_struct_s_members(rb_obj_class(s));
00055
00056 if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) {
00057 rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
00058 RARRAY_LEN(members), RSTRUCT_LEN(s));
00059 }
00060 return members;
00061 }
00062
00063 static VALUE
00064 rb_struct_s_members_m(VALUE klass)
00065 {
00066 VALUE members, ary;
00067 VALUE *p, *pend;
00068
00069 members = rb_struct_s_members(klass);
00070 ary = rb_ary_new2(RARRAY_LEN(members));
00071 p = RARRAY_PTR(members); pend = p + RARRAY_LEN(members);
00072 while (p < pend) {
00073 rb_ary_push(ary, *p);
00074 p++;
00075 }
00076
00077 return ary;
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 static VALUE
00093 rb_struct_members_m(VALUE obj)
00094 {
00095 return rb_struct_s_members_m(rb_obj_class(obj));
00096 }
00097
00098 VALUE
00099 rb_struct_getmember(VALUE obj, ID id)
00100 {
00101 VALUE members, slot, *ptr, *ptr_members;
00102 long i, len;
00103
00104 ptr = RSTRUCT_PTR(obj);
00105 members = rb_struct_members(obj);
00106 ptr_members = RARRAY_PTR(members);
00107 slot = ID2SYM(id);
00108 len = RARRAY_LEN(members);
00109 for (i=0; i<len; i++) {
00110 if (ptr_members[i] == slot) {
00111 return ptr[i];
00112 }
00113 }
00114 rb_name_error(id, "%s is not struct member", rb_id2name(id));
00115 return Qnil;
00116 }
00117
00118 static VALUE
00119 rb_struct_ref(VALUE obj)
00120 {
00121 return rb_struct_getmember(obj, rb_frame_this_func());
00122 }
00123
00124 static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_PTR(obj)[0];}
00125 static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_PTR(obj)[1];}
00126 static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_PTR(obj)[2];}
00127 static VALUE rb_struct_ref3(VALUE obj) {return RSTRUCT_PTR(obj)[3];}
00128 static VALUE rb_struct_ref4(VALUE obj) {return RSTRUCT_PTR(obj)[4];}
00129 static VALUE rb_struct_ref5(VALUE obj) {return RSTRUCT_PTR(obj)[5];}
00130 static VALUE rb_struct_ref6(VALUE obj) {return RSTRUCT_PTR(obj)[6];}
00131 static VALUE rb_struct_ref7(VALUE obj) {return RSTRUCT_PTR(obj)[7];}
00132 static VALUE rb_struct_ref8(VALUE obj) {return RSTRUCT_PTR(obj)[8];}
00133 static VALUE rb_struct_ref9(VALUE obj) {return RSTRUCT_PTR(obj)[9];}
00134
00135 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00136 #define N_REF_FUNC numberof(ref_func)
00137
00138 static VALUE (*const ref_func[])(VALUE) = {
00139 rb_struct_ref0,
00140 rb_struct_ref1,
00141 rb_struct_ref2,
00142 rb_struct_ref3,
00143 rb_struct_ref4,
00144 rb_struct_ref5,
00145 rb_struct_ref6,
00146 rb_struct_ref7,
00147 rb_struct_ref8,
00148 rb_struct_ref9,
00149 };
00150
00151 static void
00152 rb_struct_modify(VALUE s)
00153 {
00154 if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
00155 if (!OBJ_UNTRUSTED(s) && rb_safe_level() >= 4)
00156 rb_raise(rb_eSecurityError, "Insecure: can't modify Struct");
00157 }
00158
00159 static VALUE
00160 rb_struct_set(VALUE obj, VALUE val)
00161 {
00162 VALUE members, slot, *ptr, *ptr_members;
00163 long i, len;
00164
00165 members = rb_struct_members(obj);
00166 ptr_members = RARRAY_PTR(members);
00167 len = RARRAY_LEN(members);
00168 rb_struct_modify(obj);
00169 ptr = RSTRUCT_PTR(obj);
00170 for (i=0; i<len; i++) {
00171 slot = ptr_members[i];
00172 if (rb_id_attrset(SYM2ID(slot)) == rb_frame_this_func()) {
00173 return ptr[i] = val;
00174 }
00175 }
00176 rb_name_error(rb_frame_this_func(), "`%s' is not a struct member",
00177 rb_id2name(rb_frame_this_func()));
00178 return Qnil;
00179 }
00180
00181 static VALUE
00182 make_struct(VALUE name, VALUE members, VALUE klass)
00183 {
00184 VALUE nstr, *ptr_members;
00185 ID id;
00186 long i, len;
00187
00188 OBJ_FREEZE(members);
00189 if (NIL_P(name)) {
00190 nstr = rb_class_new(klass);
00191 rb_make_metaclass(nstr, RBASIC(klass)->klass);
00192 rb_class_inherited(klass, nstr);
00193 }
00194 else {
00195
00196 name = rb_str_to_str(name);
00197 id = rb_to_id(name);
00198 if (!rb_is_const_id(id)) {
00199 rb_name_error(id, "identifier %s needs to be constant", StringValuePtr(name));
00200 }
00201 if (rb_const_defined_at(klass, id)) {
00202 rb_warn("redefining constant Struct::%s", StringValuePtr(name));
00203 rb_mod_remove_const(klass, ID2SYM(id));
00204 }
00205 nstr = rb_define_class_id_under(klass, id, klass);
00206 }
00207 rb_ivar_set(nstr, id_members, members);
00208
00209 rb_define_alloc_func(nstr, struct_alloc);
00210 rb_define_singleton_method(nstr, "new", rb_class_new_instance, -1);
00211 rb_define_singleton_method(nstr, "[]", rb_class_new_instance, -1);
00212 rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0);
00213 ptr_members = RARRAY_PTR(members);
00214 len = RARRAY_LEN(members);
00215 for (i=0; i< len; i++) {
00216 ID id = SYM2ID(ptr_members[i]);
00217 if (rb_is_local_id(id) || rb_is_const_id(id)) {
00218 if (i < N_REF_FUNC) {
00219 rb_define_method_id(nstr, id, ref_func[i], 0);
00220 }
00221 else {
00222 rb_define_method_id(nstr, id, rb_struct_ref, 0);
00223 }
00224 rb_define_method_id(nstr, rb_id_attrset(id), rb_struct_set, 1);
00225 }
00226 }
00227
00228 return nstr;
00229 }
00230
00231 VALUE
00232 rb_struct_alloc_noinit(VALUE klass)
00233 {
00234 return struct_alloc(klass);
00235 }
00236
00237 VALUE
00238 rb_struct_define_without_accessor(const char *class_name, VALUE super, rb_alloc_func_t alloc, ...)
00239 {
00240 VALUE klass;
00241 va_list ar;
00242 VALUE members;
00243 long i;
00244 char *name;
00245
00246 members = rb_ary_new2(0);
00247 va_start(ar, alloc);
00248 i = 0;
00249 while ((name = va_arg(ar, char*)) != NULL) {
00250 rb_ary_push(members, ID2SYM(rb_intern(name)));
00251 }
00252 va_end(ar);
00253 OBJ_FREEZE(members);
00254
00255 if (class_name) {
00256 klass = rb_define_class(class_name, super);
00257 }
00258 else {
00259 klass = rb_class_new(super);
00260 rb_make_metaclass(klass, RBASIC(super)->klass);
00261 rb_class_inherited(super, klass);
00262 }
00263
00264 rb_ivar_set(klass, id_members, members);
00265
00266 if (alloc)
00267 rb_define_alloc_func(klass, alloc);
00268 else
00269 rb_define_alloc_func(klass, struct_alloc);
00270
00271 return klass;
00272 }
00273
00274 VALUE
00275 rb_struct_define(const char *name, ...)
00276 {
00277 va_list ar;
00278 VALUE nm, ary;
00279 char *mem;
00280
00281 if (!name) nm = Qnil;
00282 else nm = rb_str_new2(name);
00283 ary = rb_ary_new();
00284
00285 va_start(ar, name);
00286 while ((mem = va_arg(ar, char*)) != 0) {
00287 ID slot = rb_intern(mem);
00288 rb_ary_push(ary, ID2SYM(slot));
00289 }
00290 va_end(ar);
00291
00292 return make_struct(nm, ary, rb_cStruct);
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
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 (TYPE(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(st, struct RStruct);
00397 OBJSETUP(st, klass, T_STRUCT);
00398
00399 n = num_members(klass);
00400
00401 if (0 < n && n <= RSTRUCT_EMBED_LEN_MAX) {
00402 RBASIC(st)->flags &= ~RSTRUCT_EMBED_LEN_MASK;
00403 RBASIC(st)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
00404 rb_mem_clear(st->as.ary, n);
00405 }
00406 else {
00407 st->as.heap.ptr = ALLOC_N(VALUE, n);
00408 rb_mem_clear(st->as.heap.ptr, n);
00409 st->as.heap.len = n;
00410 }
00411
00412 return (VALUE)st;
00413 }
00414
00415 VALUE
00416 rb_struct_alloc(VALUE klass, VALUE values)
00417 {
00418 return rb_class_new_instance(RARRAY_LENINT(values), RARRAY_PTR(values), klass);
00419 }
00420
00421 VALUE
00422 rb_struct_new(VALUE klass, ...)
00423 {
00424 VALUE tmpargs[N_REF_FUNC], *mem = tmpargs;
00425 int size, i;
00426 va_list args;
00427
00428 size = rb_long2int(num_members(klass));
00429 if (size > numberof(tmpargs)) {
00430 tmpargs[0] = rb_ary_tmp_new(size);
00431 mem = RARRAY_PTR(tmpargs[0]);
00432 }
00433 va_start(args, klass);
00434 for (i=0; i<size; i++) {
00435 mem[i] = va_arg(args, VALUE);
00436 }
00437 va_end(args);
00438
00439 return rb_class_new_instance(size, mem, klass);
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 static VALUE
00464 rb_struct_each(VALUE s)
00465 {
00466 long i;
00467
00468 RETURN_ENUMERATOR(s, 0, 0);
00469 for (i=0; i<RSTRUCT_LEN(s); i++) {
00470 rb_yield(RSTRUCT_PTR(s)[i]);
00471 }
00472 return s;
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 static VALUE
00497 rb_struct_each_pair(VALUE s)
00498 {
00499 VALUE members;
00500 long i;
00501
00502 RETURN_ENUMERATOR(s, 0, 0);
00503 members = rb_struct_members(s);
00504 for (i=0; i<RSTRUCT_LEN(s); i++) {
00505 rb_yield_values(2, rb_ary_entry(members, i), RSTRUCT_PTR(s)[i]);
00506 }
00507 return s;
00508 }
00509
00510 static VALUE
00511 inspect_struct(VALUE s, VALUE dummy, int recur)
00512 {
00513 VALUE cname = rb_class_name(rb_obj_class(s));
00514 VALUE members, str = rb_str_new2("#<struct ");
00515 VALUE *ptr, *ptr_members;
00516 long i, len;
00517 char first = RSTRING_PTR(cname)[0];
00518
00519 if (recur || first != '#') {
00520 rb_str_append(str, cname);
00521 }
00522 if (recur) {
00523 return rb_str_cat2(str, ":...>");
00524 }
00525
00526 members = rb_struct_members(s);
00527 ptr_members = RARRAY_PTR(members);
00528 ptr = RSTRUCT_PTR(s);
00529 len = RSTRUCT_LEN(s);
00530 for (i=0; i<len; i++) {
00531 VALUE slot;
00532 ID id;
00533
00534 if (i > 0) {
00535 rb_str_cat2(str, ", ");
00536 }
00537 else if (first != '#') {
00538 rb_str_cat2(str, " ");
00539 }
00540 slot = ptr_members[i];
00541 id = SYM2ID(slot);
00542 if (rb_is_local_id(id) || rb_is_const_id(id)) {
00543 rb_str_append(str, rb_id2str(id));
00544 }
00545 else {
00546 rb_str_append(str, rb_inspect(slot));
00547 }
00548 rb_str_cat2(str, "=");
00549 rb_str_append(str, rb_inspect(ptr[i]));
00550 }
00551 rb_str_cat2(str, ">");
00552 OBJ_INFECT(str, s);
00553
00554 return str;
00555 }
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 static VALUE
00566 rb_struct_inspect(VALUE s)
00567 {
00568 return rb_exec_recursive(inspect_struct, s, 0);
00569 }
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 static VALUE
00584 rb_struct_to_a(VALUE s)
00585 {
00586 return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_PTR(s));
00587 }
00588
00589
00590 VALUE
00591 rb_struct_init_copy(VALUE copy, VALUE s)
00592 {
00593 if (copy == s) return copy;
00594 rb_check_frozen(copy);
00595 if (!rb_obj_is_instance_of(s, rb_obj_class(copy))) {
00596 rb_raise(rb_eTypeError, "wrong argument class");
00597 }
00598 if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) {
00599 rb_raise(rb_eTypeError, "struct size mismatch");
00600 }
00601 MEMCPY(RSTRUCT_PTR(copy), RSTRUCT_PTR(s), VALUE, RSTRUCT_LEN(copy));
00602
00603 return copy;
00604 }
00605
00606 static VALUE
00607 rb_struct_aref_id(VALUE s, ID id)
00608 {
00609 VALUE *ptr, members, *ptr_members;
00610 long i, len;
00611
00612 ptr = RSTRUCT_PTR(s);
00613 members = rb_struct_members(s);
00614 ptr_members = RARRAY_PTR(members);
00615 len = RARRAY_LEN(members);
00616 for (i=0; i<len; i++) {
00617 if (SYM2ID(ptr_members[i]) == id) {
00618 return ptr[i];
00619 }
00620 }
00621 rb_name_error(id, "no member '%s' in struct", rb_id2name(id));
00622 return Qnil;
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 VALUE
00645 rb_struct_aref(VALUE s, VALUE idx)
00646 {
00647 long i;
00648
00649 if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
00650 return rb_struct_aref_id(s, rb_to_id(idx));
00651 }
00652
00653 i = NUM2LONG(idx);
00654 if (i < 0) i = RSTRUCT_LEN(s) + i;
00655 if (i < 0)
00656 rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)",
00657 i, RSTRUCT_LEN(s));
00658 if (RSTRUCT_LEN(s) <= i)
00659 rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)",
00660 i, RSTRUCT_LEN(s));
00661 return RSTRUCT_PTR(s)[i];
00662 }
00663
00664 static VALUE
00665 rb_struct_aset_id(VALUE s, ID id, VALUE val)
00666 {
00667 VALUE members, *ptr, *ptr_members;
00668 long i, len;
00669
00670 members = rb_struct_members(s);
00671 len = RARRAY_LEN(members);
00672 rb_struct_modify(s);
00673 if (RSTRUCT_LEN(s) != len) {
00674 rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
00675 len, RSTRUCT_LEN(s));
00676 }
00677 ptr = RSTRUCT_PTR(s);
00678 ptr_members = RARRAY_PTR(members);
00679 for (i=0; i<len; i++) {
00680 if (SYM2ID(ptr_members[i]) == id) {
00681 ptr[i] = val;
00682 return val;
00683 }
00684 }
00685 rb_name_error(id, "no member '%s' in struct", rb_id2name(id));
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 VALUE
00710 rb_struct_aset(VALUE s, VALUE idx, VALUE val)
00711 {
00712 long i;
00713
00714 if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
00715 return rb_struct_aset_id(s, rb_to_id(idx), val);
00716 }
00717
00718 i = NUM2LONG(idx);
00719 if (i < 0) i = RSTRUCT_LEN(s) + i;
00720 if (i < 0) {
00721 rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)",
00722 i, RSTRUCT_LEN(s));
00723 }
00724 if (RSTRUCT_LEN(s) <= i) {
00725 rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)",
00726 i, RSTRUCT_LEN(s));
00727 }
00728 rb_struct_modify(s);
00729 return RSTRUCT_PTR(s)[i] = val;
00730 }
00731
00732 static VALUE
00733 struct_entry(VALUE s, long n)
00734 {
00735 return rb_struct_aref(s, LONG2NUM(n));
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 static VALUE
00755 rb_struct_values_at(int argc, VALUE *argv, VALUE s)
00756 {
00757 return rb_get_values_at(s, RSTRUCT_LEN(s), argc, argv, struct_entry);
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775 static VALUE
00776 rb_struct_select(int argc, VALUE *argv, VALUE s)
00777 {
00778 VALUE result;
00779 long i;
00780
00781 if (argc > 0) {
00782 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
00783 }
00784 RETURN_ENUMERATOR(s, 0, 0);
00785 result = rb_ary_new();
00786 for (i = 0; i < RSTRUCT_LEN(s); i++) {
00787 if (RTEST(rb_yield(RSTRUCT_PTR(s)[i]))) {
00788 rb_ary_push(result, RSTRUCT_PTR(s)[i]);
00789 }
00790 }
00791
00792 return result;
00793 }
00794
00795 static VALUE
00796 recursive_equal(VALUE s, VALUE s2, int recur)
00797 {
00798 VALUE *ptr, *ptr2;
00799 long i, len;
00800
00801 if (recur) return Qtrue;
00802 ptr = RSTRUCT_PTR(s);
00803 ptr2 = RSTRUCT_PTR(s2);
00804 len = RSTRUCT_LEN(s);
00805 for (i=0; i<len; i++) {
00806 if (!rb_equal(ptr[i], ptr2[i])) return Qfalse;
00807 }
00808 return Qtrue;
00809 }
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828 static VALUE
00829 rb_struct_equal(VALUE s, VALUE s2)
00830 {
00831 if (s == s2) return Qtrue;
00832 if (TYPE(s2) != T_STRUCT) return Qfalse;
00833 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
00834 if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
00835 rb_bug("inconsistent struct");
00836 }
00837
00838 return rb_exec_recursive_paired(recursive_equal, s, s2, s2);
00839 }
00840
00841 static VALUE
00842 recursive_hash(VALUE s, VALUE dummy, int recur)
00843 {
00844 long i, len;
00845 st_index_t h;
00846 VALUE n, *ptr;
00847
00848 h = rb_hash_start(rb_hash(rb_obj_class(s)));
00849 if (!recur) {
00850 ptr = RSTRUCT_PTR(s);
00851 len = RSTRUCT_LEN(s);
00852 for (i = 0; i < len; i++) {
00853 n = rb_hash(ptr[i]);
00854 h = rb_hash_uint(h, NUM2LONG(n));
00855 }
00856 }
00857 h = rb_hash_end(h);
00858 return INT2FIX(h);
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868 static VALUE
00869 rb_struct_hash(VALUE s)
00870 {
00871 return rb_exec_recursive_outer(recursive_hash, s, 0);
00872 }
00873
00874 static VALUE
00875 recursive_eql(VALUE s, VALUE s2, int recur)
00876 {
00877 VALUE *ptr, *ptr2;
00878 long i, len;
00879
00880 if (recur) return Qtrue;
00881 ptr = RSTRUCT_PTR(s);
00882 ptr2 = RSTRUCT_PTR(s2);
00883 len = RSTRUCT_LEN(s);
00884 for (i=0; i<len; i++) {
00885 if (!rb_eql(ptr[i], ptr2[i])) return Qfalse;
00886 }
00887 return Qtrue;
00888 }
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898 static VALUE
00899 rb_struct_eql(VALUE s, VALUE s2)
00900 {
00901 if (s == s2) return Qtrue;
00902 if (TYPE(s2) != T_STRUCT) return Qfalse;
00903 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
00904 if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
00905 rb_bug("inconsistent struct");
00906 }
00907
00908 return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
00909 }
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923 static VALUE
00924 rb_struct_size(VALUE s)
00925 {
00926 return LONG2FIX(RSTRUCT_LEN(s));
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944 void
00945 Init_Struct(void)
00946 {
00947 rb_cStruct = rb_define_class("Struct", rb_cObject);
00948 rb_include_module(rb_cStruct, rb_mEnumerable);
00949
00950 rb_undef_alloc_func(rb_cStruct);
00951 rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1);
00952
00953 rb_define_method(rb_cStruct, "initialize", rb_struct_initialize_m, -1);
00954 rb_define_method(rb_cStruct, "initialize_copy", rb_struct_init_copy, 1);
00955
00956 rb_define_method(rb_cStruct, "==", rb_struct_equal, 1);
00957 rb_define_method(rb_cStruct, "eql?", rb_struct_eql, 1);
00958 rb_define_method(rb_cStruct, "hash", rb_struct_hash, 0);
00959
00960 rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0);
00961 rb_define_alias(rb_cStruct, "to_s", "inspect");
00962 rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0);
00963 rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0);
00964 rb_define_method(rb_cStruct, "size", rb_struct_size, 0);
00965 rb_define_method(rb_cStruct, "length", rb_struct_size, 0);
00966
00967 rb_define_method(rb_cStruct, "each", rb_struct_each, 0);
00968 rb_define_method(rb_cStruct, "each_pair", rb_struct_each_pair, 0);
00969 rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1);
00970 rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2);
00971 rb_define_method(rb_cStruct, "select", rb_struct_select, -1);
00972 rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1);
00973
00974 rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0);
00975 id_members = rb_intern("__members__");
00976 }
00977