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/CLOWNFISH-7-string-only-hash-keys Commit: 8282412f06a8e48ebdd7957e380ac46f4090ad40 Parents: 93f0dee Author: Nick Wellnhofer <[email protected]> Authored: Tue Apr 14 12:57:44 2015 +0200 Committer: Nick Wellnhofer <[email protected]> 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; }
