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