lucy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nwelln...@apache.org
Subject [3/3] lucy-clownfish git commit: String-only keys for Hash
Date Thu, 16 Apr 2015 19:22:52 GMT
String-only keys for Hash

This commit changes the Hash tombstone to be a String object. Care must
be taken to

- never incref of decref the tombstone object. This could happen during
  Clean.
- check for the tombstone when looking up entries.

Fixes CLOWNFISH-7.


Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/8282412f
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/8282412f
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/8282412f

Branch: refs/heads/master
Commit: 8282412f06a8e48ebdd7957e380ac46f4090ad40
Parents: 93f0dee
Author: Nick Wellnhofer <wellnhofer@aevum.de>
Authored: Tue Apr 14 12:57:44 2015 +0200
Committer: Nick Wellnhofer <wellnhofer@aevum.de>
Committed: Wed Apr 15 15:35:26 2015 +0200

----------------------------------------------------------------------
 runtime/c/src/Clownfish/Obj.c                   |  1 -
 runtime/core/Clownfish/Class.c                  |  5 +-
 runtime/core/Clownfish/Hash.c                   | 74 +++++++++++---------
 runtime/core/Clownfish/Hash.cfh                 | 30 +++-----
 runtime/core/Clownfish/HashIterator.c           | 11 +--
 runtime/core/Clownfish/HashIterator.cfh         |  2 +-
 runtime/core/Clownfish/Test/TestHash.c          | 48 ++++++-------
 runtime/core/Clownfish/Test/TestHashIterator.c  | 18 ++---
 runtime/go/ext/clownfish.c                      |  1 -
 .../perl/buildlib/Clownfish/Build/Binding.pm    | 10 +--
 runtime/perl/xs/XSBind.c                        | 23 +++---
 11 files changed, 106 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/c/src/Clownfish/Obj.c
