diff --git a/stdlib/ktSrc/JavaUtil.kt b/stdlib/ktSrc/JavaUtil.kt index 64e5bf117e8..3a6761e9a26 100644 --- a/stdlib/ktSrc/JavaUtil.kt +++ b/stdlib/ktSrc/JavaUtil.kt @@ -11,7 +11,7 @@ val Collection<*>.empty : Boolean get() = isEmpty() /** Returns a new ArrayList with a variable number of initial elements */ -fun arrayList(vararg values: T) : ArrayList { +inline fun arrayList(vararg values: T) : ArrayList { val answer = ArrayList() for (v in values) answer.add(v) @@ -19,7 +19,7 @@ fun arrayList(vararg values: T) : ArrayList { } /** Returns a new HashSet with a variable number of initial elements */ -fun hashSet(vararg values: T) : HashSet { +inline fun hashSet(vararg values: T) : HashSet { val answer = HashSet() for (v in values) answer.add(v) @@ -46,7 +46,7 @@ protected fun Set.create(defaultSize: Int? = null) : Set { /** Returns true if any elements in the collection match the given predicate */ -fun java.lang.Iterable.any(predicate: fun(T): Boolean) : Boolean { +inline fun java.lang.Iterable.any(predicate: fun(T): Boolean) : Boolean { for (elem in this) { if (predicate(elem)) { return true @@ -56,7 +56,7 @@ fun java.lang.Iterable.any(predicate: fun(T): Boolean) : Boolean { } /** Returns true if all elements in the collection match the given predicate */ -fun java.lang.Iterable.all(predicate: fun(T): Boolean) : Boolean { +inline fun java.lang.Iterable.all(predicate: fun(T): Boolean) : Boolean { for (elem in this) { if (!predicate(elem)) { return false @@ -66,7 +66,7 @@ fun java.lang.Iterable.all(predicate: fun(T): Boolean) : Boolean { } /** Returns the first item in the collection which matches the given predicate or null if none matched */ -fun java.lang.Iterable.find(predicate: fun(T): Boolean) : T? { +inline fun java.lang.Iterable.find(predicate: fun(T): Boolean) : T? { for (elem in this) { if (predicate(elem)) return elem @@ -77,7 +77,7 @@ fun java.lang.Iterable.find(predicate: fun(T): Boolean) : T? { /** Returns a new collection containing all elements in this collection which match the given predicate */ // TODO using: Collection for the return type - I wonder if this exact type could be // deduced somewhat from the This.Type; e.g. returning Set on a Set, Array on Array etc -fun java.lang.Iterable.filter(predicate: fun(T): Boolean) : Collection { +inline fun java.lang.Iterable.filter(predicate: fun(T): Boolean) : Collection { val result = this.create() for (elem in this) { if (predicate(elem)) @@ -86,8 +86,47 @@ fun java.lang.Iterable.filter(predicate: fun(T): Boolean) : Collection return result } +/** + * Returns the result of transforming each item in the collection to a one or more values which + * are concatenated together into a single collection + */ +// TODO should use Iterable instead of Collection in transform? +inline fun java.lang.Iterable.flatMap(transform: fun(T): Collection) : Collection { + val result = this.create() + for (elem in this) { + val coll = transform(elem) + if (coll != null) { + for (r in coll) { + result.add(r) + } + } + } + return result +} + +/** Performs the given operation on each element inside the collection */ +inline fun java.lang.Iterable.foreach(operation: fun(element: T) : Unit) { + for (elem in this) + operation(elem) +} + +/** Creates a String from all the elements in the collection, using the seperator between them and using the given prefix and postfix if supplied */ +inline fun java.lang.Iterable.join(separator: String, prefix: String = "", postfix: String = "") : String { + val buffer = StringBuilder(prefix) + var first = true + for (elem in this) { + if (first) + first = false + else + buffer.append(separator) + buffer.append(elem) + } + buffer.append(postfix) + return buffer.toString().sure() +} + /** Returns a new collection containing the results of applying the given function to each element in this collection */ -fun java.lang.Iterable.map(transform : fun(T) : R) : Collection { +inline fun java.lang.Iterable.map(transform : fun(T) : R) : Collection { val result = this.create() for (item in this) result.add(transform(item)) @@ -95,9 +134,91 @@ fun java.lang.Iterable.map(transform : fun(T) : R) : Collection { } /** Returns a new collection containing the results of applying the given function to each element in this collection */ -fun java.util.Collection.map(transform : fun(T) : R) : Collection { +inline fun java.util.Collection.map(transform : fun(T) : R) : Collection { val result = this.create(this.size) for (item in this) result.add(transform(item)) return result -} \ No newline at end of file +} + +inline fun > java.lang.Iterable.sort() : List { + val answer = this.toList() + answer.sort() + return answer +} + +inline fun > java.lang.Iterable.sort(comparator: java.util.Comparator) : List { + val answer = this.toList() + answer.sort(comparator) + return answer +} + +/** + TODO figure out necessary variance/generics ninja stuff... :) +inline fun java.lang.Iterable.sort(transform: fun(T) : java.lang.Comparable<*>) : List { + val answer = this.toList() + val comparator = java.util.Comparator() { + fun compare(o1: T, o2: T): Int { + val v1 = transform(o1) + val v2 = transform(o2) + if (v1 == v2) { + return 0 + } else { + return v1.compareTo(v2) + } + } + } + answer.sort(comparator) + return answer +} +*/ + +inline fun java.lang.Iterable.toList() : List { + if (this is List) + return this + else { + val list = ArrayList() + for (elem in this) + list.add(elem) + return list + } +} + +inline fun java.util.Collection.toArray() : Array { + if (this is Array) + return this + else { + val answer = Array(this.size) + var idx = 0 + for (elem in this) + answer[idx++] = elem + return answer as Array + } +} + + +// List APIs + +inline fun > List.sort() : Unit { + Collections.sort(this) +} + +inline fun > List.sort(comparator: java.util.Comparator) : Unit { + Collections.sort(this, comparator) +} + +val List.head : T? + get() = this.get(0) + +val List.first : T? + get() = this.head + +val List.tail : T? + get() { + val s = this.size + return if (s > 0) this.get(s - 1) else null + + } +val List.last : T? + get() = this.tail + diff --git a/stdlib/lib/junit-4.9.jar b/testlib/lib/junit-4.9.jar similarity index 100% rename from stdlib/lib/junit-4.9.jar rename to testlib/lib/junit-4.9.jar diff --git a/stdlib/ktSrc/Test.kt b/testlib/src/Test.kt similarity index 96% rename from stdlib/ktSrc/Test.kt rename to testlib/src/Test.kt index e30921ff75a..b586a0ff4e3 100644 --- a/stdlib/ktSrc/Test.kt +++ b/testlib/src/Test.kt @@ -44,7 +44,7 @@ fun fails(block: fun() : Any) { } fun todo(block: fun(): Any) { - // Ignore the code :) + println("TODO at " + Exception().getStackTrace()?.get(1)) } /* diff --git a/testlib/test/CollectionApiCheck.kt b/testlib/test/CollectionApiCheck.kt new file mode 100644 index 00000000000..0b97d4cb974 --- /dev/null +++ b/testlib/test/CollectionApiCheck.kt @@ -0,0 +1,34 @@ +namespace test.apicheck + +import java.util.* + +trait Traversable { + + /** Returns true if any elements in the collection match the given predicate */ + fun any(predicate: fun(T): Boolean) : Boolean + + /** Returns true if all elements in the collection match the given predicate */ + fun all(predicate: fun(T): Boolean) : Boolean + + /** Returns the first item in the collection which matches the given predicate or null if none matched */ + fun find(predicate: fun(T): Boolean) : T? + + /** Returns a new collection containing all elements in this collection which match the given predicate */ + // TODO using: Collection for the return type - I wonder if this exact type could be + // deduced somewhat from the This.Type; e.g. returning Set on a Set, Array on Array etc + fun filter(predicate: fun(T): Boolean) : Collection + + /** Performs the given operation on each element inside the collection */ + fun foreach(operation: fun(element: T) : Unit) + + /** Returns a new collection containing the results of applying the given function to each element in this collection */ + fun java.lang.Iterable.map(transform : fun(T) : R) : Collection +} + +/** +TODO try use delegation here to make sure we implement all the methods in the Traversable API + +class ListImpl(coll: ArrayList) : Traversable by coll { +} + +*/ \ No newline at end of file diff --git a/stdlib/test/CollectionTest.kt b/testlib/test/CollectionTest.kt similarity index 51% rename from stdlib/test/CollectionTest.kt rename to testlib/test/CollectionTest.kt index 9b42f50bf76..8882fa699ac 100644 --- a/stdlib/test/CollectionTest.kt +++ b/testlib/test/CollectionTest.kt @@ -51,6 +51,38 @@ class CollectionTest() : TestSupport() { assertEquals("foo", f) } + fun testFlatMap() { + /** + TODO compiler bug + we should be able to remove the explicit type on the function + http://youtrack.jetbrains.net/issue/KT-849 + */ + // TODO there should be a neater way to do this :) + + val characters = arrayList('f', 'o', 'o', 'b', 'a', 'r') + /* + val characters = data.flatMap{ + Arrays.asList((it as java.lang.String).toCharArray()) as Collection + } + */ + todo { + println("Got list of characters ${characters}") + val text = characters.join("") + assertEquals("foobar", text) + } + } + + fun testForeach() { + var count = 0 + val x = data.foreach{ count += it.length } + assertEquals(6, count) + } + + fun testJoin() { + val text = data.join("-", "<", ">") + assertEquals("", text) + } + fun testMap() { /** TODO compiler bug @@ -65,4 +97,27 @@ class CollectionTest() : TestSupport() { assertEquals(arrayList(3, 3), lengths) } + fun testSort() { + val coll: List = arrayList("foo", "bar", "abc") + + // TODO fixme + // Some sort of in/out variance thing - or an issue with Java interop? + //coll.sort() + todo { + assertEquals(3, coll.size) + assertEquals(arrayList("abc", "bar", "foo"), coll) + + } + } + + fun testToArray() { + val arr = data.toArray() + println("Got array ${arr}") + todo { + assert { + arr is Array + } + } + } + } \ No newline at end of file diff --git a/testlib/test/ListTest.kt b/testlib/test/ListTest.kt new file mode 100644 index 00000000000..fc041d4362c --- /dev/null +++ b/testlib/test/ListTest.kt @@ -0,0 +1,29 @@ +namespace test.collections + +import std.test.* + +// TODO can we avoid importing all this stuff by default I wonder? +// e.g. making println and the collection builder methods public by default? +import std.io.* +import std.util.* +import java.util.* + +class ListTest() : TestSupport() { + val data = arrayList("foo", "bar") + + fun testHeadAndTail() { + val h = data.head + assertEquals("foo", h) + + val t = data.tail + assertEquals("bar", t) + } + + fun testFirstAndLast() { + val h = data.first + assertEquals("foo", h) + + val t = data.last + assertEquals("bar", t) + } +} \ No newline at end of file diff --git a/stdlib/test/SetTest.kt b/testlib/test/SetTest.kt similarity index 100% rename from stdlib/test/SetTest.kt rename to testlib/test/SetTest.kt diff --git a/testlib/testlib.iml b/testlib/testlib.iml new file mode 100644 index 00000000000..408dd5e34f8 --- /dev/null +++ b/testlib/testlib.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + +