399 lines
10 KiB
Plaintext
399 lines
10 KiB
Plaintext
package lyng.stdlib
|
|
|
|
extern fun flow(builder: FlowBuilder.()->Void): Flow
|
|
|
|
/* Built-in exception type. */
|
|
extern class Exception
|
|
extern class IllegalArgumentException
|
|
extern class NotImplementedException
|
|
extern class Delegate
|
|
extern class Iterable<T> {
|
|
fun iterator(): Iterator<T>
|
|
fun forEach(action: (T)->Void): Void
|
|
fun map<R>(transform: (T)->R): List<R>
|
|
fun toList(): List<T>
|
|
}
|
|
|
|
extern class Iterator<T> {
|
|
fun hasNext(): Bool
|
|
fun next(): T
|
|
fun cancelIteration(): Void
|
|
fun toList(): List<T>
|
|
}
|
|
|
|
extern class Collection<T> : Iterable<T> {
|
|
}
|
|
|
|
extern class Array<T> : Collection<T> {
|
|
}
|
|
|
|
extern class List<T> : Array<T> {
|
|
fun add(value: T, more...): Void
|
|
}
|
|
|
|
extern class Set<T> : Collection<T> {
|
|
}
|
|
|
|
extern class Map<K,V> {
|
|
}
|
|
|
|
extern class MapEntry<K,V>
|
|
|
|
// Built-in math helpers (implemented in host runtime).
|
|
extern fun abs(x: Object): Real
|
|
extern fun ln(x: Object): Real
|
|
extern fun pow(x: Object, y: Object): Real
|
|
extern fun sqrt(x: Object): Real
|
|
|
|
// Last regex match result, updated by =~ / !~.
|
|
var $~: Object? = null
|
|
|
|
/*
|
|
Wrap a builder into a zero-argument thunk that computes once and caches the result.
|
|
The first call invokes builder() and stores the value; subsequent calls return the cached value.
|
|
*/
|
|
fun cached<T>(builder: ()->T): ()->T {
|
|
var calculated: Bool = false
|
|
var value: Object? = null
|
|
{
|
|
if( !calculated ) {
|
|
value = builder()
|
|
calculated = true
|
|
}
|
|
value as T
|
|
}
|
|
}
|
|
/* Filter elements of this iterable using the provided predicate and provide a flow
|
|
of results. Coudl be used to map infinte flows, etc.
|
|
*/
|
|
fun Iterable<T>.filterFlow(predicate: (T)->Bool): Flow<T> {
|
|
val list = this
|
|
flow {
|
|
for( item in list ) {
|
|
if( predicate(item) ) {
|
|
emit(item)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Filter this iterable and return List of elements
|
|
*/
|
|
fun Iterable<T>.filter(predicate: (T)->Bool): List<T> {
|
|
var result: List<T> = List()
|
|
for( item in this ) if( predicate(item) ) result += item
|
|
result
|
|
}
|
|
|
|
/*
|
|
Count all items in this iterable for which predicate returns true
|
|
*/
|
|
fun Iterable<T>.count(predicate: (T)->Bool): Int {
|
|
var hits = 0
|
|
this.forEach {
|
|
if( predicate(it) ) hits++
|
|
}
|
|
hits
|
|
}
|
|
/*
|
|
filter out all null elements from this collection (Iterable); flow of
|
|
non-null elements is returned
|
|
*/
|
|
fun Iterable<T>.filterFlowNotNull(): Flow<T> {
|
|
filterFlow { it != null }
|
|
}
|
|
|
|
/* Filter non-null elements and collect them into a List
|
|
*/
|
|
fun Iterable<T>.filterNotNull(): List<T> {
|
|
filter { it != null }
|
|
}
|
|
|
|
/* Skip the first N elements of this iterable. */
|
|
fun Iterable<T>.drop(n: Int): List<T> {
|
|
var cnt = 0
|
|
filter { cnt++ >= n }
|
|
}
|
|
|
|
/* Return the first element or throw if the iterable is empty. */
|
|
val Iterable<T>.first: T get() {
|
|
val i: Iterator<T> = iterator()
|
|
if( !i.hasNext() ) throw NoSuchElementException()
|
|
i.next().also { i.cancelIteration() }
|
|
}
|
|
|
|
/*
|
|
Return the first element that matches the predicate or throws
|
|
NuSuchElementException
|
|
*/
|
|
fun Iterable<T>.findFirst(predicate: (T)->Bool): T {
|
|
for( x in this ) {
|
|
if( predicate(x) )
|
|
break x
|
|
}
|
|
else throw NoSuchElementException()
|
|
}
|
|
|
|
/*
|
|
return the first element matching the predicate or null
|
|
*/
|
|
fun Iterable<T>.findFirstOrNull(predicate: (T)->Bool): T? {
|
|
for( x in this ) {
|
|
if( predicate(x) )
|
|
break x
|
|
}
|
|
else null
|
|
}
|
|
|
|
|
|
/* Return the last element or throw if the iterable is empty. */
|
|
val Iterable<T>.last: T get() {
|
|
var found = false
|
|
var element: Object = Unset
|
|
for( i in this ) {
|
|
element = i
|
|
found = true
|
|
}
|
|
if( !found ) throw NoSuchElementException()
|
|
element as T
|
|
}
|
|
|
|
/* Emit all but the last N elements of this iterable. */
|
|
fun Iterable<T>.dropLast(n: Int): Flow<T> {
|
|
val list = this
|
|
val buffer = RingBuffer(n)
|
|
flow {
|
|
for( item in list ) {
|
|
if( buffer.size == n )
|
|
emit( buffer.first() )
|
|
buffer += item
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return the last N elements of this iterable as a buffer/list. */
|
|
fun Iterable<T>.takeLast(n: Int): RingBuffer<T> {
|
|
val buffer: RingBuffer<T> = RingBuffer(n)
|
|
for( item in this ) buffer += item
|
|
buffer
|
|
}
|
|
|
|
/* Join elements into a string with a separator (separator parameter) and optional transformer. */
|
|
fun Iterable<T>.joinToString(separator: String=" ", transformer: (T)->Object = { it }): String {
|
|
var result: String? = null
|
|
for( part in this ) {
|
|
val transformed = transformer(part).toString()
|
|
if( result == null ) result = transformed
|
|
else result = (result as String) + separator + transformed
|
|
}
|
|
result ?: ""
|
|
}
|
|
|
|
/* Return true if any element matches the predicate. */
|
|
fun Iterable<T>.any(predicate: (T)->Bool): Bool {
|
|
for( i in this ) {
|
|
if( predicate(i) )
|
|
break true
|
|
} else false
|
|
}
|
|
|
|
/* Return true if all elements match the predicate. */
|
|
fun Iterable<T>.all(predicate: (T)->Bool): Bool {
|
|
!any { !predicate(it) }
|
|
}
|
|
|
|
/* Sum all elements; returns null for empty collections. */
|
|
fun Iterable<T>.sum(): T? {
|
|
val i: Iterator<T> = iterator()
|
|
if( i.hasNext() ) {
|
|
var result = i.next()
|
|
while( i.hasNext() ) result += i.next()
|
|
result
|
|
}
|
|
else null
|
|
}
|
|
|
|
/* Sum mapped values of elements; returns null for empty collections. */
|
|
fun Iterable<T>.sumOf<R>(f: (T)->R): R? {
|
|
val i: Iterator<T> = iterator()
|
|
if( i.hasNext() ) {
|
|
var result = f(i.next())
|
|
while( i.hasNext() ) result += f(i.next())
|
|
result
|
|
}
|
|
else null
|
|
}
|
|
|
|
/* Minimum value of the given function applied to elements of the collection. */
|
|
fun Iterable<T>.minOf<R>(lambda: (T)->R): R {
|
|
val i: Iterator<T> = iterator()
|
|
var minimum = lambda( i.next() )
|
|
while( i.hasNext() ) {
|
|
val x = lambda(i.next())
|
|
if( x < minimum ) minimum = x
|
|
}
|
|
minimum
|
|
}
|
|
|
|
/* Maximum value of the given function applied to elements of the collection. */
|
|
fun Iterable<T>.maxOf<R>(lambda: (T)->R): R {
|
|
val i: Iterator<T> = iterator()
|
|
var maximum = lambda( i.next() )
|
|
while( i.hasNext() ) {
|
|
val x = lambda(i.next())
|
|
if( x > maximum ) maximum = x
|
|
}
|
|
maximum
|
|
}
|
|
|
|
/* Return elements sorted by natural order. */
|
|
fun Iterable<T>.sorted(): List<T> {
|
|
sortedWith { a, b -> a <=> b }
|
|
}
|
|
|
|
/* Return elements sorted by the key selector. */
|
|
fun Iterable<T>.sortedBy<R>(predicate: (T)->R): List<T> {
|
|
sortedWith { a, b -> predicate(a) <=> predicate(b) }
|
|
}
|
|
|
|
/* Return a shuffled copy of the iterable as a list. */
|
|
fun Iterable<T>.shuffled(): List<T> {
|
|
val list: List<T> = toList()
|
|
list.shuffle()
|
|
list
|
|
}
|
|
|
|
/*
|
|
Returns a single list of all elements from all collections in the given collection.
|
|
@return List
|
|
*/
|
|
fun Iterable<Iterable<T>>.flatten(): List<T> {
|
|
var result: List<T> = List()
|
|
forEach { i ->
|
|
i.forEach { result += it }
|
|
}
|
|
result
|
|
}
|
|
|
|
/*
|
|
Returns a single list of all elements yielded from results of transform function being
|
|
invoked on each element of original collection.
|
|
*/
|
|
fun Iterable<T>.flatMap<R>(transform: (T)->Iterable<R>): List<R> {
|
|
val mapped: List<Iterable<R>> = map(transform)
|
|
mapped.flatten()
|
|
}
|
|
|
|
/* Return string representation like [a,b,c]. */
|
|
override fun List<T>.toString() {
|
|
var first = true
|
|
var result = "["
|
|
for (item in this) {
|
|
if (!first) result += ","
|
|
result += item.toString()
|
|
first = false
|
|
}
|
|
result + "]"
|
|
}
|
|
|
|
/* Sort list in-place by key selector. */
|
|
fun List<T>.sortBy<R>(predicate: (T)->R): Void {
|
|
sortWith { a, b -> predicate(a) <=> predicate(b) }
|
|
}
|
|
|
|
/* Sort list in-place by natural order. */
|
|
fun List<T>.sort(): Void {
|
|
sortWith { a, b -> a <=> b }
|
|
}
|
|
|
|
/* Print this exception and its stack trace to standard output. */
|
|
fun Exception.printStackTrace(): Void {
|
|
println(this)
|
|
for( entry in stackTrace ) {
|
|
println("\tat "+entry.toString())
|
|
}
|
|
}
|
|
|
|
/* Compile this string into a regular expression. */
|
|
val String.re: Regex get() = Regex(this)
|
|
|
|
fun TODO(message: Object?=null): Void {
|
|
throw "not implemented"
|
|
}
|
|
|
|
/*
|
|
Provides different access types for delegates.
|
|
Used in the 'bind' hook to validate delegate usage.
|
|
*/
|
|
enum DelegateAccess {
|
|
Val,
|
|
Var,
|
|
Callable
|
|
}
|
|
|
|
/*
|
|
Base interface for all delegates.
|
|
Implementing this interface is optional as Lyng uses dynamic dispatch,
|
|
but it is recommended for documentation and clarity.
|
|
*/
|
|
interface Delegate<T,ThisRefType=Void> {
|
|
/* Called when a delegated 'val' or 'var' is read. */
|
|
fun getValue(thisRef: ThisRefType, name: String): T = TODO("delegate getter is not implemented")
|
|
|
|
/* Called when a delegated 'var' is written. */
|
|
fun setValue(thisRef: ThisRefType, name: String, newValue: T): Void = TODO("delegate setter is not implemented")
|
|
|
|
/* Called when a delegated function is invoked. */
|
|
fun invoke(thisRef: ThisRefType, name: String, args...): Object = TODO("delegate invoke is not implemented")
|
|
|
|
/*
|
|
Called once during initialization to configure or validate the delegate.
|
|
Should return the delegate object to be used (usually 'this').
|
|
*/
|
|
fun bind(name: String, access: DelegateAccess, thisRef: ThisRefType): Object = this
|
|
}
|
|
|
|
/*
|
|
Executes the block with `this` set to self and
|
|
returns what the block returns.
|
|
*/
|
|
fun with<T,R>(self: T, block: T.()->R): R {
|
|
block(self)
|
|
}
|
|
|
|
/*
|
|
Standard implementation of a lazy-initialized property delegate.
|
|
The provided creator lambda is called once on the first access to compute the value.
|
|
Can only be used with 'val' properties.
|
|
*/
|
|
class lazy<T,ThisRefType=Object>(creatorParam: ThisRefType.()->T) : Delegate<T,ThisRefType> {
|
|
private val creator: ThisRefType.()->T = creatorParam
|
|
private var value = Unset
|
|
|
|
override fun bind(name: String, access: DelegateAccess, thisRef: ThisRefType): Object {
|
|
if (access != DelegateAccess.Val) throw "lazy delegate can only be used with 'val'"
|
|
this
|
|
}
|
|
|
|
override fun getValue(thisRef: ThisRefType, name: String): T {
|
|
if (value == Unset)
|
|
value = with(thisRef,creator)
|
|
value as T
|
|
}
|
|
}
|
|
|
|
/* Represents a single stack trace element. */
|
|
class StackTraceEntry(
|
|
val sourceName: String,
|
|
val line: Int,
|
|
val column: Int,
|
|
val sourceString: String
|
|
) {
|
|
val at by lazy { "%s:%s:%s"(sourceName,line+1,column+1) }
|
|
/* Formatted representation: source:line:column: text. */
|
|
override fun toString() {
|
|
"%s: %s"(at, sourceString)
|
|
}
|
|
}
|