--- ../ruby-1.6.2/hash.c Tue Sep 12 01:37:23 2000 +++ hash.c Mon Oct 30 21:25:28 2000 @@ -18,6 +18,7 @@ #include "rubysig.h" #define HASH_DELETED FL_USER1 +#define HASH_HASPROC FL_USER2 static void rb_hash_modify(hash) @@ -201,11 +202,17 @@ VALUE *argv; VALUE hash; { - VALUE ifnone; + VALUE ifnone, ifnone_proc; - rb_scan_args(argc, argv, "01", &ifnone); + rb_scan_args(argc, argv, "01&", &ifnone, &ifnone_proc); rb_hash_modify(hash); - RHASH(hash)->ifnone = ifnone; + if (ifnone_proc != Qnil) { + FL_SET(hash, HASH_HASPROC); + RHASH(hash)->ifnone = ifnone_proc; + } else { + FL_UNSET(hash, HASH_HASPROC); + RHASH(hash)->ifnone = ifnone; + } return hash; } @@ -284,6 +291,15 @@ return hash; } +static VALUE +rb_hash_get_default(hash) + VALUE hash; +{ + if (FL_TEST(hash, HASH_HASPROC)) + return rb_funcall(RHASH(hash)->ifnone, rb_intern("call"), 0); + return RHASH(hash)->ifnone; +} + VALUE rb_hash_aref(hash, key) VALUE hash, key; @@ -291,7 +307,9 @@ VALUE val; if (!st_lookup(RHASH(hash)->tbl, key, &val)) { - return RHASH(hash)->ifnone; + if (FL_TEST(hash, HASH_HASPROC)) + return rb_hash_aset(hash, key, rb_hash_get_default(hash)); + return rb_hash_get_default(hash); } return val; } @@ -330,13 +348,43 @@ } static VALUE +rb_hash_default_proc(argc, argv, hash) + int argc; + VALUE *argv; + VALUE hash; +{ + VALUE ifnone_proc; + + rb_scan_args(argc, argv, "0&", &ifnone_proc); + if (ifnone_proc != Qnil) { + FL_SET(hash, HASH_HASPROC); + RHASH(hash)->ifnone = ifnone_proc; + return Qtrue; + } + return FL_TEST(hash, HASH_HASPROC) ? Qtrue : Qfalse; +} + +static VALUE rb_hash_set_default(hash, ifnone) VALUE hash, ifnone; { + FL_UNSET(hash, HASH_HASPROC); RHASH(hash)->ifnone = ifnone; return hash; } +static VALUE +rb_hash_set_default_proc(hash, value) + VALUE hash, value; +{ + if (value == Qtrue) { + FL_SET(hash, HASH_HASPROC); + return Qtrue; + } + FL_UNSET(hash, HASH_HASPROC); + return Qfalse; +} + static int index_i(key, value, args) VALUE key, value; @@ -356,7 +404,7 @@ VALUE args[2]; args[0] = value; - args[1] = RHASH(hash)->ifnone; + args[1] = rb_hash_get_default(hash); st_foreach(RHASH(hash)->tbl, index_i, args); @@ -398,7 +446,7 @@ if (rb_block_given_p()) { return rb_yield(key); } - return RHASH(hash)->ifnone; + return rb_hash_get_default(hash); } struct shift_var { @@ -430,7 +478,8 @@ var.stop = 0; st_foreach(RHASH(hash)->tbl, shift_i, &var); - if (var.stop == 0) return RHASH(hash)->ifnone; + if (var.stop == 0) + return rb_hash_get_default(hash); return rb_assoc_new(var.key, var.val); } @@ -1422,6 +1471,8 @@ rb_define_method(rb_cHash,"store", rb_hash_aset, 2); rb_define_method(rb_cHash,"default", rb_hash_default, 0); rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1); + rb_define_method(rb_cHash,"default_proc", rb_hash_default_proc, -1); + rb_define_method(rb_cHash,"default_proc=", rb_hash_set_default_proc, 1); rb_define_method(rb_cHash,"index", rb_hash_index, 1); rb_define_method(rb_cHash,"indexes", rb_hash_indexes, -1); rb_define_method(rb_cHash,"indices", rb_hash_indexes, -1);