----------------------------------------------------------------------
diff --git a/runtime/c/src/Clownfish/Obj.c b/runtime/c/src/Clownfish/Obj.c
index 3db144f..f0bad24 100644
--- a/runtime/c/src/Clownfish/Obj.c
+++ b/runtime/c/src/Clownfish/Obj.c
@@ -30,7 +30,6 @@ SI_immortal(cfish_Class *klass) {
     if (klass == CFISH_CLASS
         || klass == CFISH_METHOD
         || klass == CFISH_BOOLNUM
-        || klass == CFISH_HASHTOMBSTONE
        ){
         return true;
     }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/Class.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c
index 6e87e49..284e57d 100644
--- a/runtime/core/Clownfish/Class.c
+++ b/runtime/core/Clownfish/Class.c
@@ -100,7 +100,6 @@ Class_bootstrap(const ClassSpec *specs, size_t num_specs)
         if (spec->klass == &CLASS
             || spec->klass == &METHOD
             || spec->klass == &BOOLNUM
-            || spec->klass == &HASHTOMBSTONE
             || spec->klass == &STRING
             || spec->klass == &STACKSTRING
             || spec->klass == &LOCKFREEREGISTRY
@@ -284,14 +283,14 @@ Class_singleton(String *class_name, Class *parent) {
             Hash *meths = Hash_new(num_fresh);
             for (uint32_t i = 0; i < num_fresh; i++) {
                 String *meth = (String*)VA_Fetch(fresh_host_methods, i);
-                Hash_Store(meths, (Obj*)meth, (Obj*)CFISH_TRUE);
+                Hash_Store(meths, meth, (Obj*)CFISH_TRUE);
             }
             for (Class *klass = parent; klass; klass = klass->parent) {
                 for (size_t i = 0; klass->methods[i]; i++) {
                     Method *method = klass->methods[i];
                     if (method->callback_func) {
                         String *name = Method_Host_Name(method);
-                        if (Hash_Fetch(meths, (Obj*)name)) {
+                        if (Hash_Fetch(meths, name)) {
                             Class_Override(singleton, method->callback_func,
                                             method->offset);
                         }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/Hash.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Hash.c b/runtime/core/Clownfish/Hash.c
index c46b9ea..53a2e49 100644
--- a/runtime/core/Clownfish/Hash.c
+++ b/runtime/core/Clownfish/Hash.c
@@ -15,7 +15,6 @@
  */
 
 #define C_CFISH_HASH
-#define C_CFISH_HASHTOMBSTONE
 #define CFISH_USE_SHORT_NAMES
 
 #include <string.h>
@@ -29,12 +28,14 @@
 #include "Clownfish/VArray.h"
 #include "Clownfish/Util/Memory.h"
 
-static HashTombStone *TOMBSTONE;
+// TOMBSTONE is shared across threads, so it must never be incref'd or
+// decref'd.
+static String *TOMBSTONE;
 
 #define HashEntry cfish_HashEntry
 
 typedef struct HashEntry {
-    Obj     *key;
+    String  *key;
     Obj     *value;
     int32_t  hash_sum;
 } HashEntry;
@@ -45,7 +46,7 @@ SI_kill_iter(Hash *self);
 
 // Return the entry associated with the key, if any.
 static CFISH_INLINE HashEntry*
-SI_fetch_entry(Hash *self, Obj *key, int32_t hash_sum);
+SI_fetch_entry(Hash *self, String *key, int32_t hash_sum);
 
 // Double the number of buckets and redistribute all entries.
 static CFISH_INLINE HashEntry*
@@ -53,7 +54,7 @@ SI_rebuild_hash(Hash *self);
 
 void
 Hash_init_class() {
-    TOMBSTONE = (HashTombStone*)Class_Make_Obj(HASHTOMBSTONE);
+    TOMBSTONE = Str_newf("[HASHTOMBSTONE]");
 }
 
 Hash*
@@ -104,6 +105,10 @@ Hash_Clear_IMP(Hash *self) {
     // Iterate through all entries.
     for (; entry < limit; entry++) {
         if (!entry->key) { continue; }
+        if (entry->key == TOMBSTONE) {
+            entry->key = NULL;
+            continue;
+        }
         DECREF(entry->key);
         DECREF(entry->value);
         entry->key       = NULL;
@@ -117,7 +122,7 @@ Hash_Clear_IMP(Hash *self) {
 }
 
 void
-Hash_do_store(Hash *self, Obj *key, Obj *value,
+Hash_do_store(Hash *self, String *key, Obj *value,
               int32_t hash_sum, bool use_this_key) {
     HashEntry *entry = SI_fetch_entry(self, key, hash_sum);
     if (entry) {
@@ -135,8 +140,8 @@ Hash_do_store(Hash *self, Obj *key, Obj *value,
     while (1) {
         tick &= mask;
         HashEntry *entry = entries + tick;
-        if (entry->key == (Obj*)TOMBSTONE || !entry->key) {
-            if (entry->key == (Obj*)TOMBSTONE) {
+        if (entry->key == TOMBSTONE || !entry->key) {
+            if (entry->key == TOMBSTONE) {
                 // Take note of diminished tombstone clutter.
                 self->threshold++;
             }
@@ -153,32 +158,32 @@ Hash_do_store(Hash *self, Obj *key, Obj *value,
 }
 
 void
-Hash_Store_IMP(Hash *self, Obj *key, Obj *value) {
-    Hash_do_store(self, key, value, Obj_Hash_Sum(key), false);
+Hash_Store_IMP(Hash *self, String *key, Obj *value) {
+    Hash_do_store(self, key, value, Str_Hash_Sum(key), false);
 }
 
 void
 Hash_Store_Utf8_IMP(Hash *self, const char *key, size_t key_len, Obj *value) {
     StackString *key_buf = SSTR_WRAP_UTF8((char*)key, key_len);
-    Hash_do_store(self, (Obj*)key_buf, value,
+    Hash_do_store(self, (String*)key_buf, value,
                   SStr_Hash_Sum(key_buf), false);
 }
 
-Obj*
-Hash_Make_Key_IMP(Hash *self, Obj *key, int32_t hash_sum) {
+String*
+Hash_Make_Key_IMP(Hash *self, String *key, int32_t hash_sum) {
     UNUSED_VAR(self);
     UNUSED_VAR(hash_sum);
-    return Obj_Clone(key);
+    return Str_Clone(key);
 }
 
 Obj*
 Hash_Fetch_Utf8_IMP(Hash *self, const char *key, size_t key_len) {
     StackString *key_buf = SSTR_WRAP_UTF8(key, key_len);
-    return Hash_Fetch_IMP(self, (Obj*)key_buf);
+    return Hash_Fetch_IMP(self, (String*)key_buf);
 }
 
 static CFISH_INLINE HashEntry*
-SI_fetch_entry(Hash *self, Obj *key, int32_t hash_sum) {
+SI_fetch_entry(Hash *self, String *key, int32_t hash_sum) {
     uint32_t tick = hash_sum;
     HashEntry *const entries = (HashEntry*)self->entries;
     HashEntry *entry;
@@ -191,7 +196,8 @@ SI_fetch_entry(Hash *self, Obj *key, int32_t hash_sum) {
             return NULL;
         }
         else if (entry->hash_sum == hash_sum
-                 && Obj_Equals(key, entry->key)
+                 && entry->key != TOMBSTONE
+                 && Str_Equals(key, (Obj*)entry->key)
                 ) {
             return entry;
         }
@@ -200,18 +206,18 @@ SI_fetch_entry(Hash *self, Obj *key, int32_t hash_sum) {
 }
 
 Obj*
-Hash_Fetch_IMP(Hash *self, Obj *key) {
-    HashEntry *entry = SI_fetch_entry(self, key, Obj_Hash_Sum(key));
+Hash_Fetch_IMP(Hash *self, String *key) {
+    HashEntry *entry = SI_fetch_entry(self, key, Str_Hash_Sum(key));
     return entry ? entry->value : NULL;
 }
 
 Obj*
-Hash_Delete_IMP(Hash *self, Obj *key) {
-    HashEntry *entry = SI_fetch_entry(self, key, Obj_Hash_Sum(key));
+Hash_Delete_IMP(Hash *self, String *key) {
+    HashEntry *entry = SI_fetch_entry(self, key, Str_Hash_Sum(key));
     if (entry) {
         Obj *value = entry->value;
         DECREF(entry->key);
-        entry->key       = (Obj*)TOMBSTONE;
+        entry->key       = TOMBSTONE;
         entry->value     = NULL;
         entry->hash_sum  = 0;
         self->size--;
@@ -226,7 +232,7 @@ Hash_Delete_IMP(Hash *self, Obj *key) {
 Obj*
 Hash_Delete_Utf8_IMP(Hash *self, const char *key, size_t key_len) {
     StackString *key_buf = SSTR_WRAP_UTF8(key, key_len);
-    return Hash_Delete_IMP(self, (Obj*)key_buf);
+    return Hash_Delete_IMP(self, (String*)key_buf);
 }
 
 uint32_t
@@ -241,7 +247,7 @@ SI_kill_iter(Hash *self) {
 }
 
 bool
-Hash_Next_IMP(Hash *self, Obj **key, Obj **value) {
+Hash_Next_IMP(Hash *self, String **key, Obj **value) {
     while (1) {
         if (++self->iter_tick >= (int32_t)self->capacity) {
             // Bail since we've completed the iteration.
@@ -253,7 +259,7 @@ Hash_Next_IMP(Hash *self, Obj **key, Obj **value) {
         else {
             HashEntry *const entry
                 = (HashEntry*)self->entries + self->iter_tick;
-            if (entry->key && entry->key != (Obj*)TOMBSTONE) {
+            if (entry->key && entry->key != TOMBSTONE) {
                 // Success!
                 *key   = entry->key;
                 *value = entry->value;
@@ -263,16 +269,16 @@ Hash_Next_IMP(Hash *self, Obj **key, Obj **value) {
     }
 }
 
-Obj*
-Hash_Find_Key_IMP(Hash *self, Obj *key, int32_t hash_sum) {
+String*
+Hash_Find_Key_IMP(Hash *self, String *key, int32_t hash_sum) {
     HashEntry *entry = SI_fetch_entry(self, key, hash_sum);
     return entry ? entry->key : NULL;
 }
 
 VArray*
 Hash_Keys_IMP(Hash *self) {
-    Obj *key;
-    Obj *val;
+    String *key;
+    Obj    *val;
     VArray *keys = VA_new(self->size);
     Hash_Iterate(self);
     while (Hash_Next(self, &key, &val)) {
@@ -283,8 +289,8 @@ Hash_Keys_IMP(Hash *self) {
 
 VArray*
 Hash_Values_IMP(Hash *self) {
-    Obj *key;
-    Obj *val;
+    String *key;
+    Obj    *val;
     VArray *values = VA_new(self->size);
     Hash_Iterate(self);
     while (Hash_Next(self, &key, &val)) { VA_Push(values, INCREF(val)); }
@@ -294,7 +300,7 @@ Hash_Values_IMP(Hash *self) {
 bool
 Hash_Equals_IMP(Hash *self, Obj *other) {
     Hash    *twin = (Hash*)other;
-    Obj     *key;
+    String  *key;
     Obj     *val;
 
     if (twin == self)             { return true; }
@@ -338,7 +344,7 @@ SI_rebuild_hash(Hash *self) {
     self->size      = 0;
 
     for (; entry < limit; entry++) {
-        if (!entry->key || entry->key == (Obj*)TOMBSTONE) {
+        if (!entry->key || entry->key == TOMBSTONE) {
             continue;
         }
         Hash_do_store(self, entry->key, entry->value,
@@ -350,7 +356,7 @@ SI_rebuild_hash(Hash *self) {
     return (HashEntry*)self->entries;
 }
 
-HashTombStone*
+String*
 Hash_get_tombstone() {
     return TOMBSTONE;
 }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/Hash.cfh
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Hash.cfh b/runtime/core/Clownfish/Hash.cfh
index cb65921..c33b010 100644
--- a/runtime/core/Clownfish/Hash.cfh
+++ b/runtime/core/Clownfish/Hash.cfh
@@ -19,10 +19,7 @@ parcel Clownfish;
 /**
  * Hashtable.
  *
- * Values are stored by reference and may be any kind of Obj. By default, keys
- * are cloned and so must belong to a class that implements [](cfish:Obj.Clone); however,
- * this behavior can be changed by overridding [](cfish:.Make_Key), e.g. to implement
- * efficient hash sets.
+ * Values are stored by reference and may be any kind of Obj.
  */
 class Clownfish::Hash inherits Clownfish::Obj {
 
@@ -45,7 +42,7 @@ class Clownfish::Hash inherits Clownfish::Obj {
     inert Hash*
     init(Hash *self, uint32_t capacity = 0);
 
-    inert HashTombStone*
+    inert String*
     get_tombstone();
 
     /** Empty the hash of all key-value pairs.
@@ -53,11 +50,10 @@ class Clownfish::Hash inherits Clownfish::Obj {
     void
     Clear(Hash *self);
 
-    /** Store a key-value pair.  If `key` is not already present,
-     * [](cfish:.Make_Key) will be called to manufacture the internally used key.
+    /** Store a key-value pair.
      */
     void
-    Store(Hash *self, Obj *key, decremented Obj *value);
+    Store(Hash *self, String *key, decremented Obj *value);
 
     void
     Store_Utf8(Hash *self, const char *str, size_t len,
@@ -68,7 +64,7 @@ class Clownfish::Hash inherits Clownfish::Obj {
      * @return the value, or NULL if `key` is not present.
      */
     nullable Obj*
-    Fetch(Hash *self, Obj *key);
+    Fetch(Hash *self, String *key);
 
     nullable Obj*
     Fetch_Utf8(Hash *self, const char *key, size_t key_len);
@@ -79,7 +75,7 @@ class Clownfish::Hash inherits Clownfish::Obj {
      * succeeds; otherwise NULL.
      */
     incremented nullable Obj*
-    Delete(Hash *self, Obj *key);
+    Delete(Hash *self, String *key);
 
     incremented nullable Obj*
     Delete_Utf8(Hash *self, const char *key, size_t key_ley);
@@ -98,13 +94,13 @@ class Clownfish::Hash inherits Clownfish::Obj {
      * exhausted.
      */
     bool
-    Next(Hash *self, Obj **key, Obj **value);
+    Next(Hash *self, String **key, Obj **value);
 
     /** Search for a key which Equals the key supplied, and return the key
      * rather than its value.
      */
-    nullable Obj*
-    Find_Key(Hash *self, Obj *key, int32_t hash_sum);
+    nullable String*
+    Find_Key(Hash *self, String *key, int32_t hash_sum);
 
     /** Return an VArray of pointers to the hash's keys.
      */
@@ -120,8 +116,8 @@ class Clownfish::Hash inherits Clownfish::Obj {
      * supply an object which produces the same [](cfish:Obj.Hash_Sum) value and tests
      * true for [](cfish:Obj.Equals).  By default, calls [](cfish:Obj.Clone).
      */
-    public incremented Obj*
-    Make_Key(Hash *self, Obj *key, int32_t hash_sum);
+    public incremented String*
+    Make_Key(Hash *self, String *key, int32_t hash_sum);
 
     uint32_t
     Get_Capacity(Hash *self);
@@ -140,8 +136,4 @@ class Clownfish::Hash inherits Clownfish::Obj {
     Destroy(Hash *self);
 }
 
-class Clownfish::Hash::HashTombStone
-    inherits Clownfish::Obj {
-}
-
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/HashIterator.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/HashIterator.c b/runtime/core/Clownfish/HashIterator.c
index 9f5b599..ee31066 100644
--- a/runtime/core/Clownfish/HashIterator.c
+++ b/runtime/core/Clownfish/HashIterator.c
@@ -20,14 +20,15 @@
 
 #include "Clownfish/Class.h"
 #include "Clownfish/Err.h"
+#include "Clownfish/String.h"
 
 #include "Clownfish/Hash.h"
 #include "Clownfish/HashIterator.h"
 
-static HashTombStone *TOMBSTONE;
+static String *TOMBSTONE;
 
 typedef struct HashEntry {
-    Obj     *key;
+    String  *key;
     Obj     *value;
     int32_t  hash_sum;
 } HashEntry;
@@ -68,7 +69,7 @@ HashIter_Next_IMP(HashIterator *self) {
         else {
             HashEntry *const entry
                 = (HashEntry*)self->hash->entries + self->tick;
-            if (entry->key && entry->key != (Obj*)TOMBSTONE) {
+            if (entry->key && entry->key != TOMBSTONE) {
                 // Success.
                 return true;
             }
@@ -76,7 +77,7 @@ HashIter_Next_IMP(HashIterator *self) {
     }
 }
 
-Obj*
+String*
 HashIter_Get_Key_IMP(HashIterator *self) {
     if (self->capacity != self->hash->capacity) {
         THROW(ERR, "Hash modified during iteration.");
@@ -90,7 +91,7 @@ HashIter_Get_Key_IMP(HashIterator *self) {
 
     HashEntry *const entry
         = (HashEntry*)self->hash->entries + self->tick;
-    if (entry->key == (Obj*)TOMBSTONE) {
+    if (entry->key == TOMBSTONE) {
         THROW(ERR, "Hash modified during iteration.");
     }
     return entry->key;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/HashIterator.cfh
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/HashIterator.cfh b/runtime/core/Clownfish/HashIterator.cfh
index 3e9e1f1..0e51273 100644
--- a/runtime/core/Clownfish/HashIterator.cfh
+++ b/runtime/core/Clownfish/HashIterator.cfh
@@ -37,7 +37,7 @@ class Clownfish::HashIterator nickname HashIter inherits Clownfish::Obj
{
     public bool
     Next(HashIterator *self);
 
-    public Obj*
+    public String*
     Get_Key(HashIterator *self);
 
     public nullable Obj*

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/Test/TestHash.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Test/TestHash.c b/runtime/core/Clownfish/Test/TestHash.c
index 9d14e1d..1bb7682 100644
--- a/runtime/core/Clownfish/Test/TestHash.c
+++ b/runtime/core/Clownfish/Test/TestHash.c
@@ -74,8 +74,8 @@ test_Store_and_Fetch(TestBatchRunner *runner) {
 
     for (int32_t i = 0; i < 100; i++) {
         String *str = Str_newf("%i32", i);
-        Hash_Store(hash, (Obj*)str, (Obj*)str);
-        Hash_Store(dupe, (Obj*)str, INCREF(str));
+        Hash_Store(hash, str, (Obj*)str);
+        Hash_Store(dupe, str, INCREF(str));
         VA_Push(expected, INCREF(str));
     }
     TEST_TRUE(runner, Hash_Equals(hash, (Obj*)dupe), "Equals");
@@ -84,8 +84,8 @@ test_Store_and_Fetch(TestBatchRunner *runner) {
                 "Initial capacity sufficient (no rebuilds)");
 
     for (int32_t i = 0; i < 100; i++) {
-        Obj *key  = VA_Fetch(expected, i);
-        Obj *elem = Hash_Fetch(hash, key);
+        String *key  = (String*)VA_Fetch(expected, i);
+        Obj    *elem = Hash_Fetch(hash, key);
         VA_Push(got, (Obj*)INCREF(elem));
     }
 
@@ -94,32 +94,32 @@ test_Store_and_Fetch(TestBatchRunner *runner) {
     TEST_INT_EQ(runner, Hash_Get_Size(hash), 100,
                 "size incremented properly by Hash_Store");
 
-    TEST_TRUE(runner, Hash_Fetch(hash, (Obj*)foo) == NULL,
+    TEST_TRUE(runner, Hash_Fetch(hash, (String*)foo) == NULL,
               "Fetch against non-existent key returns NULL");
 
     Obj *stored_foo = INCREF(foo);
-    Hash_Store(hash, (Obj*)forty, stored_foo);
-    TEST_TRUE(runner, SStr_Equals(foo, Hash_Fetch(hash, (Obj*)forty)),
+    Hash_Store(hash, (String*)forty, stored_foo);
+    TEST_TRUE(runner, SStr_Equals(foo, Hash_Fetch(hash, (String*)forty)),
               "Hash_Store replaces existing value");
     TEST_FALSE(runner, Hash_Equals(hash, (Obj*)dupe),
                "replacement value spoils equals");
     TEST_INT_EQ(runner, Hash_Get_Size(hash), 100,
                 "size unaffected after value replaced");
 
-    TEST_TRUE(runner, Hash_Delete(hash, (Obj*)forty) == stored_foo,
+    TEST_TRUE(runner, Hash_Delete(hash, (String*)forty) == stored_foo,
               "Delete returns value");
     DECREF(stored_foo);
     TEST_INT_EQ(runner, Hash_Get_Size(hash), 99,
                 "size decremented by successful Delete");
-    TEST_TRUE(runner, Hash_Delete(hash, (Obj*)forty) == NULL,
+    TEST_TRUE(runner, Hash_Delete(hash, (String*)forty) == NULL,
               "Delete returns NULL when key not found");
     TEST_INT_EQ(runner, Hash_Get_Size(hash), 99,
                 "size not decremented by unsuccessful Delete");
-    DECREF(Hash_Delete(dupe, (Obj*)forty));
+    DECREF(Hash_Delete(dupe, (String*)forty));
     TEST_TRUE(runner, VA_Equals(got, (Obj*)expected), "Equals after Delete");
 
     Hash_Clear(hash);
-    TEST_TRUE(runner, Hash_Fetch(hash, (Obj*)twenty) == NULL, "Clear");
+    TEST_TRUE(runner, Hash_Fetch(hash, (String*)twenty) == NULL, "Clear");
     TEST_TRUE(runner, Hash_Get_Size(hash) == 0, "size is 0 after Clear");
 
     DECREF(hash);
@@ -137,7 +137,7 @@ test_Keys_Values_Iter(TestBatchRunner *runner) {
 
     for (uint32_t i = 0; i < 500; i++) {
         String *str = Str_newf("%u32", i);
-        Hash_Store(hash, (Obj*)str, (Obj*)str);
+        Hash_Store(hash, str, (Obj*)str);
         VA_Push(expected, INCREF(str));
     }
 
@@ -153,8 +153,8 @@ test_Keys_Values_Iter(TestBatchRunner *runner) {
     VA_Clear(values);
 
     {
-        Obj *key;
-        Obj *value;
+        String *key;
+        Obj    *value;
         Hash_Iterate(hash);
         while (Hash_Next(hash, &key, &value)) {
             VA_Push(keys, INCREF(key));
@@ -170,9 +170,9 @@ test_Keys_Values_Iter(TestBatchRunner *runner) {
     {
         StackString *forty = SSTR_WRAP_UTF8("40", 2);
         StackString *nope  = SSTR_WRAP_UTF8("nope", 4);
-        Obj *key = Hash_Find_Key(hash, (Obj*)forty, SStr_Hash_Sum(forty));
-        TEST_TRUE(runner, Obj_Equals(key, (Obj*)forty), "Find_Key");
-        key = Hash_Find_Key(hash, (Obj*)nope, SStr_Hash_Sum(nope)),
+        String *key = Hash_Find_Key(hash, (String*)forty, SStr_Hash_Sum(forty));
+        TEST_TRUE(runner, Str_Equals(key, (Obj*)forty), "Find_Key");
+        key = Hash_Find_Key(hash, (String*)nope, SStr_Hash_Sum(nope)),
         TEST_TRUE(runner, key == NULL,
                   "Find_Key returns NULL for non-existent key");
     }
@@ -192,11 +192,11 @@ test_stress(TestBatchRunner *runner) {
 
     for (uint32_t i = 0; i < 1000; i++) {
         String *str = TestUtils_random_string(rand() % 1200);
-        while (Hash_Fetch(hash, (Obj*)str)) {
+        while (Hash_Fetch(hash, str)) {
             DECREF(str);
             str = TestUtils_random_string(rand() % 1200);
         }
-        Hash_Store(hash, (Obj*)str, (Obj*)str);
+        Hash_Store(hash, str, (Obj*)str);
         VA_Push(expected, INCREF(str));
     }
 
@@ -205,7 +205,7 @@ test_stress(TestBatchRunner *runner) {
     // Overwrite for good measure.
     for (uint32_t i = 0; i < 1000; i++) {
         String *str = (String*)VA_Fetch(expected, i);
-        Hash_Store(hash, (Obj*)str, INCREF(str));
+        Hash_Store(hash, str, INCREF(str));
     }
 
     keys   = Hash_Keys(hash);
@@ -240,10 +240,10 @@ test_store_skips_tombstone(TestBatchRunner *runner) {
         two = NULL;
     }
 
-    Hash_Store(hash, (Obj*)one, (Obj*)CFISH_TRUE);
-    Hash_Store(hash, (Obj*)two, (Obj*)CFISH_TRUE);
-    Hash_Delete(hash, (Obj*)one);
-    Hash_Store(hash, (Obj*)two, (Obj*)CFISH_TRUE);
+    Hash_Store(hash, one, (Obj*)CFISH_TRUE);
+    Hash_Store(hash, two, (Obj*)CFISH_TRUE);
+    Hash_Delete(hash, one);
+    Hash_Store(hash, two, (Obj*)CFISH_TRUE);
 
     TEST_INT_EQ(runner, Hash_Get_Size(hash), 1, "Store skips tombstone");
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/core/Clownfish/Test/TestHashIterator.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Test/TestHashIterator.c b/runtime/core/Clownfish/Test/TestHashIterator.c
index 4d73f9a..6031c68 100644
--- a/runtime/core/Clownfish/Test/TestHashIterator.c
+++ b/runtime/core/Clownfish/Test/TestHashIterator.c
@@ -46,7 +46,7 @@ test_Next(TestBatchRunner *runner) {
 
     for (uint32_t i = 0; i < 500; i++) {
         String *str = Str_newf("%u32", i);
-        Hash_Store(hash, (Obj*)str, (Obj*)str);
+        Hash_Store(hash, str, (Obj*)str);
         VA_Push(expected, INCREF(str));
     }
 
@@ -55,7 +55,7 @@ test_Next(TestBatchRunner *runner) {
     {
         HashIterator *iter = HashIter_new(hash);
         while (HashIter_Next(iter)) {
-            Obj *key = HashIter_Get_Key(iter);
+            String *key = HashIter_Get_Key(iter);
             Obj *value = HashIter_Get_Value(iter);
             VA_Push(keys, INCREF(key));
             VA_Push(values, INCREF(value));
@@ -121,7 +121,7 @@ static void
 test_Get_Key_and_Get_Value(TestBatchRunner *runner) {
     Hash   *hash = Hash_new(0);
     String *str  = Str_newf("foo");
-    Hash_Store(hash, (Obj*)str, (Obj*)str);
+    Hash_Store(hash, str, (Obj*)str);
 
     HashIterator *iter = HashIter_new(hash);
     DECREF(hash);
@@ -159,7 +159,7 @@ test_illegal_modification(TestBatchRunner *runner) {
 
     for (uint32_t i = 0; i < 3; i++) {
         String *str = Str_newf("%u32", i);
-        Hash_Store(hash, (Obj*)str, (Obj*)str);
+        Hash_Store(hash, str, (Obj*)str);
     }
 
     HashIterator *iter = HashIter_new(hash);
@@ -167,7 +167,7 @@ test_illegal_modification(TestBatchRunner *runner) {
 
     for (uint32_t i = 0; i < 100; i++) {
         String *str = Str_newf("foo %u32", i);
-        Hash_Store(hash, (Obj*)str, (Obj*)str);
+        Hash_Store(hash, str, (Obj*)str);
     }
 
     Err *next_error = Err_trap(S_invoke_Next, iter);
@@ -194,8 +194,8 @@ test_tombstone(TestBatchRunner *runner) {
     {
         Hash   *hash = Hash_new(0);
         String *str  = Str_newf("foo");
-        Hash_Store(hash, (Obj*)str, INCREF(str));
-        DECREF(Hash_Delete(hash, (Obj*)str));
+        Hash_Store(hash, str, INCREF(str));
+        DECREF(Hash_Delete(hash, str));
         DECREF(str);
 
         HashIterator *iter = HashIter_new(hash);
@@ -207,11 +207,11 @@ test_tombstone(TestBatchRunner *runner) {
     {
         Hash   *hash = Hash_new(0);
         String *str  = Str_newf("foo");
-        Hash_Store(hash, (Obj*)str, INCREF(str));
+        Hash_Store(hash, str, INCREF(str));
 
         HashIterator *iter = HashIter_new(hash);
         HashIter_Next(iter);
-        DECREF(Hash_Delete(hash, (Obj*)str));
+        DECREF(Hash_Delete(hash, str));
 
 
         Err *get_key_error = Err_trap(S_invoke_Get_Key, iter);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/go/ext/clownfish.c
----------------------------------------------------------------------
diff --git a/runtime/go/ext/clownfish.c b/runtime/go/ext/clownfish.c
index 851012b..3150dfa 100644
--- a/runtime/go/ext/clownfish.c
+++ b/runtime/go/ext/clownfish.c
@@ -47,7 +47,6 @@ SI_immortal(cfish_Class *klass) {
     if (klass == CFISH_CLASS
         || klass == CFISH_METHOD
         || klass == CFISH_BOOLNUM
-        || klass == CFISH_HASHTOMBSTONE
        ){
         return true;
     }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/perl/buildlib/Clownfish/Build/Binding.pm
----------------------------------------------------------------------
diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm b/runtime/perl/buildlib/Clownfish/Build/Binding.pm
index e793f08..0b682f3 100644
--- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm
+++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm
@@ -276,7 +276,7 @@ _fetch(self, key)
     cfish_Hash *self;
     cfish_String *key;
 CODE:
-    RETVAL = CFISH_OBJ_TO_SV(CFISH_Hash_Fetch_IMP(self, (cfish_Obj*)key));
+    RETVAL = CFISH_OBJ_TO_SV(CFISH_Hash_Fetch_IMP(self, key));
 OUTPUT: RETVAL
 
 void
@@ -287,7 +287,7 @@ store(self, key, value);
 PPCODE:
 {
     if (value) { CFISH_INCREF(value); }
-    CFISH_Hash_Store_IMP(self, (cfish_Obj*)key, value);
+    CFISH_Hash_Store_IMP(self, key, value);
 }
 
 void
@@ -295,11 +295,11 @@ next(self)
     cfish_Hash *self;
 PPCODE:
 {
-    cfish_Obj *key;
-    cfish_Obj *val;
+    cfish_String *key;
+    cfish_Obj    *val;
 
     if (CFISH_Hash_Next(self, &key, &val)) {
-        SV *key_sv = (SV*)CFISH_Obj_To_Host(key);
+        SV *key_sv = (SV*)CFISH_Str_To_Host(key);
         SV *val_sv = (SV*)CFISH_Obj_To_Host(val);
 
         XPUSHs(sv_2mortal(key_sv));

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8282412f/runtime/perl/xs/XSBind.c
----------------------------------------------------------------------
diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c
index 33e41af..737cd9e 100644
--- a/runtime/perl/xs/XSBind.c
+++ b/runtime/perl/xs/XSBind.c
@@ -346,22 +346,16 @@ S_cfish_hash_to_perl_hash(pTHX_ cfish_Hash *hash) {
 
     // Iterate over key-value pairs.
     CFISH_Hash_Iterate(hash);
-    while (CFISH_Hash_Next(hash, (cfish_Obj**)&key, &val)) {
+    while (CFISH_Hash_Next(hash, &key, &val)) {
         // Recurse for each value.
         SV *val_sv = XSBind_cfish_to_perl(aTHX_ val);
-        if (!CFISH_Obj_Is_A((cfish_Obj*)key, CFISH_STRING)) {
-            CFISH_THROW(CFISH_ERR,
-                        "Can't convert a key of class %o to a Perl hash key",
-                        CFISH_Obj_Get_Class_Name((cfish_Obj*)key));
-        }
-        else {
-            STRLEN key_size = CFISH_Str_Get_Size(key);
-            char *key_sv_ptr = SvGROW(key_sv, key_size + 1);
-            memcpy(key_sv_ptr, CFISH_Str_Get_Ptr8(key), key_size);
-            SvCUR_set(key_sv, key_size);
-            *SvEND(key_sv) = '\0';
-            (void)hv_store_ent(perl_hash, key_sv, val_sv, 0);
-        }
+
+        STRLEN key_size = CFISH_Str_Get_Size(key);
+        char *key_sv_ptr = SvGROW(key_sv, key_size + 1);
+        memcpy(key_sv_ptr, CFISH_Str_Get_Ptr8(key), key_size);
+        SvCUR_set(key_sv, key_size);
+        *SvEND(key_sv) = '\0';
+        (void)hv_store_ent(perl_hash, key_sv, val_sv, 0);
     }
     SvREFCNT_dec(key_sv);
 
@@ -610,7 +604,6 @@ SI_immortal(cfish_Class *klass) {
     if (klass == CFISH_CLASS
         || klass == CFISH_METHOD
         || klass == CFISH_BOOLNUM
-        || klass == CFISH_HASHTOMBSTONE
        ){
         return true;
     }


Mime
View raw message