Rename VArray to Vector New nickname is "Vec".
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/3fb61a74 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/3fb61a74 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/3fb61a74 Branch: refs/heads/master Commit: 3fb61a74de64263bd0f7d6bb00419c09638e2ba6 Parents: 7c88b32 Author: Nick Wellnhofer <[email protected]> Authored: Sun Apr 26 19:34:25 2015 +0200 Committer: Nick Wellnhofer <[email protected]> Committed: Sun Apr 26 21:01:05 2015 +0200 ---------------------------------------------------------------------- runtime/c/src/Clownfish/Class.c | 6 +- runtime/core/Clownfish/Class.c | 14 +- runtime/core/Clownfish/Class.cfh | 4 +- runtime/core/Clownfish/Hash.c | 14 +- runtime/core/Clownfish/Hash.cfh | 8 +- runtime/core/Clownfish/Test.c | 4 +- runtime/core/Clownfish/Test/TestHash.c | 58 +-- runtime/core/Clownfish/Test/TestHashIterator.c | 24 +- runtime/core/Clownfish/Test/TestVArray.c | 491 ------------------- runtime/core/Clownfish/Test/TestVArray.cfh | 29 -- runtime/core/Clownfish/Test/TestVector.c | 491 +++++++++++++++++++ runtime/core/Clownfish/Test/TestVector.cfh | 29 ++ .../Clownfish/TestHarness/TestBatchRunner.c | 2 +- runtime/core/Clownfish/TestHarness/TestSuite.c | 14 +- .../core/Clownfish/TestHarness/TestSuite.cfh | 2 +- runtime/core/Clownfish/VArray.c | 313 ------------ runtime/core/Clownfish/VArray.cfh | 143 ------ runtime/core/Clownfish/Vector.c | 313 ++++++++++++ runtime/core/Clownfish/Vector.cfh | 143 ++++++ runtime/example-lang/src/CFBind.h | 2 +- runtime/example-lang/src/Clownfish/Class.c | 4 +- runtime/go/clownfish/clownfish.go | 6 +- runtime/go/ext/clownfish.c | 6 +- .../perl/buildlib/Clownfish/Build/Binding.pm | 24 +- runtime/perl/lib/Clownfish.pm | 4 +- runtime/perl/lib/Clownfish.pod | 6 +- runtime/perl/lib/Clownfish/VArray.pm | 2 +- runtime/perl/t/binding/016-varray.t | 2 +- runtime/perl/t/core/016-varray.t | 2 +- runtime/perl/xs/XSBind.c | 32 +- runtime/perl/xs/XSBind.h | 6 +- runtime/ruby/ext/Bind.c | 10 +- runtime/ruby/ext/Bind.h | 4 +- 33 files changed, 1106 insertions(+), 1106 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/c/src/Clownfish/Class.c ---------------------------------------------------------------------- diff --git a/runtime/c/src/Clownfish/Class.c b/runtime/c/src/Clownfish/Class.c index 1ad617d..fc495c5 100644 --- a/runtime/c/src/Clownfish/Class.c +++ b/runtime/c/src/Clownfish/Class.c @@ -24,7 +24,7 @@ #include "Clownfish/String.h" #include "Clownfish/Err.h" #include "Clownfish/Util/Memory.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" Obj* Class_Make_Obj_IMP(Class *self) { @@ -56,10 +56,10 @@ Class_register_with_host(Class *singleton, Class *parent) { UNUSED_VAR(parent); } -VArray* +Vector* Class_fresh_host_methods(String *class_name) { UNUSED_VAR(class_name); - return VA_new(0); + return Vec_new(0); } String* http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Class.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c index 1b480b3..d691253 100644 --- a/runtime/core/Clownfish/Class.c +++ b/runtime/core/Clownfish/Class.c @@ -33,7 +33,7 @@ #include "Clownfish/LockFreeRegistry.h" #include "Clownfish/Method.h" #include "Clownfish/Num.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/Util/Atomic.h" #include "Clownfish/Util/Memory.h" @@ -222,12 +222,12 @@ Class_Get_Obj_Alloc_Size_IMP(Class *self) { return self->obj_alloc_size; } -VArray* +Vector* Class_Get_Methods_IMP(Class *self) { - VArray *retval = VA_new(0); + Vector *retval = Vec_new(0); for (size_t i = 0; self->methods[i]; ++i) { - VA_Push(retval, INCREF(self->methods[i])); + Vec_Push(retval, INCREF(self->methods[i])); } return retval; @@ -252,7 +252,7 @@ Class_singleton(String *class_name, Class *parent) { Class *singleton = (Class*)LFReg_Fetch(Class_registry, class_name); if (singleton == NULL) { - VArray *fresh_host_methods; + Vector *fresh_host_methods; uint32_t num_fresh; if (parent == NULL) { @@ -278,11 +278,11 @@ Class_singleton(String *class_name, Class *parent) { // Allow host methods to override. fresh_host_methods = Class_fresh_host_methods(class_name); - num_fresh = VA_Get_Size(fresh_host_methods); + num_fresh = Vec_Get_Size(fresh_host_methods); if (num_fresh) { Hash *meths = Hash_new(num_fresh); for (uint32_t i = 0; i < num_fresh; i++) { - String *meth = (String*)VA_Fetch(fresh_host_methods, i); + String *meth = (String*)Vec_Fetch(fresh_host_methods, i); Hash_Store(meths, meth, (Obj*)CFISH_TRUE); } for (Class *klass = parent; klass; klass = klass->parent) { http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Class.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Class.cfh b/runtime/core/Clownfish/Class.cfh index 8b966b7..4b95fda 100644 --- a/runtime/core/Clownfish/Class.cfh +++ b/runtime/core/Clownfish/Class.cfh @@ -89,7 +89,7 @@ class Clownfish::Class inherits Clownfish::Obj { /** List all of the methods defined directly within a host subclass. */ - inert incremented VArray* + inert incremented Vector* fresh_host_methods(String *class_name); /** Replace a function pointer in the Class's vtable. @@ -133,7 +133,7 @@ class Clownfish::Class inherits Clownfish::Obj { /** Return novel methods of the class. */ - VArray* + Vector* Get_Methods(Class *self); public incremented Class* http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Hash.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Hash.c b/runtime/core/Clownfish/Hash.c index e23d3b6..68326a8 100644 --- a/runtime/core/Clownfish/Hash.c +++ b/runtime/core/Clownfish/Hash.c @@ -25,7 +25,7 @@ #include "Clownfish/Hash.h" #include "Clownfish/String.h" #include "Clownfish/Err.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/Util/Memory.h" // TOMBSTONE is shared across threads, so it must never be incref'd or @@ -227,30 +227,30 @@ Hash_Find_Key_IMP(Hash *self, String *key, size_t hash_sum) { return entry ? entry->key : NULL; } -VArray* +Vector* Hash_Keys_IMP(Hash *self) { - VArray *keys = VA_new(self->size); + Vector *keys = Vec_new(self->size); HashEntry *entry = (HashEntry*)self->entries; HashEntry *const limit = entry + self->capacity; for (; entry < limit; entry++) { if (entry->key && entry->key != TOMBSTONE) { - VA_Push(keys, INCREF(entry->key)); + Vec_Push(keys, INCREF(entry->key)); } } return keys; } -VArray* +Vector* Hash_Values_IMP(Hash *self) { - VArray *values = VA_new(self->size); + Vector *values = Vec_new(self->size); HashEntry *entry = (HashEntry*)self->entries; HashEntry *const limit = entry + self->capacity; for (; entry < limit; entry++) { if (entry->key && entry->key != TOMBSTONE) { - VA_Push(values, INCREF(entry->value)); + Vec_Push(values, INCREF(entry->value)); } } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Hash.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Hash.cfh b/runtime/core/Clownfish/Hash.cfh index 2960f2a..8fe27e0 100644 --- a/runtime/core/Clownfish/Hash.cfh +++ b/runtime/core/Clownfish/Hash.cfh @@ -85,14 +85,14 @@ public class Clownfish::Hash inherits Clownfish::Obj { nullable String* Find_Key(Hash *self, String *key, size_t hash_sum); - /** Return an VArray of pointers to the hash's keys. + /** Return an Vector of pointers to the hash's keys. */ - public incremented VArray* + public incremented Vector* Keys(Hash *self); - /** Return an VArray of pointers to the hash's values. + /** Return an Vector of pointers to the hash's values. */ - public incremented VArray* + public incremented Vector* Values(Hash *self); size_t http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test.c b/runtime/core/Clownfish/Test.c index 606e8fe..03c91a9 100644 --- a/runtime/core/Clownfish/Test.c +++ b/runtime/core/Clownfish/Test.c @@ -32,7 +32,7 @@ #include "Clownfish/Test/TestNum.h" #include "Clownfish/Test/TestObj.h" #include "Clownfish/Test/TestThreads.h" -#include "Clownfish/Test/TestVArray.h" +#include "Clownfish/Test/TestVector.h" #include "Clownfish/Test/Util/TestAtomic.h" #include "Clownfish/Test/Util/TestMemory.h" #include "Clownfish/Test/Util/TestNumberUtils.h" @@ -42,7 +42,7 @@ TestSuite* Test_create_test_suite() { TestSuite *suite = TestSuite_new(); - TestSuite_Add_Batch(suite, (TestBatch*)TestVArray_new()); + TestSuite_Add_Batch(suite, (TestBatch*)TestVector_new()); TestSuite_Add_Batch(suite, (TestBatch*)TestHash_new()); TestSuite_Add_Batch(suite, (TestBatch*)TestHashIterator_new()); TestSuite_Add_Batch(suite, (TestBatch*)TestObj_new()); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test/TestHash.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestHash.c b/runtime/core/Clownfish/Test/TestHash.c index f871641..5c47c12 100644 --- a/runtime/core/Clownfish/Test/TestHash.c +++ b/runtime/core/Clownfish/Test/TestHash.c @@ -28,7 +28,7 @@ #include "Clownfish/Test.h" #include "Clownfish/TestHarness/TestBatchRunner.h" #include "Clownfish/TestHarness/TestUtils.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/Class.h" TestHash* @@ -66,8 +66,8 @@ test_Store_and_Fetch(TestBatchRunner *runner) { Hash *hash = Hash_new(100); Hash *dupe = Hash_new(100); const uint32_t starting_cap = Hash_Get_Capacity(hash); - VArray *expected = VA_new(100); - VArray *got = VA_new(100); + Vector *expected = Vec_new(100); + Vector *got = Vec_new(100); StackString *twenty = SSTR_WRAP_UTF8("20", 2); StackString *forty = SSTR_WRAP_UTF8("40", 2); StackString *foo = SSTR_WRAP_UTF8("foo", 3); @@ -76,7 +76,7 @@ test_Store_and_Fetch(TestBatchRunner *runner) { String *str = Str_newf("%i32", i); Hash_Store(hash, str, (Obj*)str); Hash_Store(dupe, str, INCREF(str)); - VA_Push(expected, INCREF(str)); + Vec_Push(expected, INCREF(str)); } TEST_TRUE(runner, Hash_Equals(hash, (Obj*)dupe), "Equals"); @@ -84,12 +84,12 @@ test_Store_and_Fetch(TestBatchRunner *runner) { "Initial capacity sufficient (no rebuilds)"); for (int32_t i = 0; i < 100; i++) { - String *key = (String*)VA_Fetch(expected, i); + String *key = (String*)Vec_Fetch(expected, i); Obj *elem = Hash_Fetch(hash, key); - VA_Push(got, (Obj*)INCREF(elem)); + Vec_Push(got, (Obj*)INCREF(elem)); } - TEST_TRUE(runner, VA_Equals(got, (Obj*)expected), + TEST_TRUE(runner, Vec_Equals(got, (Obj*)expected), "basic Store and Fetch"); TEST_INT_EQ(runner, Hash_Get_Size(hash), 100, "size incremented properly by Hash_Store"); @@ -116,7 +116,7 @@ test_Store_and_Fetch(TestBatchRunner *runner) { TEST_INT_EQ(runner, Hash_Get_Size(hash), 99, "size not decremented by unsuccessful Delete"); DECREF(Hash_Delete(dupe, (String*)forty)); - TEST_TRUE(runner, VA_Equals(got, (Obj*)expected), "Equals after Delete"); + TEST_TRUE(runner, Vec_Equals(got, (Obj*)expected), "Equals after Delete"); Hash_Clear(hash); TEST_TRUE(runner, Hash_Fetch(hash, (String*)twenty) == NULL, "Clear"); @@ -131,26 +131,26 @@ test_Store_and_Fetch(TestBatchRunner *runner) { static void test_Keys_Values(TestBatchRunner *runner) { Hash *hash = Hash_new(0); // trigger multiple rebuilds. - VArray *expected = VA_new(100); - VArray *keys; - VArray *values; + Vector *expected = Vec_new(100); + Vector *keys; + Vector *values; for (uint32_t i = 0; i < 500; i++) { String *str = Str_newf("%u32", i); Hash_Store(hash, str, (Obj*)str); - VA_Push(expected, INCREF(str)); + Vec_Push(expected, INCREF(str)); } - VA_Sort(expected); + Vec_Sort(expected); keys = Hash_Keys(hash); values = Hash_Values(hash); - VA_Sort(keys); - VA_Sort(values); - TEST_TRUE(runner, VA_Equals(keys, (Obj*)expected), "Keys"); - TEST_TRUE(runner, VA_Equals(values, (Obj*)expected), "Values"); - VA_Clear(keys); - VA_Clear(values); + Vec_Sort(keys); + Vec_Sort(values); + TEST_TRUE(runner, Vec_Equals(keys, (Obj*)expected), "Keys"); + TEST_TRUE(runner, Vec_Equals(values, (Obj*)expected), "Values"); + Vec_Clear(keys); + Vec_Clear(values); { StackString *forty = SSTR_WRAP_UTF8("40", 2); @@ -171,9 +171,9 @@ test_Keys_Values(TestBatchRunner *runner) { static void test_stress(TestBatchRunner *runner) { Hash *hash = Hash_new(0); // trigger multiple rebuilds. - VArray *expected = VA_new(1000); - VArray *keys; - VArray *values; + Vector *expected = Vec_new(1000); + Vector *keys; + Vector *values; for (uint32_t i = 0; i < 1000; i++) { String *str = TestUtils_random_string(rand() % 1200); @@ -182,23 +182,23 @@ test_stress(TestBatchRunner *runner) { str = TestUtils_random_string(rand() % 1200); } Hash_Store(hash, str, (Obj*)str); - VA_Push(expected, INCREF(str)); + Vec_Push(expected, INCREF(str)); } - VA_Sort(expected); + Vec_Sort(expected); // Overwrite for good measure. for (uint32_t i = 0; i < 1000; i++) { - String *str = (String*)VA_Fetch(expected, i); + String *str = (String*)Vec_Fetch(expected, i); Hash_Store(hash, str, INCREF(str)); } keys = Hash_Keys(hash); values = Hash_Values(hash); - VA_Sort(keys); - VA_Sort(values); - TEST_TRUE(runner, VA_Equals(keys, (Obj*)expected), "stress Keys"); - TEST_TRUE(runner, VA_Equals(values, (Obj*)expected), "stress Values"); + Vec_Sort(keys); + Vec_Sort(values); + TEST_TRUE(runner, Vec_Equals(keys, (Obj*)expected), "stress Keys"); + TEST_TRUE(runner, Vec_Equals(values, (Obj*)expected), "stress Values"); DECREF(keys); DECREF(values); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test/TestHashIterator.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestHashIterator.c b/runtime/core/Clownfish/Test/TestHashIterator.c index 87f9f6f..fd929d3 100644 --- a/runtime/core/Clownfish/Test/TestHashIterator.c +++ b/runtime/core/Clownfish/Test/TestHashIterator.c @@ -27,7 +27,7 @@ #include "Clownfish/Hash.h" #include "Clownfish/HashIterator.h" #include "Clownfish/Test.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/TestHarness/TestBatchRunner.h" #include "Clownfish/TestHarness/TestUtils.h" #include "Clownfish/Class.h" @@ -40,25 +40,25 @@ TestHashIterator_new() { static void test_Next(TestBatchRunner *runner) { Hash *hash = Hash_new(0); // trigger multiple rebuilds. - VArray *expected = VA_new(100); - VArray *keys = VA_new(500); - VArray *values = VA_new(500); + Vector *expected = Vec_new(100); + Vector *keys = Vec_new(500); + Vector *values = Vec_new(500); for (uint32_t i = 0; i < 500; i++) { String *str = Str_newf("%u32", i); Hash_Store(hash, str, (Obj*)str); - VA_Push(expected, INCREF(str)); + Vec_Push(expected, INCREF(str)); } - VA_Sort(expected); + Vec_Sort(expected); { HashIterator *iter = HashIter_new(hash); while (HashIter_Next(iter)) { String *key = HashIter_Get_Key(iter); Obj *value = HashIter_Get_Value(iter); - VA_Push(keys, INCREF(key)); - VA_Push(values, INCREF(value)); + Vec_Push(keys, INCREF(key)); + Vec_Push(values, INCREF(value)); } TEST_TRUE(runner, !HashIter_Next(iter), "Next continues to return false after iteration finishes."); @@ -66,10 +66,10 @@ test_Next(TestBatchRunner *runner) { DECREF(iter); } - VA_Sort(keys); - VA_Sort(values); - TEST_TRUE(runner, VA_Equals(keys, (Obj*)expected), "Keys from Iter"); - TEST_TRUE(runner, VA_Equals(values, (Obj*)expected), "Values from Iter"); + Vec_Sort(keys); + Vec_Sort(values); + TEST_TRUE(runner, Vec_Equals(keys, (Obj*)expected), "Keys from Iter"); + TEST_TRUE(runner, Vec_Equals(values, (Obj*)expected), "Values from Iter"); DECREF(hash); DECREF(expected); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test/TestVArray.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestVArray.c b/runtime/core/Clownfish/Test/TestVArray.c deleted file mode 100644 index ae28879..0000000 --- a/runtime/core/Clownfish/Test/TestVArray.c +++ /dev/null @@ -1,491 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <string.h> -#include <stdlib.h> - -#define C_CFISH_VARRAY -#define CFISH_USE_SHORT_NAMES -#define TESTCFISH_USE_SHORT_NAMES - -#include "Clownfish/Test/TestVArray.h" - -#include "Clownfish/String.h" -#include "Clownfish/Err.h" -#include "Clownfish/Num.h" -#include "Clownfish/Test.h" -#include "Clownfish/TestHarness/TestBatchRunner.h" -#include "Clownfish/TestHarness/TestUtils.h" -#include "Clownfish/VArray.h" -#include "Clownfish/Class.h" - -TestVArray* -TestVArray_new() { - return (TestVArray*)Class_Make_Obj(TESTVARRAY); -} - -// Return an array of size 10 with 30 garbage pointers behind. -static VArray* -S_array_with_garbage() { - VArray *array = VA_new(100); - - for (int i = 0; i < 40; i++) { - VA_Push(array, (Obj*)CFISH_TRUE); - } - - // Remove elements using different methods. - VA_Excise(array, 10, 10); - for (int i = 0; i < 10; i++) { VA_Pop(array); } - VA_Resize(array, 10); - - return array; -} - -static void -test_Equals(TestBatchRunner *runner) { - VArray *array = VA_new(0); - VArray *other = VA_new(0); - StackString *stuff = SSTR_WRAP_UTF8("stuff", 5); - - TEST_TRUE(runner, VA_Equals(array, (Obj*)array), - "Array equal to self"); - - TEST_FALSE(runner, VA_Equals(array, (Obj*)CFISH_TRUE), - "Array not equal to non-array"); - - TEST_TRUE(runner, VA_Equals(array, (Obj*)other), - "Empty arrays are equal"); - - VA_Push(array, (Obj*)CFISH_TRUE); - TEST_FALSE(runner, VA_Equals(array, (Obj*)other), - "Add one elem and Equals returns false"); - - VA_Push(other, (Obj*)CFISH_TRUE); - TEST_TRUE(runner, VA_Equals(array, (Obj*)other), - "Add a matching elem and Equals returns true"); - - VA_Store(array, 2, (Obj*)CFISH_TRUE); - TEST_FALSE(runner, VA_Equals(array, (Obj*)other), - "Add elem after a NULL and Equals returns false"); - - VA_Store(other, 2, (Obj*)CFISH_TRUE); - TEST_TRUE(runner, VA_Equals(array, (Obj*)other), - "Empty elems don't spoil Equals"); - - VA_Store(other, 2, INCREF(stuff)); - TEST_FALSE(runner, VA_Equals(array, (Obj*)other), - "Non-matching value spoils Equals"); - - VA_Store(other, 2, NULL); - TEST_FALSE(runner, VA_Equals(array, (Obj*)other), - "NULL value spoils Equals"); - TEST_FALSE(runner, VA_Equals(other, (Obj*)array), - "NULL value spoils Equals (reversed)"); - - VA_Excise(array, 1, 2); // removes empty elems - DECREF(VA_Delete(other, 1)); // leaves NULL in place of deleted elem - DECREF(VA_Delete(other, 2)); - TEST_FALSE(runner, VA_Equals(array, (Obj*)other), - "Empty trailing elements spoil Equals"); - - DECREF(array); - DECREF(other); -} - -static void -test_Store_Fetch(TestBatchRunner *runner) { - VArray *array = VA_new(0); - String *elem; - - TEST_TRUE(runner, VA_Fetch(array, 2) == NULL, "Fetch beyond end"); - - VA_Store(array, 2, (Obj*)Str_newf("foo")); - elem = (String*)CERTIFY(VA_Fetch(array, 2), STRING); - TEST_INT_EQ(runner, 3, VA_Get_Size(array), "Store updates size"); - TEST_TRUE(runner, Str_Equals_Utf8(elem, "foo", 3), "Store"); - - elem = (String*)INCREF(elem); - TEST_INT_EQ(runner, 2, CFISH_REFCOUNT_NN(elem), - "start with refcount of 2"); - VA_Store(array, 2, (Obj*)Str_newf("bar")); - TEST_INT_EQ(runner, 1, CFISH_REFCOUNT_NN(elem), - "Displacing elem via Store updates refcount"); - DECREF(elem); - elem = (String*)CERTIFY(VA_Fetch(array, 2), STRING); - TEST_TRUE(runner, Str_Equals_Utf8(elem, "bar", 3), "Store displacement"); - - DECREF(array); - - array = S_array_with_garbage(); - VA_Store(array, 40, (Obj*)CFISH_TRUE); - bool all_null = true; - for (int i = 10; i < 40; i++) { - if (VA_Fetch(array, i) != NULL) { all_null = false; } - } - TEST_TRUE(runner, all_null, "Out-of-bounds Store clears excised elements"); - DECREF(array); -} - -static void -test_Push_Pop_Insert(TestBatchRunner *runner) { - VArray *array = VA_new(0); - String *elem; - - TEST_INT_EQ(runner, VA_Get_Size(array), 0, "size starts at 0"); - TEST_TRUE(runner, VA_Pop(array) == NULL, - "Pop from empty array returns NULL"); - - VA_Push(array, (Obj*)Str_newf("a")); - VA_Push(array, (Obj*)Str_newf("b")); - VA_Push(array, (Obj*)Str_newf("c")); - - TEST_INT_EQ(runner, VA_Get_Size(array), 3, "size after Push"); - TEST_TRUE(runner, NULL != CERTIFY(VA_Fetch(array, 2), STRING), "Push"); - - elem = (String*)CERTIFY(VA_Pop(array), STRING); - TEST_TRUE(runner, Str_Equals_Utf8(elem, "c", 1), "Pop"); - TEST_INT_EQ(runner, VA_Get_Size(array), 2, "size after Pop"); - DECREF(elem); - - VA_Insert(array, 0, (Obj*)Str_newf("foo")); - elem = (String*)CERTIFY(VA_Fetch(array, 0), STRING); - TEST_TRUE(runner, Str_Equals_Utf8(elem, "foo", 3), "Insert"); - TEST_INT_EQ(runner, VA_Get_Size(array), 3, "size after Insert"); - - for (int i = 0; i < 256; ++i) { - VA_Push(array, (Obj*)Str_newf("flotsam")); - } - for (int i = 0; i < 512; ++i) { - VA_Insert(array, i, (Obj*)Str_newf("jetsam")); - } - TEST_INT_EQ(runner, VA_Get_Size(array), 3 + 256 + 512, - "size after exercising Push and Insert"); - - DECREF(array); -} - -static void -test_Delete(TestBatchRunner *runner) { - VArray *wanted = VA_new(5); - VArray *got = VA_new(5); - uint32_t i; - - for (i = 0; i < 5; i++) { VA_Push(got, (Obj*)Str_newf("%u32", i)); } - VA_Store(wanted, 0, (Obj*)Str_newf("0", i)); - VA_Store(wanted, 1, (Obj*)Str_newf("1", i)); - VA_Store(wanted, 4, (Obj*)Str_newf("4", i)); - DECREF(VA_Delete(got, 2)); - DECREF(VA_Delete(got, 3)); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), "Delete"); - - TEST_TRUE(runner, VA_Delete(got, 25000) == NULL, - "Delete beyond array size returns NULL"); - - DECREF(wanted); - DECREF(got); -} - -static void -test_Resize(TestBatchRunner *runner) { - VArray *array = VA_new(3); - uint32_t i; - - for (i = 0; i < 2; i++) { VA_Push(array, (Obj*)Str_newf("%u32", i)); } - TEST_INT_EQ(runner, VA_Get_Capacity(array), 3, "Start with capacity 3"); - - VA_Resize(array, 4); - TEST_INT_EQ(runner, VA_Get_Size(array), 4, "Resize up"); - TEST_INT_EQ(runner, VA_Get_Capacity(array), 4, - "Resize changes capacity"); - - VA_Resize(array, 2); - TEST_INT_EQ(runner, VA_Get_Size(array), 2, "Resize down"); - TEST_TRUE(runner, VA_Fetch(array, 2) == NULL, "Resize down zaps elem"); - - VA_Resize(array, 2); - TEST_INT_EQ(runner, VA_Get_Size(array), 2, "Resize to same size"); - - DECREF(array); - - array = S_array_with_garbage(); - VA_Resize(array, 40); - bool all_null = true; - for (int i = 10; i < 40; i++) { - if (VA_Fetch(array, i) != NULL) { all_null = false; } - } - TEST_TRUE(runner, all_null, "Resize clears excised elements"); - DECREF(array); -} - -static void -test_Excise(TestBatchRunner *runner) { - VArray *wanted = VA_new(5); - VArray *got = VA_new(5); - - for (uint32_t i = 0; i < 5; i++) { - VA_Push(wanted, (Obj*)Str_newf("%u32", i)); - VA_Push(got, (Obj*)Str_newf("%u32", i)); - } - - VA_Excise(got, 7, 1); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), - "Excise outside of range is no-op"); - - VA_Excise(got, 2, 2); - DECREF(VA_Delete(wanted, 2)); - DECREF(VA_Delete(wanted, 3)); - VA_Store(wanted, 2, VA_Delete(wanted, 4)); - VA_Resize(wanted, 3); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), - "Excise multiple elems"); - - VA_Excise(got, 2, 2); - VA_Resize(wanted, 2); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), - "Splicing too many elems truncates"); - - VA_Excise(got, 0, 1); - VA_Store(wanted, 0, VA_Delete(wanted, 1)); - VA_Resize(wanted, 1); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), - "Excise first elem"); - - DECREF(got); - DECREF(wanted); -} - -static void -test_Push_All(TestBatchRunner *runner) { - VArray *wanted = VA_new(0); - VArray *got = VA_new(0); - VArray *scratch = VA_new(0); - VArray *empty = VA_new(0); - uint32_t i; - - for (i = 0; i < 40; i++) { VA_Push(wanted, (Obj*)Str_newf("%u32", i)); } - VA_Push(wanted, NULL); - for (i = 0; i < 20; i++) { VA_Push(got, (Obj*)Str_newf("%u32", i)); } - for (i = 20; i < 40; i++) { VA_Push(scratch, (Obj*)Str_newf("%u32", i)); } - VA_Push(scratch, NULL); - - VA_Push_All(got, scratch); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), "Push_All"); - - VA_Push_All(got, empty); - TEST_TRUE(runner, VA_Equals(wanted, (Obj*)got), - "Push_All with empty array"); - - DECREF(wanted); - DECREF(got); - DECREF(scratch); - DECREF(empty); -} - -static void -test_Slice(TestBatchRunner *runner) { - VArray *array = VA_new(0); - for (uint32_t i = 0; i < 10; i++) { VA_Push(array, (Obj*)Str_newf("%u32", i)); } - { - VArray *slice = VA_Slice(array, 0, 10); - TEST_TRUE(runner, VA_Equals(array, (Obj*)slice), "Slice entire array"); - DECREF(slice); - } - { - VArray *slice = VA_Slice(array, 0, 11); - TEST_TRUE(runner, VA_Equals(array, (Obj*)slice), - "Exceed length"); - DECREF(slice); - } - { - VArray *wanted = VA_new(0); - VA_Push(wanted, (Obj*)Str_newf("9")); - VArray *slice = VA_Slice(array, 9, 11); - TEST_TRUE(runner, VA_Equals(slice, (Obj*)wanted), - "Exceed length, start near end"); - DECREF(slice); - DECREF(wanted); - } - { - VArray *slice = VA_Slice(array, 0, 0); - TEST_TRUE(runner, VA_Get_Size(slice) == 0, "empty slice"); - DECREF(slice); - } - { - VArray *slice = VA_Slice(array, 20, 1); - TEST_TRUE(runner, VA_Get_Size(slice) == 0, "exceed offset"); - DECREF(slice); - } - { - VArray *wanted = VA_new(0); - VA_Push(wanted, (Obj*)Str_newf("9")); - VArray *slice = VA_Slice(array, 9, SIZE_MAX - 1); - TEST_TRUE(runner, VA_Get_Size(slice) == 1, "guard against overflow"); - DECREF(slice); - DECREF(wanted); - } - DECREF(array); -} - -static void -test_Clone(TestBatchRunner *runner) { - VArray *array = VA_new(0); - VArray *twin; - uint32_t i; - - for (i = 0; i < 10; i++) { - VA_Push(array, (Obj*)Int32_new(i)); - } - VA_Push(array, NULL); - twin = VA_Clone(array); - TEST_TRUE(runner, VA_Equals(array, (Obj*)twin), "Clone"); - TEST_TRUE(runner, VA_Fetch(array, 1) == VA_Fetch(twin, 1), - "Clone doesn't clone elements"); - - DECREF(array); - DECREF(twin); -} - -static void -S_overflow_Push(void *context) { - UNUSED_VAR(context); - VArray *array = VA_new(0); - array->cap = SIZE_MAX; - array->size = array->cap; - VA_Push(array, (Obj*)CFISH_TRUE); -} - -static void -S_overflow_Insert(void *context) { - UNUSED_VAR(context); - VArray *array = VA_new(0); - array->cap = SIZE_MAX; - array->size = array->cap; - VA_Insert(array, 38911, (Obj*)CFISH_TRUE); -} - -static void -S_overflow_Push_All(void *context) { - UNUSED_VAR(context); - VArray *array = VA_new(0); - array->cap = 1000000000; - array->size = array->cap; - VArray *other = VA_new(0); - other->cap = SIZE_MAX - array->cap + 1; - other->size = other->cap; - VA_Push_All(array, other); -} - -static void -S_overflow_Store(void *context) { - UNUSED_VAR(context); - VArray *array = VA_new(0); - VA_Store(array, SIZE_MAX, (Obj*)CFISH_TRUE); -} - -static void -S_test_exception(TestBatchRunner *runner, Err_Attempt_t func, - const char *test_name) { - Err *error = Err_trap(func, NULL); - TEST_TRUE(runner, error != NULL, test_name); - DECREF(error); -} - -static void -test_exceptions(TestBatchRunner *runner) { - if (getenv("LUCY_VALGRIND")) { - SKIP(runner, 4, "memory leak"); - return; - } - S_test_exception(runner, S_overflow_Push, - "Push throws on overflow"); - S_test_exception(runner, S_overflow_Insert, - "Insert throws on overflow"); - S_test_exception(runner, S_overflow_Push_All, - "Push_All throws on overflow"); - S_test_exception(runner, S_overflow_Store, - "Store throws on overflow"); -} - -static void -test_Sort(TestBatchRunner *runner) { - VArray *array = VA_new(8); - VArray *wanted = VA_new(8); - - VA_Push(array, NULL); - VA_Push(array, (Obj*)Str_newf("aaab")); - VA_Push(array, (Obj*)Str_newf("ab")); - VA_Push(array, NULL); - VA_Push(array, NULL); - VA_Push(array, (Obj*)Str_newf("aab")); - VA_Push(array, (Obj*)Str_newf("b")); - - VA_Push(wanted, (Obj*)Str_newf("aaab")); - VA_Push(wanted, (Obj*)Str_newf("aab")); - VA_Push(wanted, (Obj*)Str_newf("ab")); - VA_Push(wanted, (Obj*)Str_newf("b")); - VA_Push(wanted, NULL); - VA_Push(wanted, NULL); - VA_Push(wanted, NULL); - - VA_Sort(array); - TEST_TRUE(runner, VA_Equals(array, (Obj*)wanted), "Sort with NULLs"); - - DECREF(array); - DECREF(wanted); -} - -static void -test_Grow(TestBatchRunner *runner) { - VArray *array = VA_new(500); - uint32_t cap; - - cap = VA_Get_Capacity(array); - TEST_TRUE(runner, cap >= 500, "Array is created with minimum capacity"); - - VA_Grow(array, 2000); - cap = VA_Get_Capacity(array); - TEST_TRUE(runner, cap >= 2000, "Grow to larger capacity"); - - uint32_t old_cap = cap; - VA_Grow(array, old_cap); - cap = VA_Get_Capacity(array); - TEST_TRUE(runner, cap >= old_cap, "Grow to same capacity"); - - VA_Grow(array, 1000); - cap = VA_Get_Capacity(array); - TEST_TRUE(runner, cap >= 1000, "Grow to smaller capacity"); - - DECREF(array); -} - -void -TestVArray_Run_IMP(TestVArray *self, TestBatchRunner *runner) { - TestBatchRunner_Plan(runner, (TestBatch*)self, 59); - test_Equals(runner); - test_Store_Fetch(runner); - test_Push_Pop_Insert(runner); - test_Delete(runner); - test_Resize(runner); - test_Excise(runner); - test_Push_All(runner); - test_Slice(runner); - test_Clone(runner); - test_exceptions(runner); - test_Sort(runner); - test_Grow(runner); -} - - http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test/TestVArray.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestVArray.cfh b/runtime/core/Clownfish/Test/TestVArray.cfh deleted file mode 100644 index 735fccb..0000000 --- a/runtime/core/Clownfish/Test/TestVArray.cfh +++ /dev/null @@ -1,29 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -parcel TestClownfish; - -class Clownfish::Test::TestVArray - inherits Clownfish::TestHarness::TestBatch { - - inert incremented TestVArray* - new(); - - void - Run(TestVArray *self, TestBatchRunner *runner); -} - - http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test/TestVector.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestVector.c b/runtime/core/Clownfish/Test/TestVector.c new file mode 100644 index 0000000..7697f29 --- /dev/null +++ b/runtime/core/Clownfish/Test/TestVector.c @@ -0,0 +1,491 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include <stdlib.h> + +#define C_CFISH_VECTOR +#define CFISH_USE_SHORT_NAMES +#define TESTCFISH_USE_SHORT_NAMES + +#include "Clownfish/Test/TestVector.h" + +#include "Clownfish/String.h" +#include "Clownfish/Err.h" +#include "Clownfish/Num.h" +#include "Clownfish/Test.h" +#include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Clownfish/TestHarness/TestUtils.h" +#include "Clownfish/Vector.h" +#include "Clownfish/Class.h" + +TestVector* +TestVector_new() { + return (TestVector*)Class_Make_Obj(TESTVECTOR); +} + +// Return an array of size 10 with 30 garbage pointers behind. +static Vector* +S_array_with_garbage() { + Vector *array = Vec_new(100); + + for (int i = 0; i < 40; i++) { + Vec_Push(array, (Obj*)CFISH_TRUE); + } + + // Remove elements using different methods. + Vec_Excise(array, 10, 10); + for (int i = 0; i < 10; i++) { Vec_Pop(array); } + Vec_Resize(array, 10); + + return array; +} + +static void +test_Equals(TestBatchRunner *runner) { + Vector *array = Vec_new(0); + Vector *other = Vec_new(0); + StackString *stuff = SSTR_WRAP_UTF8("stuff", 5); + + TEST_TRUE(runner, Vec_Equals(array, (Obj*)array), + "Array equal to self"); + + TEST_FALSE(runner, Vec_Equals(array, (Obj*)CFISH_TRUE), + "Array not equal to non-array"); + + TEST_TRUE(runner, Vec_Equals(array, (Obj*)other), + "Empty arrays are equal"); + + Vec_Push(array, (Obj*)CFISH_TRUE); + TEST_FALSE(runner, Vec_Equals(array, (Obj*)other), + "Add one elem and Equals returns false"); + + Vec_Push(other, (Obj*)CFISH_TRUE); + TEST_TRUE(runner, Vec_Equals(array, (Obj*)other), + "Add a matching elem and Equals returns true"); + + Vec_Store(array, 2, (Obj*)CFISH_TRUE); + TEST_FALSE(runner, Vec_Equals(array, (Obj*)other), + "Add elem after a NULL and Equals returns false"); + + Vec_Store(other, 2, (Obj*)CFISH_TRUE); + TEST_TRUE(runner, Vec_Equals(array, (Obj*)other), + "Empty elems don't spoil Equals"); + + Vec_Store(other, 2, INCREF(stuff)); + TEST_FALSE(runner, Vec_Equals(array, (Obj*)other), + "Non-matching value spoils Equals"); + + Vec_Store(other, 2, NULL); + TEST_FALSE(runner, Vec_Equals(array, (Obj*)other), + "NULL value spoils Equals"); + TEST_FALSE(runner, Vec_Equals(other, (Obj*)array), + "NULL value spoils Equals (reversed)"); + + Vec_Excise(array, 1, 2); // removes empty elems + DECREF(Vec_Delete(other, 1)); // leaves NULL in place of deleted elem + DECREF(Vec_Delete(other, 2)); + TEST_FALSE(runner, Vec_Equals(array, (Obj*)other), + "Empty trailing elements spoil Equals"); + + DECREF(array); + DECREF(other); +} + +static void +test_Store_Fetch(TestBatchRunner *runner) { + Vector *array = Vec_new(0); + String *elem; + + TEST_TRUE(runner, Vec_Fetch(array, 2) == NULL, "Fetch beyond end"); + + Vec_Store(array, 2, (Obj*)Str_newf("foo")); + elem = (String*)CERTIFY(Vec_Fetch(array, 2), STRING); + TEST_INT_EQ(runner, 3, Vec_Get_Size(array), "Store updates size"); + TEST_TRUE(runner, Str_Equals_Utf8(elem, "foo", 3), "Store"); + + elem = (String*)INCREF(elem); + TEST_INT_EQ(runner, 2, CFISH_REFCOUNT_NN(elem), + "start with refcount of 2"); + Vec_Store(array, 2, (Obj*)Str_newf("bar")); + TEST_INT_EQ(runner, 1, CFISH_REFCOUNT_NN(elem), + "Displacing elem via Store updates refcount"); + DECREF(elem); + elem = (String*)CERTIFY(Vec_Fetch(array, 2), STRING); + TEST_TRUE(runner, Str_Equals_Utf8(elem, "bar", 3), "Store displacement"); + + DECREF(array); + + array = S_array_with_garbage(); + Vec_Store(array, 40, (Obj*)CFISH_TRUE); + bool all_null = true; + for (int i = 10; i < 40; i++) { + if (Vec_Fetch(array, i) != NULL) { all_null = false; } + } + TEST_TRUE(runner, all_null, "Out-of-bounds Store clears excised elements"); + DECREF(array); +} + +static void +test_Push_Pop_Insert(TestBatchRunner *runner) { + Vector *array = Vec_new(0); + String *elem; + + TEST_INT_EQ(runner, Vec_Get_Size(array), 0, "size starts at 0"); + TEST_TRUE(runner, Vec_Pop(array) == NULL, + "Pop from empty array returns NULL"); + + Vec_Push(array, (Obj*)Str_newf("a")); + Vec_Push(array, (Obj*)Str_newf("b")); + Vec_Push(array, (Obj*)Str_newf("c")); + + TEST_INT_EQ(runner, Vec_Get_Size(array), 3, "size after Push"); + TEST_TRUE(runner, NULL != CERTIFY(Vec_Fetch(array, 2), STRING), "Push"); + + elem = (String*)CERTIFY(Vec_Pop(array), STRING); + TEST_TRUE(runner, Str_Equals_Utf8(elem, "c", 1), "Pop"); + TEST_INT_EQ(runner, Vec_Get_Size(array), 2, "size after Pop"); + DECREF(elem); + + Vec_Insert(array, 0, (Obj*)Str_newf("foo")); + elem = (String*)CERTIFY(Vec_Fetch(array, 0), STRING); + TEST_TRUE(runner, Str_Equals_Utf8(elem, "foo", 3), "Insert"); + TEST_INT_EQ(runner, Vec_Get_Size(array), 3, "size after Insert"); + + for (int i = 0; i < 256; ++i) { + Vec_Push(array, (Obj*)Str_newf("flotsam")); + } + for (int i = 0; i < 512; ++i) { + Vec_Insert(array, i, (Obj*)Str_newf("jetsam")); + } + TEST_INT_EQ(runner, Vec_Get_Size(array), 3 + 256 + 512, + "size after exercising Push and Insert"); + + DECREF(array); +} + +static void +test_Delete(TestBatchRunner *runner) { + Vector *wanted = Vec_new(5); + Vector *got = Vec_new(5); + uint32_t i; + + for (i = 0; i < 5; i++) { Vec_Push(got, (Obj*)Str_newf("%u32", i)); } + Vec_Store(wanted, 0, (Obj*)Str_newf("0", i)); + Vec_Store(wanted, 1, (Obj*)Str_newf("1", i)); + Vec_Store(wanted, 4, (Obj*)Str_newf("4", i)); + DECREF(Vec_Delete(got, 2)); + DECREF(Vec_Delete(got, 3)); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), "Delete"); + + TEST_TRUE(runner, Vec_Delete(got, 25000) == NULL, + "Delete beyond array size returns NULL"); + + DECREF(wanted); + DECREF(got); +} + +static void +test_Resize(TestBatchRunner *runner) { + Vector *array = Vec_new(3); + uint32_t i; + + for (i = 0; i < 2; i++) { Vec_Push(array, (Obj*)Str_newf("%u32", i)); } + TEST_INT_EQ(runner, Vec_Get_Capacity(array), 3, "Start with capacity 3"); + + Vec_Resize(array, 4); + TEST_INT_EQ(runner, Vec_Get_Size(array), 4, "Resize up"); + TEST_INT_EQ(runner, Vec_Get_Capacity(array), 4, + "Resize changes capacity"); + + Vec_Resize(array, 2); + TEST_INT_EQ(runner, Vec_Get_Size(array), 2, "Resize down"); + TEST_TRUE(runner, Vec_Fetch(array, 2) == NULL, "Resize down zaps elem"); + + Vec_Resize(array, 2); + TEST_INT_EQ(runner, Vec_Get_Size(array), 2, "Resize to same size"); + + DECREF(array); + + array = S_array_with_garbage(); + Vec_Resize(array, 40); + bool all_null = true; + for (int i = 10; i < 40; i++) { + if (Vec_Fetch(array, i) != NULL) { all_null = false; } + } + TEST_TRUE(runner, all_null, "Resize clears excised elements"); + DECREF(array); +} + +static void +test_Excise(TestBatchRunner *runner) { + Vector *wanted = Vec_new(5); + Vector *got = Vec_new(5); + + for (uint32_t i = 0; i < 5; i++) { + Vec_Push(wanted, (Obj*)Str_newf("%u32", i)); + Vec_Push(got, (Obj*)Str_newf("%u32", i)); + } + + Vec_Excise(got, 7, 1); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), + "Excise outside of range is no-op"); + + Vec_Excise(got, 2, 2); + DECREF(Vec_Delete(wanted, 2)); + DECREF(Vec_Delete(wanted, 3)); + Vec_Store(wanted, 2, Vec_Delete(wanted, 4)); + Vec_Resize(wanted, 3); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), + "Excise multiple elems"); + + Vec_Excise(got, 2, 2); + Vec_Resize(wanted, 2); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), + "Splicing too many elems truncates"); + + Vec_Excise(got, 0, 1); + Vec_Store(wanted, 0, Vec_Delete(wanted, 1)); + Vec_Resize(wanted, 1); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), + "Excise first elem"); + + DECREF(got); + DECREF(wanted); +} + +static void +test_Push_All(TestBatchRunner *runner) { + Vector *wanted = Vec_new(0); + Vector *got = Vec_new(0); + Vector *scratch = Vec_new(0); + Vector *empty = Vec_new(0); + uint32_t i; + + for (i = 0; i < 40; i++) { Vec_Push(wanted, (Obj*)Str_newf("%u32", i)); } + Vec_Push(wanted, NULL); + for (i = 0; i < 20; i++) { Vec_Push(got, (Obj*)Str_newf("%u32", i)); } + for (i = 20; i < 40; i++) { Vec_Push(scratch, (Obj*)Str_newf("%u32", i)); } + Vec_Push(scratch, NULL); + + Vec_Push_All(got, scratch); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), "Push_All"); + + Vec_Push_All(got, empty); + TEST_TRUE(runner, Vec_Equals(wanted, (Obj*)got), + "Push_All with empty array"); + + DECREF(wanted); + DECREF(got); + DECREF(scratch); + DECREF(empty); +} + +static void +test_Slice(TestBatchRunner *runner) { + Vector *array = Vec_new(0); + for (uint32_t i = 0; i < 10; i++) { Vec_Push(array, (Obj*)Str_newf("%u32", i)); } + { + Vector *slice = Vec_Slice(array, 0, 10); + TEST_TRUE(runner, Vec_Equals(array, (Obj*)slice), "Slice entire array"); + DECREF(slice); + } + { + Vector *slice = Vec_Slice(array, 0, 11); + TEST_TRUE(runner, Vec_Equals(array, (Obj*)slice), + "Exceed length"); + DECREF(slice); + } + { + Vector *wanted = Vec_new(0); + Vec_Push(wanted, (Obj*)Str_newf("9")); + Vector *slice = Vec_Slice(array, 9, 11); + TEST_TRUE(runner, Vec_Equals(slice, (Obj*)wanted), + "Exceed length, start near end"); + DECREF(slice); + DECREF(wanted); + } + { + Vector *slice = Vec_Slice(array, 0, 0); + TEST_TRUE(runner, Vec_Get_Size(slice) == 0, "empty slice"); + DECREF(slice); + } + { + Vector *slice = Vec_Slice(array, 20, 1); + TEST_TRUE(runner, Vec_Get_Size(slice) == 0, "exceed offset"); + DECREF(slice); + } + { + Vector *wanted = Vec_new(0); + Vec_Push(wanted, (Obj*)Str_newf("9")); + Vector *slice = Vec_Slice(array, 9, SIZE_MAX - 1); + TEST_TRUE(runner, Vec_Get_Size(slice) == 1, "guard against overflow"); + DECREF(slice); + DECREF(wanted); + } + DECREF(array); +} + +static void +test_Clone(TestBatchRunner *runner) { + Vector *array = Vec_new(0); + Vector *twin; + uint32_t i; + + for (i = 0; i < 10; i++) { + Vec_Push(array, (Obj*)Int32_new(i)); + } + Vec_Push(array, NULL); + twin = Vec_Clone(array); + TEST_TRUE(runner, Vec_Equals(array, (Obj*)twin), "Clone"); + TEST_TRUE(runner, Vec_Fetch(array, 1) == Vec_Fetch(twin, 1), + "Clone doesn't clone elements"); + + DECREF(array); + DECREF(twin); +} + +static void +S_overflow_Push(void *context) { + UNUSED_VAR(context); + Vector *array = Vec_new(0); + array->cap = SIZE_MAX; + array->size = array->cap; + Vec_Push(array, (Obj*)CFISH_TRUE); +} + +static void +S_overflow_Insert(void *context) { + UNUSED_VAR(context); + Vector *array = Vec_new(0); + array->cap = SIZE_MAX; + array->size = array->cap; + Vec_Insert(array, 38911, (Obj*)CFISH_TRUE); +} + +static void +S_overflow_Push_All(void *context) { + UNUSED_VAR(context); + Vector *array = Vec_new(0); + array->cap = 1000000000; + array->size = array->cap; + Vector *other = Vec_new(0); + other->cap = SIZE_MAX - array->cap + 1; + other->size = other->cap; + Vec_Push_All(array, other); +} + +static void +S_overflow_Store(void *context) { + UNUSED_VAR(context); + Vector *array = Vec_new(0); + Vec_Store(array, SIZE_MAX, (Obj*)CFISH_TRUE); +} + +static void +S_test_exception(TestBatchRunner *runner, Err_Attempt_t func, + const char *test_name) { + Err *error = Err_trap(func, NULL); + TEST_TRUE(runner, error != NULL, test_name); + DECREF(error); +} + +static void +test_exceptions(TestBatchRunner *runner) { + if (getenv("LUCY_VALGRIND")) { + SKIP(runner, 4, "memory leak"); + return; + } + S_test_exception(runner, S_overflow_Push, + "Push throws on overflow"); + S_test_exception(runner, S_overflow_Insert, + "Insert throws on overflow"); + S_test_exception(runner, S_overflow_Push_All, + "Push_All throws on overflow"); + S_test_exception(runner, S_overflow_Store, + "Store throws on overflow"); +} + +static void +test_Sort(TestBatchRunner *runner) { + Vector *array = Vec_new(8); + Vector *wanted = Vec_new(8); + + Vec_Push(array, NULL); + Vec_Push(array, (Obj*)Str_newf("aaab")); + Vec_Push(array, (Obj*)Str_newf("ab")); + Vec_Push(array, NULL); + Vec_Push(array, NULL); + Vec_Push(array, (Obj*)Str_newf("aab")); + Vec_Push(array, (Obj*)Str_newf("b")); + + Vec_Push(wanted, (Obj*)Str_newf("aaab")); + Vec_Push(wanted, (Obj*)Str_newf("aab")); + Vec_Push(wanted, (Obj*)Str_newf("ab")); + Vec_Push(wanted, (Obj*)Str_newf("b")); + Vec_Push(wanted, NULL); + Vec_Push(wanted, NULL); + Vec_Push(wanted, NULL); + + Vec_Sort(array); + TEST_TRUE(runner, Vec_Equals(array, (Obj*)wanted), "Sort with NULLs"); + + DECREF(array); + DECREF(wanted); +} + +static void +test_Grow(TestBatchRunner *runner) { + Vector *array = Vec_new(500); + uint32_t cap; + + cap = Vec_Get_Capacity(array); + TEST_TRUE(runner, cap >= 500, "Array is created with minimum capacity"); + + Vec_Grow(array, 2000); + cap = Vec_Get_Capacity(array); + TEST_TRUE(runner, cap >= 2000, "Grow to larger capacity"); + + uint32_t old_cap = cap; + Vec_Grow(array, old_cap); + cap = Vec_Get_Capacity(array); + TEST_TRUE(runner, cap >= old_cap, "Grow to same capacity"); + + Vec_Grow(array, 1000); + cap = Vec_Get_Capacity(array); + TEST_TRUE(runner, cap >= 1000, "Grow to smaller capacity"); + + DECREF(array); +} + +void +TestVector_Run_IMP(TestVector *self, TestBatchRunner *runner) { + TestBatchRunner_Plan(runner, (TestBatch*)self, 59); + test_Equals(runner); + test_Store_Fetch(runner); + test_Push_Pop_Insert(runner); + test_Delete(runner); + test_Resize(runner); + test_Excise(runner); + test_Push_All(runner); + test_Slice(runner); + test_Clone(runner); + test_exceptions(runner); + test_Sort(runner); + test_Grow(runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Test/TestVector.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestVector.cfh b/runtime/core/Clownfish/Test/TestVector.cfh new file mode 100644 index 0000000..090b8b9 --- /dev/null +++ b/runtime/core/Clownfish/Test/TestVector.cfh @@ -0,0 +1,29 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +parcel TestClownfish; + +class Clownfish::Test::TestVector + inherits Clownfish::TestHarness::TestBatch { + + inert incremented TestVector* + new(); + + void + Run(TestVector *self, TestBatchRunner *runner); +} + + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/TestHarness/TestBatchRunner.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/TestHarness/TestBatchRunner.c b/runtime/core/Clownfish/TestHarness/TestBatchRunner.c index 7183226..dbc0b99 100644 --- a/runtime/core/Clownfish/TestHarness/TestBatchRunner.c +++ b/runtime/core/Clownfish/TestHarness/TestBatchRunner.c @@ -27,7 +27,7 @@ #include "Clownfish/Err.h" #include "Clownfish/TestHarness/TestBatch.h" #include "Clownfish/TestHarness/TestFormatter.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/Class.h" struct try_run_tests_context { http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/TestHarness/TestSuite.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/TestHarness/TestSuite.c b/runtime/core/Clownfish/TestHarness/TestSuite.c index c99c761..856525b 100644 --- a/runtime/core/Clownfish/TestHarness/TestSuite.c +++ b/runtime/core/Clownfish/TestHarness/TestSuite.c @@ -28,7 +28,7 @@ #include "Clownfish/TestHarness/TestBatchRunner.h" #include "Clownfish/TestHarness/TestFormatter.h" #include "Clownfish/TestHarness/TestSuiteRunner.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/Class.h" static void @@ -42,7 +42,7 @@ TestSuite_new() { TestSuite* TestSuite_init(TestSuite *self) { - self->batches = VA_new(0); + self->batches = Vec_new(0); return self; } @@ -54,7 +54,7 @@ TestSuite_Destroy_IMP(TestSuite *self) { void TestSuite_Add_Batch_IMP(TestSuite *self, TestBatch *batch) { - VA_Push(self->batches, (Obj*)batch); + Vec_Push(self->batches, (Obj*)batch); } bool @@ -62,10 +62,10 @@ TestSuite_Run_Batch_IMP(TestSuite *self, String *class_name, TestFormatter *formatter) { S_unbuffer_stdout(); - uint32_t size = VA_Get_Size(self->batches); + uint32_t size = Vec_Get_Size(self->batches); for (uint32_t i = 0; i < size; ++i) { - TestBatch *batch = (TestBatch*)VA_Fetch(self->batches, i); + TestBatch *batch = (TestBatch*)Vec_Fetch(self->batches, i); if (Str_Equals(TestBatch_Get_Class_Name(batch), (Obj*)class_name)) { TestBatchRunner *runner = TestBatchRunner_new(formatter); @@ -84,10 +84,10 @@ TestSuite_Run_All_Batches_IMP(TestSuite *self, TestFormatter *formatter) { S_unbuffer_stdout(); TestSuiteRunner *runner = TestSuiteRunner_new(formatter); - uint32_t size = VA_Get_Size(self->batches); + uint32_t size = Vec_Get_Size(self->batches); for (uint32_t i = 0; i < size; ++i) { - TestBatch *batch = (TestBatch*)VA_Fetch(self->batches, i); + TestBatch *batch = (TestBatch*)Vec_Fetch(self->batches, i); TestSuiteRunner_Run_Batch(runner, batch); } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/TestHarness/TestSuite.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/TestHarness/TestSuite.cfh b/runtime/core/Clownfish/TestHarness/TestSuite.cfh index 52bfa2c..64e54c3 100644 --- a/runtime/core/Clownfish/TestHarness/TestSuite.cfh +++ b/runtime/core/Clownfish/TestHarness/TestSuite.cfh @@ -19,7 +19,7 @@ parcel Clownfish; /** Manage a collection of test batches. */ class Clownfish::TestHarness::TestSuite inherits Clownfish::Obj { - VArray *batches; + Vector *batches; inert incremented TestSuite* new(); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/VArray.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/VArray.c b/runtime/core/Clownfish/VArray.c deleted file mode 100644 index 8343602..0000000 --- a/runtime/core/Clownfish/VArray.c +++ /dev/null @@ -1,313 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define C_CFISH_VARRAY -#include <string.h> -#include <stdlib.h> - -#define CFISH_USE_SHORT_NAMES - -#include "Clownfish/Class.h" -#include "Clownfish/VArray.h" -#include "Clownfish/Err.h" -#include "Clownfish/Util/Memory.h" -#include "Clownfish/Util/SortUtils.h" - -static CFISH_INLINE void -SI_grow_and_oversize(VArray *self, size_t addend1, size_t addend2); - -VArray* -VA_new(size_t capacity) { - VArray *self = (VArray*)Class_Make_Obj(VARRAY); - VA_init(self, capacity); - return self; -} - -VArray* -VA_init(VArray *self, size_t capacity) { - // Init. - self->size = 0; - - // Assign. - self->cap = capacity; - - // Derive. - self->elems = (Obj**)CALLOCATE(capacity, sizeof(Obj*)); - - return self; -} - -void -VA_Destroy_IMP(VArray *self) { - if (self->elems) { - Obj **elems = self->elems; - Obj **const limit = elems + self->size; - for (; elems < limit; elems++) { - DECREF(*elems); - } - FREEMEM(self->elems); - } - SUPER_DESTROY(self, VARRAY); -} - -VArray* -VA_Clone_IMP(VArray *self) { - VArray *twin = VA_new(self->size); - twin->size = self->size; - - // Copy and incref. - Obj **elems = self->elems; - Obj **twin_elems = twin->elems; - for (size_t i = 0, max = self->size; i < max; i++) { - twin_elems[i] = INCREF(elems[i]); - } - - return twin; -} - -void -VA_Push_IMP(VArray *self, Obj *element) { - SI_grow_and_oversize(self, self->size, 1); - self->elems[self->size] = element; - self->size++; -} - -void -VA_Push_All_IMP(VArray *self, VArray *other) { - SI_grow_and_oversize(self, self->size, other->size); - - // Copy and incref. - Obj **dest = self->elems + self->size; - Obj **other_elems = other->elems; - for (size_t i = 0, max = other->size; i < max; i++) { - dest[i] = INCREF(other_elems[i]); - } - - self->size += other->size; -} - -Obj* -VA_Pop_IMP(VArray *self) { - if (!self->size) { - return NULL; - } - self->size--; - return self->elems[self->size]; -} - -void -VA_Insert_IMP(VArray *self, size_t tick, Obj *elem) { - if (tick >= self->size) { - VA_Store(self, tick, elem); - return; - } - - SI_grow_and_oversize(self, self->size, 1); - memmove(self->elems + tick + 1, self->elems + tick, - (self->size - tick) * sizeof(Obj*)); - self->elems[tick] = elem; - self->size++; -} - -void -VA_Insert_All_IMP(VArray *self, size_t tick, VArray *other) { - SI_grow_and_oversize(self, tick, other->size); - - if (tick < self->size) { - memmove(self->elems + tick + other->size, self->elems + tick, - (self->size - tick) * sizeof(Obj*)); - } - else { - memset(self->elems + self->size, 0, - (tick - self->size) * sizeof(Obj*)); - } - - // Copy and incref. - Obj **dest = self->elems + tick; - Obj **other_elems = other->elems; - for (size_t i = 0, max = other->size; i < max; i++) { - dest[i] = INCREF(other_elems[i]); - } - - self->size = tick + other->size; -} - -Obj* -VA_Fetch_IMP(VArray *self, size_t num) { - if (num >= self->size) { - return NULL; - } - - return self->elems[num]; -} - -void -VA_Store_IMP(VArray *self, size_t tick, Obj *elem) { - SI_grow_and_oversize(self, tick, 1); - if (tick < self->size) { - DECREF(self->elems[tick]); - } - else { - memset(self->elems + self->size, 0, - (tick - self->size) * sizeof(Obj*)); - self->size = tick + 1; - } - self->elems[tick] = elem; -} - -void -VA_Grow_IMP(VArray *self, size_t capacity) { - if (capacity > self->cap) { - if (capacity > SIZE_MAX / sizeof(Obj*)) { - THROW(ERR, "Array index overflow"); - } - self->elems = (Obj**)REALLOCATE(self->elems, capacity * sizeof(Obj*)); - self->cap = capacity; - } -} - -Obj* -VA_Delete_IMP(VArray *self, size_t num) { - Obj *elem = NULL; - if (num < self->size) { - elem = self->elems[num]; - self->elems[num] = NULL; - } - return elem; -} - -void -VA_Excise_IMP(VArray *self, size_t offset, size_t length) { - if (offset >= self->size) { return; } - if (length > self->size - offset) { length = self->size - offset; } - - Obj **elems = self->elems; - for (size_t i = 0; i < length; i++) { - DECREF(elems[offset + i]); - } - - size_t num_to_move = self->size - (offset + length); - memmove(self->elems + offset, self->elems + offset + length, - num_to_move * sizeof(Obj*)); - self->size -= length; -} - -void -VA_Clear_IMP(VArray *self) { - VA_Excise_IMP(self, 0, self->size); -} - -void -VA_Resize_IMP(VArray *self, size_t size) { - if (size < self->size) { - VA_Excise(self, size, self->size - size); - } - else if (size > self->size) { - VA_Grow(self, size); - memset(self->elems + self->size, 0, - (size - self->size) * sizeof(Obj*)); - } - self->size = size; -} - -size_t -VA_Get_Size_IMP(VArray *self) { - return self->size; -} - -size_t -VA_Get_Capacity_IMP(VArray *self) { - return self->cap; -} - -static int -S_default_compare(void *context, const void *va, const void *vb) { - Obj *a = *(Obj**)va; - Obj *b = *(Obj**)vb; - UNUSED_VAR(context); - if (a != NULL && b != NULL) { return Obj_Compare_To(a, b); } - else if (a == NULL && b == NULL) { return 0; } - else if (a == NULL) { return 1; } // NULL to the back - else /* b == NULL */ { return -1; } // NULL to the back -} - -void -VA_Sort_IMP(VArray *self) { - void *scratch = MALLOCATE(self->size * sizeof(Obj*)); - Sort_mergesort(self->elems, scratch, self->size, sizeof(void*), - S_default_compare, NULL); - FREEMEM(scratch); -} - -bool -VA_Equals_IMP(VArray *self, Obj *other) { - VArray *twin = (VArray*)other; - if (twin == self) { return true; } - if (!Obj_Is_A(other, VARRAY)) { return false; } - if (twin->size != self->size) { - return false; - } - else { - Obj **elems = self->elems; - Obj **twin_elems = twin->elems; - for (size_t i = 0, max = self->size; i < max; i++) { - Obj *val = elems[i]; - Obj *other_val = twin_elems[i]; - if ((val && !other_val) || (other_val && !val)) { return false; } - if (val && !Obj_Equals(val, other_val)) { return false; } - } - } - return true; -} - -VArray* -VA_Slice_IMP(VArray *self, size_t offset, size_t length) { - // Adjust ranges if necessary. - if (offset >= self->size) { - offset = 0; - length = 0; - } - else if (length > self->size - offset) { - length = self->size - offset; - } - - // Copy elements. - VArray *slice = VA_new(length); - slice->size = length; - Obj **slice_elems = slice->elems; - Obj **my_elems = self->elems; - for (size_t i = 0; i < length; i++) { - slice_elems[i] = INCREF(my_elems[offset + i]); - } - - return slice; -} - -// Ensure that the array's capacity is at least (addend1 + addend2). -// If the array must be grown, oversize the allocation. -static void -SI_grow_and_oversize(VArray *self, size_t addend1, size_t addend2) { - size_t new_size = addend1 + addend2; - // Check for overflow. - if (new_size < addend1) { - THROW(ERR, "Array index overflow"); - } - if (new_size > self->cap) { - size_t capacity = Memory_oversize(new_size, sizeof(Obj*)); - VA_Grow(self, capacity); - } -} - http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/VArray.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/VArray.cfh b/runtime/core/Clownfish/VArray.cfh deleted file mode 100644 index 27f5e4a..0000000 --- a/runtime/core/Clownfish/VArray.cfh +++ /dev/null @@ -1,143 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -parcel Clownfish; - -/** Variable-sized array. - */ -class Clownfish::VArray nickname VA inherits Clownfish::Obj { - - Obj **elems; - size_t size; - size_t cap; - - inert incremented VArray* - new(size_t capacity = 0); - - /** - * @param capacity Initial number of elements that the object will be able - * to hold before reallocation. - */ - inert VArray* - init(VArray *self, size_t capacity = 0); - - /** Push an item onto the end of a VArray. - */ - void - Push(VArray *self, decremented Obj *element = NULL); - - /** Push all the elements of another VArray onto the end of this one. - */ - void - Push_All(VArray *self, VArray *other); - - /** Pop an item off of the end of a VArray. - */ - incremented nullable Obj* - Pop(VArray *self); - - /** Insert an element at `tick` moving the following elements. - */ - void - Insert(VArray *self, size_t tick, decremented Obj *element = NULL); - - /** Inserts elements from `other` array at `tick` moving the following - * elements. - */ - void - Insert_All(VArray *self, size_t tick, VArray *other); - - /** Ensure that the VArray has room for at least `capacity` - * elements. - */ - void - Grow(VArray *self, size_t capacity); - - /** Fetch the element at `tick`. - */ - nullable Obj* - Fetch(VArray *self, size_t tick); - - /** Store an element at index `tick`, possibly displacing an - * existing element. - */ - void - Store(VArray *self, size_t tick, decremented Obj *elem = NULL); - - /** Replace an element in the VArray with NULL and return it. - * - * @return whatever was stored at `tick`. - */ - incremented nullable Obj* - Delete(VArray *self, size_t tick); - - /** Remove `length` elements from the array, starting at - * `offset`. Move elements over to fill in the gap. - */ - void - Excise(VArray *self, size_t offset, size_t length); - - /** Clone the VArray but merely increment the refcounts of its elements - * rather than clone them. - */ - public incremented VArray* - Clone(VArray *self); - - /** Sort the VArray. - */ - void - Sort(VArray *self); - - /** Set the size for the VArray. If the new size is larger than the - * current size, grow the object to accommodate NULL elements; if smaller - * than the current size, decrement and discard truncated elements. - */ - void - Resize(VArray *self, size_t size); - - /** Empty the VArray. - */ - void - Clear(VArray *self); - - /** Accessor for `size` member. - */ - public size_t - Get_Size(VArray *self); - - /** Accessor for `capacity` member. - */ - size_t - Get_Capacity(VArray *self); - - /** Return a new array consisting of elements from a contiguous slice. If - * the specified range is out of bounds, return an array with fewer - * elements -- potentially none. - * - * @param offset The index of the element to start at. - * @param length The maximum number of elements to slice. - */ - public incremented VArray* - Slice(VArray *self, size_t offset, size_t length); - - public bool - Equals(VArray *self, Obj *other); - - public void - Destroy(VArray *self); -} - - http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Vector.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Vector.c b/runtime/core/Clownfish/Vector.c new file mode 100644 index 0000000..1fa775c --- /dev/null +++ b/runtime/core/Clownfish/Vector.c @@ -0,0 +1,313 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define C_CFISH_VECTOR +#include <string.h> +#include <stdlib.h> + +#define CFISH_USE_SHORT_NAMES + +#include "Clownfish/Class.h" +#include "Clownfish/Vector.h" +#include "Clownfish/Err.h" +#include "Clownfish/Util/Memory.h" +#include "Clownfish/Util/SortUtils.h" + +static CFISH_INLINE void +SI_grow_and_oversize(Vector *self, size_t addend1, size_t addend2); + +Vector* +Vec_new(size_t capacity) { + Vector *self = (Vector*)Class_Make_Obj(VECTOR); + Vec_init(self, capacity); + return self; +} + +Vector* +Vec_init(Vector *self, size_t capacity) { + // Init. + self->size = 0; + + // Assign. + self->cap = capacity; + + // Derive. + self->elems = (Obj**)CALLOCATE(capacity, sizeof(Obj*)); + + return self; +} + +void +Vec_Destroy_IMP(Vector *self) { + if (self->elems) { + Obj **elems = self->elems; + Obj **const limit = elems + self->size; + for (; elems < limit; elems++) { + DECREF(*elems); + } + FREEMEM(self->elems); + } + SUPER_DESTROY(self, VECTOR); +} + +Vector* +Vec_Clone_IMP(Vector *self) { + Vector *twin = Vec_new(self->size); + twin->size = self->size; + + // Copy and incref. + Obj **elems = self->elems; + Obj **twin_elems = twin->elems; + for (size_t i = 0, max = self->size; i < max; i++) { + twin_elems[i] = INCREF(elems[i]); + } + + return twin; +} + +void +Vec_Push_IMP(Vector *self, Obj *element) { + SI_grow_and_oversize(self, self->size, 1); + self->elems[self->size] = element; + self->size++; +} + +void +Vec_Push_All_IMP(Vector *self, Vector *other) { + SI_grow_and_oversize(self, self->size, other->size); + + // Copy and incref. + Obj **dest = self->elems + self->size; + Obj **other_elems = other->elems; + for (size_t i = 0, max = other->size; i < max; i++) { + dest[i] = INCREF(other_elems[i]); + } + + self->size += other->size; +} + +Obj* +Vec_Pop_IMP(Vector *self) { + if (!self->size) { + return NULL; + } + self->size--; + return self->elems[self->size]; +} + +void +Vec_Insert_IMP(Vector *self, size_t tick, Obj *elem) { + if (tick >= self->size) { + Vec_Store(self, tick, elem); + return; + } + + SI_grow_and_oversize(self, self->size, 1); + memmove(self->elems + tick + 1, self->elems + tick, + (self->size - tick) * sizeof(Obj*)); + self->elems[tick] = elem; + self->size++; +} + +void +Vec_Insert_All_IMP(Vector *self, size_t tick, Vector *other) { + SI_grow_and_oversize(self, tick, other->size); + + if (tick < self->size) { + memmove(self->elems + tick + other->size, self->elems + tick, + (self->size - tick) * sizeof(Obj*)); + } + else { + memset(self->elems + self->size, 0, + (tick - self->size) * sizeof(Obj*)); + } + + // Copy and incref. + Obj **dest = self->elems + tick; + Obj **other_elems = other->elems; + for (size_t i = 0, max = other->size; i < max; i++) { + dest[i] = INCREF(other_elems[i]); + } + + self->size = tick + other->size; +} + +Obj* +Vec_Fetch_IMP(Vector *self, size_t num) { + if (num >= self->size) { + return NULL; + } + + return self->elems[num]; +} + +void +Vec_Store_IMP(Vector *self, size_t tick, Obj *elem) { + SI_grow_and_oversize(self, tick, 1); + if (tick < self->size) { + DECREF(self->elems[tick]); + } + else { + memset(self->elems + self->size, 0, + (tick - self->size) * sizeof(Obj*)); + self->size = tick + 1; + } + self->elems[tick] = elem; +} + +void +Vec_Grow_IMP(Vector *self, size_t capacity) { + if (capacity > self->cap) { + if (capacity > SIZE_MAX / sizeof(Obj*)) { + THROW(ERR, "Vector index overflow"); + } + self->elems = (Obj**)REALLOCATE(self->elems, capacity * sizeof(Obj*)); + self->cap = capacity; + } +} + +Obj* +Vec_Delete_IMP(Vector *self, size_t num) { + Obj *elem = NULL; + if (num < self->size) { + elem = self->elems[num]; + self->elems[num] = NULL; + } + return elem; +} + +void +Vec_Excise_IMP(Vector *self, size_t offset, size_t length) { + if (offset >= self->size) { return; } + if (length > self->size - offset) { length = self->size - offset; } + + Obj **elems = self->elems; + for (size_t i = 0; i < length; i++) { + DECREF(elems[offset + i]); + } + + size_t num_to_move = self->size - (offset + length); + memmove(self->elems + offset, self->elems + offset + length, + num_to_move * sizeof(Obj*)); + self->size -= length; +} + +void +Vec_Clear_IMP(Vector *self) { + Vec_Excise_IMP(self, 0, self->size); +} + +void +Vec_Resize_IMP(Vector *self, size_t size) { + if (size < self->size) { + Vec_Excise(self, size, self->size - size); + } + else if (size > self->size) { + Vec_Grow(self, size); + memset(self->elems + self->size, 0, + (size - self->size) * sizeof(Obj*)); + } + self->size = size; +} + +size_t +Vec_Get_Size_IMP(Vector *self) { + return self->size; +} + +size_t +Vec_Get_Capacity_IMP(Vector *self) { + return self->cap; +} + +static int +S_default_compare(void *context, const void *va, const void *vb) { + Obj *a = *(Obj**)va; + Obj *b = *(Obj**)vb; + UNUSED_VAR(context); + if (a != NULL && b != NULL) { return Obj_Compare_To(a, b); } + else if (a == NULL && b == NULL) { return 0; } + else if (a == NULL) { return 1; } // NULL to the back + else /* b == NULL */ { return -1; } // NULL to the back +} + +void +Vec_Sort_IMP(Vector *self) { + void *scratch = MALLOCATE(self->size * sizeof(Obj*)); + Sort_mergesort(self->elems, scratch, self->size, sizeof(void*), + S_default_compare, NULL); + FREEMEM(scratch); +} + +bool +Vec_Equals_IMP(Vector *self, Obj *other) { + Vector *twin = (Vector*)other; + if (twin == self) { return true; } + if (!Obj_Is_A(other, VECTOR)) { return false; } + if (twin->size != self->size) { + return false; + } + else { + Obj **elems = self->elems; + Obj **twin_elems = twin->elems; + for (size_t i = 0, max = self->size; i < max; i++) { + Obj *val = elems[i]; + Obj *other_val = twin_elems[i]; + if ((val && !other_val) || (other_val && !val)) { return false; } + if (val && !Obj_Equals(val, other_val)) { return false; } + } + } + return true; +} + +Vector* +Vec_Slice_IMP(Vector *self, size_t offset, size_t length) { + // Adjust ranges if necessary. + if (offset >= self->size) { + offset = 0; + length = 0; + } + else if (length > self->size - offset) { + length = self->size - offset; + } + + // Copy elements. + Vector *slice = Vec_new(length); + slice->size = length; + Obj **slice_elems = slice->elems; + Obj **my_elems = self->elems; + for (size_t i = 0; i < length; i++) { + slice_elems[i] = INCREF(my_elems[offset + i]); + } + + return slice; +} + +// Ensure that the vector's capacity is at least (addend1 + addend2). +// If the vector must be grown, oversize the allocation. +static void +SI_grow_and_oversize(Vector *self, size_t addend1, size_t addend2) { + size_t new_size = addend1 + addend2; + // Check for overflow. + if (new_size < addend1) { + THROW(ERR, "Vector index overflow"); + } + if (new_size > self->cap) { + size_t capacity = Memory_oversize(new_size, sizeof(Obj*)); + Vec_Grow(self, capacity); + } +} + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/core/Clownfish/Vector.cfh ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Vector.cfh b/runtime/core/Clownfish/Vector.cfh new file mode 100644 index 0000000..4fe17ab --- /dev/null +++ b/runtime/core/Clownfish/Vector.cfh @@ -0,0 +1,143 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +parcel Clownfish; + +/** Variable-sized array. + */ +class Clownfish::Vector nickname Vec inherits Clownfish::Obj { + + Obj **elems; + size_t size; + size_t cap; + + inert incremented Vector* + new(size_t capacity = 0); + + /** + * @param capacity Initial number of elements that the object will be able + * to hold before reallocation. + */ + inert Vector* + init(Vector *self, size_t capacity = 0); + + /** Push an item onto the end of a Vector. + */ + void + Push(Vector *self, decremented Obj *element = NULL); + + /** Push all the elements of another Vector onto the end of this one. + */ + void + Push_All(Vector *self, Vector *other); + + /** Pop an item off of the end of a Vector. + */ + incremented nullable Obj* + Pop(Vector *self); + + /** Insert an element at `tick` moving the following elements. + */ + void + Insert(Vector *self, size_t tick, decremented Obj *element = NULL); + + /** Inserts elements from `other` vector at `tick` moving the following + * elements. + */ + void + Insert_All(Vector *self, size_t tick, Vector *other); + + /** Ensure that the Vector has room for at least `capacity` + * elements. + */ + void + Grow(Vector *self, size_t capacity); + + /** Fetch the element at `tick`. + */ + nullable Obj* + Fetch(Vector *self, size_t tick); + + /** Store an element at index `tick`, possibly displacing an + * existing element. + */ + void + Store(Vector *self, size_t tick, decremented Obj *elem = NULL); + + /** Replace an element in the Vector with NULL and return it. + * + * @return whatever was stored at `tick`. + */ + incremented nullable Obj* + Delete(Vector *self, size_t tick); + + /** Remove `length` elements from the vector, starting at + * `offset`. Move elements over to fill in the gap. + */ + void + Excise(Vector *self, size_t offset, size_t length); + + /** Clone the Vector but merely increment the refcounts of its elements + * rather than clone them. + */ + public incremented Vector* + Clone(Vector *self); + + /** Sort the Vector. + */ + void + Sort(Vector *self); + + /** Set the size for the Vector. If the new size is larger than the + * current size, grow the object to accommodate NULL elements; if smaller + * than the current size, decrement and discard truncated elements. + */ + void + Resize(Vector *self, size_t size); + + /** Empty the Vector. + */ + void + Clear(Vector *self); + + /** Accessor for `size` member. + */ + public size_t + Get_Size(Vector *self); + + /** Accessor for `capacity` member. + */ + size_t + Get_Capacity(Vector *self); + + /** Return a new vector consisting of elements from a contiguous slice. If + * the specified range is out of bounds, return an vector with fewer + * elements -- potentially none. + * + * @param offset The index of the element to start at. + * @param length The maximum number of elements to slice. + */ + public incremented Vector* + Slice(Vector *self, size_t offset, size_t length); + + public bool + Equals(Vector *self, Obj *other); + + public void + Destroy(Vector *self); +} + + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/example-lang/src/CFBind.h ---------------------------------------------------------------------- diff --git a/runtime/example-lang/src/CFBind.h b/runtime/example-lang/src/CFBind.h index 5c56aed..a4d210f 100644 --- a/runtime/example-lang/src/CFBind.h +++ b/runtime/example-lang/src/CFBind.h @@ -31,7 +31,7 @@ extern "C" { #include "Clownfish/Err.h" #include "Clownfish/Hash.h" #include "Clownfish/Num.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/Class.h" /* Strip the prefix from some common symbols where we know there's no http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/example-lang/src/Clownfish/Class.c ---------------------------------------------------------------------- diff --git a/runtime/example-lang/src/Clownfish/Class.c b/runtime/example-lang/src/Clownfish/Class.c index ca0f89d..48ad548 100644 --- a/runtime/example-lang/src/Clownfish/Class.c +++ b/runtime/example-lang/src/Clownfish/Class.c @@ -42,10 +42,10 @@ cfish_Class_register_with_host(cfish_Class *singleton, cfish_Class *parent) { THROW(CFISH_ERR, "TODO"); } -cfish_VArray* +cfish_Vector* cfish_Class_fresh_host_methods(const cfish_String *class_name) { THROW(CFISH_ERR, "TODO"); - UNREACHABLE_RETURN(cfish_VArray*); + UNREACHABLE_RETURN(cfish_Vector*); } cfish_String* http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/go/clownfish/clownfish.go ---------------------------------------------------------------------- diff --git a/runtime/go/clownfish/clownfish.go b/runtime/go/clownfish/clownfish.go index 5e884a5..626633f 100644 --- a/runtime/go/clownfish/clownfish.go +++ b/runtime/go/clownfish/clownfish.go @@ -25,7 +25,7 @@ package clownfish #include "Clownfish/Class.h" #include "Clownfish/String.h" #include "Clownfish/Hash.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/String.h" #include "Clownfish/Util/Memory.h" #include "Clownfish/LockFreeRegistry.h" @@ -101,8 +101,8 @@ type implHash struct { ref *C.cfish_Hash } -type implVArray struct { - ref *C.cfish_VArray +type implVector struct { + ref *C.cfish_Vector } type implClass struct { http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/go/ext/clownfish.c ---------------------------------------------------------------------- diff --git a/runtime/go/ext/clownfish.c b/runtime/go/ext/clownfish.c index 3150dfa..bd33c56 100644 --- a/runtime/go/ext/clownfish.c +++ b/runtime/go/ext/clownfish.c @@ -32,7 +32,7 @@ #include "Clownfish/Err.h" #include "Clownfish/Util/Memory.h" #include "Clownfish/String.h" -#include "Clownfish/VArray.h" +#include "Clownfish/Vector.h" #include "Clownfish/LockFreeRegistry.h" /* These symbols must be assigned real values during Go initialization, @@ -171,10 +171,10 @@ Class_register_with_host(Class *singleton, Class *parent) { UNUSED_VAR(parent); } -VArray* +Vector* Class_fresh_host_methods(String *class_name) { UNUSED_VAR(class_name); - return VA_new(0); + return Vec_new(0); } String* http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/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 bbb7035..6d8be97 100644 --- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm +++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm @@ -493,53 +493,53 @@ sub bind_varray { ); my $xs_code = <<'END_XS_CODE'; -MODULE = Clownfish PACKAGE = Clownfish::VArray +MODULE = Clownfish PACKAGE = Clownfish::Vector SV* _clone(self) - cfish_VArray *self; + cfish_Vector *self; CODE: - RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_VA_Clone(self)); + RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Vec_Clone(self)); OUTPUT: RETVAL SV* pop(self) - cfish_VArray *self; + cfish_Vector *self; CODE: - RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_VA_Pop(self)); + RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Vec_Pop(self)); OUTPUT: RETVAL SV* delete(self, tick) - cfish_VArray *self; + cfish_Vector *self; uint32_t tick; CODE: - RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_VA_Delete(self, tick)); + RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Vec_Delete(self, tick)); OUTPUT: RETVAL void store(self, tick, value); - cfish_VArray *self; + cfish_Vector *self; uint32_t tick; cfish_Obj *value; PPCODE: { if (value) { CFISH_INCREF(value); } - CFISH_VA_Store_IMP(self, tick, value); + CFISH_Vec_Store_IMP(self, tick, value); } SV* fetch(self, tick) - cfish_VArray *self; + cfish_Vector *self; uint32_t tick; CODE: - RETVAL = CFISH_OBJ_TO_SV(CFISH_VA_Fetch(self, tick)); + RETVAL = CFISH_OBJ_TO_SV(CFISH_Vec_Fetch(self, tick)); OUTPUT: RETVAL END_XS_CODE my $binding = Clownfish::CFC::Binding::Perl::Class->new( parcel => "Clownfish", - class_name => "Clownfish::VArray", + class_name => "Clownfish::Vector", ); $binding->exclude_method($_) for @hand_rolled; $binding->append_xs($xs_code); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3fb61a74/runtime/perl/lib/Clownfish.pm ---------------------------------------------------------------------- diff --git a/runtime/perl/lib/Clownfish.pm b/runtime/perl/lib/Clownfish.pm index 51eca77..f2441c4 100644 --- a/runtime/perl/lib/Clownfish.pm +++ b/runtime/perl/lib/Clownfish.pm @@ -118,7 +118,7 @@ sub error {$Clownfish::Err::error} no strict 'refs'; my $stash = \%{"$package\::"}; my $methods - = Clownfish::VArray->new( capacity => scalar keys %$stash ); + = Clownfish::Vector->new( capacity => scalar keys %$stash ); while ( my ( $symbol, $glob ) = each %$stash ) { next if ref $glob; next unless *$glob{CODE}; @@ -224,7 +224,7 @@ sub error {$Clownfish::Err::error} } { - package Clownfish::VArray; + package Clownfish::Vector; our $VERSION = '0.004000'; $VERSION = eval $VERSION; no warnings 'redefine';
