diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/BindExtensionFunctions.kt b/libraries/sandbox/extensionTraits/src/kotlin2/BindExtensionFunctions.kt new file mode 100644 index 00000000000..048112ddcdd --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/BindExtensionFunctions.kt @@ -0,0 +1,67 @@ +package kotlin2 + +import jet.runtime.ArrayIterator + +/** + * Annotates a class used to implement extension functions + */ +annotation class extension() { +} + +/** + * Defines the extension functions on a List + */ +extension open class ListExtensions(private val that: java.util.List): CollectionExtensions(that), ListLike { + public override fun get(index: Int): T { + return that.get(index)!! + } +} + +/** + * Defines the extension functions on a Collection + */ +extension open class CollectionExtensions(private val that: java.util.Collection): CollectionLike { + public override fun iterator(): Iterator { + // TODO adapt java.util.Iterator to Iterator + throw UnsupportedOperationException() + } + public override fun size(): Int { + return that.size() + } + public override fun contains(item: T): Boolean { + return that.contains(item) + } +} + +/** + * Defines the extension functions on a Collection + */ +extension open class IteratorExtensions(private val that: java.util.Iterator): LazyTraversable { + public override fun iterator(): Iterator { + // TODO adapt java.util.Iterator to Iterator + throw UnsupportedOperationException() + } +} + +/** + * Defines the extension functions on an Array + */ +extension open class ArrayExtensions(private val that: Array): ListLike { + public override fun get(index: Int): T { + return that[index] + } + + public override fun contains(item: T): Boolean { + throw UnsupportedOperationException() + } + + public override fun iterator(): Iterator { + // TODO + //return ArrayIterator(that) + throw UnsupportedOperationException() + } + + public override fun size(): Int { + return that.size + } +} diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/CollectionLike.kt b/libraries/sandbox/extensionTraits/src/kotlin2/CollectionLike.kt new file mode 100644 index 00000000000..6cb99fd184d --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/CollectionLike.kt @@ -0,0 +1,7 @@ +package kotlin2 + +public trait CollectionLike: TraversableWithSize, EagerTraversable { + + public override abstract fun contains(item: T): Boolean + +} diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/EagerTraversable.kt b/libraries/sandbox/extensionTraits/src/kotlin2/EagerTraversable.kt new file mode 100644 index 00000000000..67a0fa63c4a --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/EagerTraversable.kt @@ -0,0 +1,94 @@ +package kotlin2 + +import java.util.ArrayList +import java.util.Collection +import java.util.List + +public trait EagerTraversable: Traversable { + /** + * Returns a list containing all elements which match the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt filter + */ + public inline fun filter(predicate: (T) -> Boolean): List = filterTo(ArrayList(), predicate) + + /** + * Returns a list containing all elements which do not match the given predicate + * + * @includeFunctionBody ../../test/CollectionTest.kt filterNot + */ + public inline fun filterNot(predicate: (T)-> Boolean): List = filterNotTo(ArrayList(), predicate) + + /** + * Returns a list containing all the non-*null* elements + * + * @includeFunctionBody ../../test/CollectionTest.kt filterNotNull + */ + public inline fun filterNotNull(): List = filterNotNullTo>(java.util.ArrayList()) + + /** + * Returns the result of transforming each element to one or more values which are concatenated together into a single collection + * + * @includeFunctionBody ../../test/CollectionTest.kt flatMap + */ + public inline fun flatMap(transform: (T)-> Collection): Collection = flatMapTo(ArrayList(), transform) + + + /** + * Returns a list containing all the non-*null* elements, throwing an [[IllegalArgumentException]] if there are any null elements + * + * @includeFunctionBody ../../test/CollectionTest.kt requireNoNulls + */ + public inline fun java.lang.Iterable?.requireNoNulls(): List { + val list = ArrayList() + for (element in this) { + if (element == null) { + throw IllegalArgumentException("null element found in $this") + } else { + list.add(element) + } + } + return list + } + + /** + * Returns a list containing the first *n* elements + * + * @includeFunctionBody ../../test/CollectionTest.kt take + */ + public inline fun take(n: Int): List { + return takeWhile(countTo(n)) + } + + /** + * Returns a list containing the first elements that satisfy the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt takeWhile + */ + public inline fun takeWhile(predicate: (T) -> Boolean): List = takeWhileTo(ArrayList(), predicate) + + /** + * Creates a copy of this collection as a [[List]] with the element added at the end + * + * @includeFunctionBody ../../test/CollectionTest.kt plus + */ + public inline fun plus(element: T): List { + val list = toCollection(ArrayList()) + list.add(element) + return list + } + + + /** + * Creates a copy of this collection as a [[List]] with all the elements added at the end + * + * @includeFunctionBody ../../test/CollectionTest.kt plusCollection + */ + public inline fun plus(elements: java.lang.Iterable): List { + val list = toCollection(ArrayList()) + list.addAll(elements.toCollection()) + return list + } + + +} \ No newline at end of file diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/Iterators.kt b/libraries/sandbox/extensionTraits/src/kotlin2/Iterators.kt new file mode 100644 index 00000000000..bda69c9d7bb --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/Iterators.kt @@ -0,0 +1,211 @@ +package kotlin2 + +import java.util.NoSuchElementException + +// not using an enum for now as JS generation doesn't support it +object State { + val Ready = 0 + val NotReady = 1 + val Done = 2 + val Failed = 3 +} + +private class FilterIterator(val iterator: Iterator, val predicate: (T)-> Boolean): AbstractIterator() { + override protected fun computeNext(): Unit { + while (iterator.hasNext) { + val next = iterator.next() + if ((predicate)(next)) { + setNext(next) + return + } + } + done() + } +} + +private class FilterNotNullIterator(val iterator: Iterator?): AbstractIterator() { + override protected fun computeNext(): Unit { + if (iterator != null) { + while (iterator.hasNext) { + val next = iterator.next() + if (next != null) { + setNext(next) + return + } + } + } + done() + } +} + +private class MapIterator(val iterator: Iterator, val transform: (T) -> R): AbstractIterator() { + override protected fun computeNext(): Unit { + if (iterator.hasNext) { + setNext((transform)(iterator.next())) + } else { + done() + } + } +} + +private class FlatMapIterator(val iterator: Iterator, val transform: (T) -> Iterator): AbstractIterator() { + var transformed: Iterator = iterate2 { null } + + override protected fun computeNext(): Unit { + while (true) { + if (transformed.hasNext) { + setNext(transformed.next()) + return + } + if (iterator.hasNext) { + transformed = (transform)(iterator.next()) + } else { + done() + return + } + } + } +} + +private class TakeWhileIterator(val iterator: Iterator, val predicate: (T) -> Boolean): AbstractIterator() { + override protected fun computeNext(): Unit { + if (iterator.hasNext) { + val item = iterator.next() + if ((predicate)(item)) { + setNext(item) + return + } + } + done() + } +} + + +/** + * A base class to simplify implementing iterators so that implementations only have to implement [[computeNext()]] + * to implement the iterator, calling [[done()]] when the iteration is complete. + */ +public abstract class AbstractIterator: Iterator { + private var state = State.NotReady + private var next: T? = null + + override val hasNext: Boolean + get() { + require(state != State.Failed) + return when (state) { + State.Done -> false + State.Ready -> true + else -> tryToComputeNext() + } + } + + override fun next(): T { + if (!hasNext) throw NoSuchElementException() + state = State.NotReady + return next.sure() + } + + + /** Returns the next element in the iteration without advancing the iteration */ + fun peek(): T { + if (!hasNext) throw NoSuchElementException() + return next.sure(); + } + + private fun tryToComputeNext(): Boolean { + state = State.Failed + computeNext(); + return state == State.Ready + } + + /** + * Computes the next item in the iterator. + * + * This callback method should call one of these two methods + * + * * [[setNext(T)]] with the next value of the iteration + * * [[done()]] to indicate there are no more elements + * + * Failure to call either method will result in the iteration terminating with a failed state + */ + abstract protected fun computeNext(): Unit + + /** + * Sets the next value in the iteration, called from the [[computeNext()]] function + */ + protected fun setNext(value: T): Unit { + next = value + state = State.Ready + } + + /** + * Sets the state to done so that the iteration terminates + */ + protected fun done() { + state = State.Done + } +} + +/** An [[Iterator]] which invokes a function to calculate the next value in the iteration until the function returns *null* */ +class FunctionIterator(val nextFunction: () -> T?): AbstractIterator() { + + override protected fun computeNext(): Unit { + val next = (nextFunction)() + if (next == null) { + done() + } else { + setNext(next) + } + } +} + +/** An [[Iterator]] which iterates over a number of iterators in sequence */ +class CompositeIterator(vararg iterators: Iterator): AbstractIterator() { + + val iteratorsIter = iterators.iterator() + var currentIter: Iterator? = null + + override protected fun computeNext(): Unit { + while (true) { + if (currentIter == null) { + if (iteratorsIter.hasNext) { + currentIter = iteratorsIter.next() + } else { + done() + return + } + } + val iter = currentIter + if (iter != null) { + if (iter.hasNext) { + setNext(iter.next()!!) + return + } else { + currentIter = null + } + } + } + } +} + +/** A singleton [[Iterator]] which invokes once over a value */ +class SingleIterator(val value: T): AbstractIterator() { + var first = true + + override protected fun computeNext(): Unit { + if (first) { + first = false + setNext(value) + } else { + done() + } + } +} + +private fun countTo(n: Int): (T) -> Boolean { + var count = 0 + return { ++count; count <= n } +} + +// TODO called iterate2 for now to avoid clash with kotlin method +public inline fun iterate2(nextFunction: () -> T?) : Iterator = FunctionIterator(nextFunction) diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/LazyTraversable.kt b/libraries/sandbox/extensionTraits/src/kotlin2/LazyTraversable.kt new file mode 100644 index 00000000000..3fd11f2293c --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/LazyTraversable.kt @@ -0,0 +1,96 @@ +package kotlin2 + +public trait LazyTraversable: Traversable { + + /** + * Returns an iterator which invokes the function to calculate the next value on each iteration until the function returns *null* + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt fibonacci + */ + public fun iterate(nextFunction: () -> T?): Iterator = FunctionIterator(nextFunction) + + /** + * Returns an iterator over elements which match the given *predicate* + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt filterAndTakeWhileExtractTheElementsWithinRange + */ + public fun filter(predicate: (T) -> Boolean): Iterator = FilterIterator(iterator(), predicate) + + /** Returns an iterator over elements which do not match the given *predicate* */ + public fun filterNot(predicate: (T) -> Boolean): Iterator = filter { !predicate(it) } + + /** Returns an iterator over non-*null* elements */ + public fun filterNotNull(): Iterator = FilterNotNullIterator(iterator()) + + /** + * Returns an iterator obtained by applying *transform*, a function transforming an object of type *T* into an object of type *R* + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt mapAndTakeWhileExtractTheTransformedElements + */ + public fun map(transform: (T) -> R): Iterator = MapIterator(iterator(), transform) + + /** + * Returns an iterator over the concatenated results of transforming each element to one or more values + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt flatMapAndTakeExtractTheTransformedElements + */ + public fun flatMap(transform: (T) -> Iterator): Iterator = FlatMapIterator(iterator(), transform) + + /** + * Creates an [[Iterator]] which iterates over this iterator then the given element at the end + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt plus + */ + public fun plus(element: T): Iterator { + return CompositeIterator(iterator(), SingleIterator(element)) + } + + + /** + * Creates an [[Iterator]] which iterates over this iterator then the following iterator + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt plusCollection + */ + public fun plus(iterator: Iterator): Iterator { + return CompositeIterator(iterator(), iterator) + } + + /** + * Creates an [[Iterator]] which iterates over this iterator then the following collection + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt plusCollection + */ + public fun plus(collection: Iterable): Iterator = plus(collection.iterator()) + + /** + * Returns an iterator containing all the non-*null* elements, lazily throwing an [[IllegalArgumentException]] + if there are any null elements + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt requireNoNulls + */ + public fun requireNoNulls(): Iterator { + // TODO since using Iterator then T can't be null ;) + return map{ + if (it == null) throw IllegalArgumentException("null element in iterator $this") else it + } + } + + + /** + * Returns an iterator restricted to the first *n* elements + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt takeExtractsTheFirstNElements + */ + public fun take(n: Int): Iterator { + var count = n + return takeWhile{ --count >= 0 } + } + + /** + * Returns an iterator restricted to the first elements that match the given *predicate* + * + * @includeFunctionBody ../../test/iterators/IteratorsTest.kt filterAndTakeWhileExtractTheElementsWithinRange + */ + public fun takeWhile(predicate: (T) -> Boolean): Iterator = TakeWhileIterator(iterator(), predicate) + +} diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/ListLike.kt b/libraries/sandbox/extensionTraits/src/kotlin2/ListLike.kt new file mode 100644 index 00000000000..d0dd32505d6 --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/ListLike.kt @@ -0,0 +1,21 @@ +package kotlin2 + +public trait ListLike: CollectionLike { + + // list like API + public abstract fun get(index: Int): T + + /** + * Get the first element in the collection. + * + * Will throw an exception if there are no elements + */ + public override fun first(): T { + return get(0) + } + + public override fun last(): T { + return get(this.size() - 1); + } + +} \ No newline at end of file diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/ReadMe.md b/libraries/sandbox/extensionTraits/src/kotlin2/ReadMe.md new file mode 100644 index 00000000000..a1349b808aa --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/ReadMe.md @@ -0,0 +1,32 @@ +## Experimental use of traits to define extension methods + +This module provides a port of the standard kotlin library into traits to more easily understand the shapes of functions and how they are grouped together, overridden and applied in different circumstances. + +* Traversable applies to all kinds of object which provide some kind of way to traverse values; so all objects like Iterable, Iterator, Collection, Array etc. +* TraversableWithSize for non-stream based collections where its fast to calculate the size +* EagerTraversable for typical collections like List, Set, Arrays where operations like filter() / flatMap() / map() are calculated eagerly for simplicity returning a List +* LazyTraversable for Iterator and streams where operations like filter() / flatMap() / map() are performed lazily returning Iterator +* CollectionLike for things like Sets where we can just iterate and know the size but cannot access by index +* ListLike for things like List and Arrays where we can access items in a collection using random access by index + +The missing bit is then how to take these traits (which have no state) and turn them into sets of extension functions on different source types. + +As an experiment, we've used annotated classes (with the extension annotation) to bind the traits to a real objects using the binding file + +* BindExensionFunctions + +The idea here is we use an annotated class with a single field (like the 'this' in an extension function), such that all the functions on the extension class can be turned into the equivalent of an extension function, replacing the 'that' field in the class with the 'this' value in the extension function. + +So we'd transform... + + extension open class CollectionExtensions(private val that: java.util.Collection): CollectionLike { + ... + } + +to be this (for each concrete method)... + + public inline fun java.util.Collection.all(predicate: (T) -> Boolean): Boolean { + for (element in this) if (!predicate(element)) return false + return true + } + diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/Traversable.kt b/libraries/sandbox/extensionTraits/src/kotlin2/Traversable.kt new file mode 100644 index 00000000000..c8bd12731ad --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/Traversable.kt @@ -0,0 +1,361 @@ +package kotlin2 + +import java.util.* + +public trait Traversable: Iterable { + + /** + * Returns *true* if all elements match the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt all + */ + public inline fun all(predicate: (T) -> Boolean): Boolean { + for (element in this) if (!predicate(element)) return false + return true + } + + /** + * Returns *true* if any elements match the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt any + */ + public inline fun any(predicate: (T) -> Boolean): Boolean { + for (element in this) if (predicate(element)) return true + return false + } + + /** + * Appends the string from all the elements separated using the *separator* and using the given *prefix* and *postfix* if supplied + * + * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will + * a special *truncated* separator (which defaults to "..." + * + * @includeFunctionBody ../../test/CollectionTest.kt appendString + */ + public inline fun appendString(buffer: Appendable, separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): Unit { + buffer.append(prefix) + var count = 0 + for (element in this) { + if (++count > 1) buffer.append(separator) + if (limit < 0 || count <= limit) { + val text = if (element == null) "null" else element.toString() + buffer.append(text) + } else break + } + if (limit >= 0 && count > limit) buffer.append(truncated) + buffer.append(postfix) + } + + /** + * Returns the number of elements which match the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt count + */ + public fun count(predicate: (T) -> Boolean): Int { + var count = 0 + for (element in this) if (predicate(element)) count++ + return count + } + + /** + * Returns the first element which matches the given *predicate* or *null* if none matched + * + * @includeFunctionBody ../../test/CollectionTest.kt find + */ + public inline fun find(predicate: (T) -> Boolean): T? { + for (element in this) if (predicate(element)) return element + return null + } + + /** + * Filters all elements which match the given predicate into the given list + * + * @includeFunctionBody ../../test/CollectionTest.kt filterIntoLinkedList + */ + public inline fun > filterTo(result: C, predicate: (T) -> Boolean): C { + for (element in this) if (predicate(element)) result.add(element) + return result + } + + /** + * Returns a list containing all elements which do not match the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt filterNotIntoLinkedList + */ + public inline fun > filterNotTo(result: C, predicate: (T) -> Boolean): C { + for (element in this) if (!predicate(element)) result.add(element) + return result + } + + /** + * Filters all non-*null* elements into the given list + * + * @includeFunctionBody ../../test/CollectionTest.kt filterNotNullIntoLinkedList + */ + public inline fun > java.lang.Iterable?.filterNotNullTo(result: C): C { + if (this != null) { + for (element in this) if (element != null) result.add(element) + } + return result + } + + /** + * Returns the result of transforming each element to one or more values which are concatenated together into a single list + * + * @includeFunctionBody ../../test/CollectionTest.kt flatMap + */ + public inline fun flatMapTo(result: Collection, transform: (T) -> Collection): Collection { + for (element in this) { + val list = transform(element) + if (list != null) { + for (r in list) result.add(r) + } + } + return result + } + + /** + * Performs the given *operation* on each element + * + * @includeFunctionBody ../../test/CollectionTest.kt forEach + */ + public inline fun forEach(operation: (T) -> Unit): Unit = for (element in this) operation(element) + + /** + * Folds all elements from from left to right with the *initial* value to perform the operation on sequential pairs of elements + * + * @includeFunctionBody ../../test/CollectionTest.kt fold + */ + public inline fun fold(initial: T, operation: (T, T) -> T): T { + var answer = initial + for (element in this) answer = operation(answer, element) + return answer + } + + /** + * Folds all elements from right to left with the *initial* value to perform the operation on sequential pairs of elements + * + * @includeFunctionBody ../../test/CollectionTest.kt foldRight + */ + public inline fun foldRight(initial: T, operation: (T, T) -> T): T = reverse().fold(initial, {x, y -> operation(y, x)}) + + + /** + * Applies binary operation to all elements of iterable, going from left to right. + * Similar to fold function, but uses the first element as initial value + * + * @includeFunctionBody ../../test/CollectionTest.kt reduce + */ + public inline fun reduce(operation: (T, T) -> T): T { + val iter = this.iterator()!! + if (!iter.hasNext) { + throw UnsupportedOperationException("Empty iterable can't be reduced") + } + + var result: T = iter.next() //compiler doesn't understand that result will initialized anyway + while (iter.hasNext) { + result = operation(result, iter.next()) + } + + return result + } + + /** + * Applies binary operation to all elements of iterable, going from right to left. + * Similar to foldRight function, but uses the last element as initial value + * + * @includeFunctionBody ../../test/CollectionTest.kt reduceRight + */ + public inline fun reduceRight(operation: (T, T) -> T): T = reverse().reduce { x, y -> operation(y, x) } + + + /** + * Groups the elements in the collection into a new [[Map]] using the supplied *toKey* function to calculate the key to group the elements by + * + * @includeFunctionBody ../../test/CollectionTest.kt groupBy + */ + public inline fun groupBy(toKey: (T) -> K): Map> = groupByTo(HashMap>(), toKey) + + /** + * Groups the elements in the collection into the given [[Map]] using the supplied *toKey* function to calculate the key to group the elements by + * + * @includeFunctionBody ../../test/CollectionTest.kt groupBy + */ + public inline fun groupByTo(result: Map>, toKey: (T) -> K): Map> { + for (element in this) { + val key = toKey(element) + val list = result.getOrPut(key) { ArrayList() } + list.add(element) + } + return result + } + + /** + * Creates a string from all the elements separated using the *separator* and using the given *prefix* and *postfix* if supplied. + * + * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will + * a special *truncated* separator (which defaults to "..." + * + * @includeFunctionBody ../../test/CollectionTest.kt makeString + */ + public inline fun makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String { + val buffer = StringBuilder() + appendString(buffer, separator, prefix, postfix, limit, truncated) + return buffer.toString().sure() + } + + /** Returns a list containing the everything but the first elements that satisfy the given *predicate* */ + public inline fun > dropWhileTo(result: L, predicate: (T) -> Boolean): L { + var start = true + for (element in this) { + if (start && predicate(element)) { + // ignore + } else { + start = false + result.add(element) + } + } + return result + } + + /** Returns a list containing the first elements that satisfy the given *predicate* */ + public inline fun > takeWhileTo(result: C, predicate: (T) -> Boolean): C { + for (element in this) if (predicate(element)) result.add(element) else break + return result + } + + /** Copies all elements into the given collection */ + public inline fun > toCollection(result: C): C { + for (element in this) result.add(element) + return result + } + + /** + * Reverses the order the elements into a list + * + * @includeFunctionBody ../../test/CollectionTest.kt reverse + */ + public inline fun reverse(): List { + val list = toList() + Collections.reverse(list) + return list + } + + /** Copies all elements into a [[LinkedList]] */ + public inline fun toLinkedList(): LinkedList = toCollection(LinkedList()) + + /** Copies all elements into a [[List]] */ + public inline fun toList(): List = toCollection(ArrayList()) + + /** Copies all elements into a [[List] */ + public inline fun toCollection(): Collection = toCollection(ArrayList()) + + /** Copies all elements into a [[Set]] */ + public inline fun toSet(): Set = toCollection(HashSet()) + + /** + TODO figure out necessary variance/generics ninja stuff... :) + public inline fun toSortedList(transform: fun(T) : java.lang.Comparable<*>) : List { + val answer = this.toList() + answer.sort(transform) + return answer + } + */ + + + /** + * Returns a list containing everything but the first *n* elements + * + * @includeFunctionBody ../../test/CollectionTest.kt drop + */ + public inline fun drop(n: Int): List { + return dropWhile(countTo(n)) + } + + /** + * Returns a list containing the everything but the first elements that satisfy the given *predicate* + * + * @includeFunctionBody ../../test/CollectionTest.kt dropWhile + */ + public inline fun dropWhile(predicate: (T) -> Boolean): List = dropWhileTo(ArrayList(), predicate) + + /** + * Count the number of elements in collection. + * + * If base collection implements [[Collection]] interface method [[Collection.size()]] will be used. + * Otherwise, this method determines the count by iterating through the all items. + */ + public fun count(): Int { + var number: Int = 0 + for (elem in this) { + ++number + } + return number + } + + /** + * Get the first element in the collection. + * + * Will throw an exception if there are no elements + */ + // TODO: Specify type of the exception + public fun first(): T { + return this.iterator()!!.next() + } + + /** + * Get the last element in the collection. + * + * If base collection implements [[List]] interface, the combination of size() and get() + * methods will be used for getting last element. Otherwise, this method determines the + * last item by iterating through the all items. + * + * Will throw an exception if there are no elements. + * + * @includeFunctionBody ../../test/CollectionTest.kt last + */ + // TODO: Specify type of the exception + public fun last(): T { + val iterator = this.iterator()!! + var last: T = iterator.next() + + while (iterator.hasNext) { + last = iterator.next() + } + + return last; + } + + /** + * Checks if collection contains given item. + * + * Method checks equality of the objects with T.equals method. + * If collection implements [[java.util.AbstractCollection]] an overridden implementation of the contains + * method will be used. + */ + public fun contains(item: T): Boolean { + for (var elem in this) { + if (elem == item) { + return true + } + } + return false + } + + /** + * Convert collection of arbitrary elements to collection of tuples of the index and the element + * + * @includeFunctionBody ../../test/ListTest.kt withIndices + */ + /* + public fun withIndices(): java.lang.Iterable<#(Int, T)> { + return object : java.lang.Iterable<#(Int, T)> { + public override fun iterator(): java.util.Iterator<#(Int, T)> { + return NumberedIterator(iterator()) + } + } + } + */ +} + + diff --git a/libraries/sandbox/extensionTraits/src/kotlin2/TraversableWithSize.kt b/libraries/sandbox/extensionTraits/src/kotlin2/TraversableWithSize.kt new file mode 100644 index 00000000000..faef1651b1c --- /dev/null +++ b/libraries/sandbox/extensionTraits/src/kotlin2/TraversableWithSize.kt @@ -0,0 +1,18 @@ +package kotlin2 + +/** + */ +public trait TraversableWithSize: Traversable { + public abstract fun size(): Int + + + /** + * Count the number of elements in collection. + * + * If base collection implements [[Collection]] interface method [[Collection.size()]] will be used. + * Otherwise, this method determines the count by iterating through the all items. + */ + public override fun count(): Int { + return size() + } +}