[macruby-changes] [3506] MacRuby/trunk/hash.c

source_changes at macosforge.org source_changes at macosforge.org
Thu Feb 11 22:01:29 PST 2010


Revision: 3506
          http://trac.macosforge.org/projects/ruby/changeset/3506
Author:   lsansonetti at apple.com
Date:     2010-02-11 22:01:26 -0800 (Thu, 11 Feb 2010)
Log Message:
-----------
Hash#compare_by_identity, #compare_by_identity?, #default_proc=: added. Hash#dup: fixed to honor subclasses. Hash#[]=: fixed to duplicate and freeze string keys

Modified Paths:
--------------
    MacRuby/trunk/hash.c

Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c	2010-02-12 04:19:12 UTC (rev 3505)
+++ MacRuby/trunk/hash.c	2010-02-12 06:01:26 UTC (rev 3506)
@@ -131,6 +131,11 @@
     rb_any_hash,
 };
 
+static const struct st_hash_type identhash = {
+    st_numcmp,
+    st_numhash,
+};
+
 static VALUE
 rhash_alloc(VALUE klass, SEL sel)
 {
@@ -149,9 +154,15 @@
 VALUE
 rhash_dup(VALUE rcv, SEL sel)
 {
+    VALUE klass = CLASS_OF(rcv);
+    while (RCLASS_SINGLETON(klass)) {
+	klass = RCLASS_SUPER(klass);
+    }
+    assert(rb_klass_is_rhash(klass));
+
     NEWOBJ(dup, rb_hash_t);
     dup->basic.flags = 0;
-    dup->basic.klass = rb_cRubyHash;
+    dup->basic.klass = klass;
     GC_WB(&dup->tbl, st_copy(RHASH(rcv)->tbl));
     GC_WB(&dup->ifnone, RHASH(rcv)->ifnone);
     dup->has_proc_default = RHASH(rcv)->has_proc_default;
@@ -559,6 +570,46 @@
 
 /*
  *  call-seq:
+ *     hsh.default_proc = proc_obj     => proc_obj
+ *
+ *  Sets the default proc to be executed on each key lookup.
+ *
+ *     h.default_proc = proc do |hash, key|
+ *       hash[key] = key + key
+ *     end
+ *     h[2]       #=> 4
+ *     h["cat"]   #=> "catcat"
+ */
+
+static void
+default_proc_arity_check(VALUE proc)
+{
+    const int arity = rb_proc_arity(proc);
+    if (arity != 0 && arity != 2) {
+	rb_raise(rb_eTypeError, "expected Proc with 2 arguments (but got %d)",
+		arity);
+    }
+}
+
+static VALUE
+rhash_set_default_proc(VALUE hash, SEL sel, VALUE proc)
+{
+    rhash_modify(hash);
+    VALUE tmp = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
+    if (NIL_P(tmp)) {
+        rb_raise(rb_eTypeError,
+		"wrong default_proc type %s (expected Proc)",
+		rb_obj_classname(proc));
+    }
+    proc = tmp;
+    default_proc_arity_check(proc);
+    GC_WB(&RHASH(hash)->ifnone, proc);
+    RHASH(hash)->has_proc_default = true;
+    return proc;
+}
+
+/*
+ *  call-seq:
  *     hsh.key(value)    => key
  *
  *  Returns the key for a given value. If not found, returns <code>nil</code>.
@@ -656,9 +707,9 @@
 rhash_shift(VALUE hash, SEL sel)
 {
     VALUE args[2] = {0, 0};
+    rhash_modify(hash);
     rhash_foreach(hash, shift_i, (st_data_t)args);
     if (args[0] != 0 && args[1] != 0) {
-	rhash_modify(hash);
 	rhash_delete_key(hash, args[0]);
 	return rb_assoc_new(args[0], args[1]);
     }
@@ -836,6 +887,10 @@
 rhash_aset(VALUE hash, SEL sel, VALUE key, VALUE val)
 {
     rhash_modify(hash);
+    if (TYPE(key) == T_STRING) {
+	key = rb_str_dup(key);
+	OBJ_FREEZE(key);
+    }
     st_insert(RHASH(hash)->tbl, key, val);
     return val;
 }
@@ -1420,6 +1475,7 @@
 rhash_update(VALUE hash1, SEL sel, VALUE hash2)
 {
     hash2 = to_hash(hash2);
+    rhash_modify(hash1);
     if (rb_block_given_p()) {
 	rb_hash_foreach(hash2, update_block_i, hash1);
     }
@@ -1567,7 +1623,8 @@
 rhash_compare_by_id(VALUE hash, SEL sel)
 {
     rhash_modify(hash);
-    // TODO
+    RHASH(hash)->tbl->type = &identhash;
+    rhash_rehash(hash, 0);
     return hash;
 }
 
@@ -1583,8 +1640,7 @@
 static VALUE
 rhash_compare_by_id_p(VALUE hash, SEL sel)
 {
-    // TODO
-    return Qfalse;
+    return RHASH(hash)->tbl->type == &identhash ? Qtrue : Qfalse;
 }
 
 bool
@@ -1730,6 +1786,8 @@
     rb_objc_define_method(rb_cRubyHash, "default=", rhash_set_default, 1);
     rb_objc_define_method(rb_cRubyHash, "default_proc",
 	    rhash_default_proc, 0);
+    rb_objc_define_method(rb_cRubyHash, "default_proc=",
+	    rhash_set_default_proc, 1);
     rb_objc_define_method(rb_cRubyHash, "key", rhash_key, 1);
     rb_objc_define_method(rb_cRubyHash, "index", rhash_index, 1);
     rb_objc_define_method(rb_cRubyHash, "size", rhash_size, 0);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100211/a6315604/attachment.html>


More information about the macruby-changes mailing list