package me.alex_s168.kotlin_bits import kotlinx.io.* import kotlinx.io.files.Path import kotlinx.io.files.SystemFileSystem import kotlin.math.max import kotlin.math.min interface IndexableSequence: Sequence { operator fun get(index: Int): T } data class Obj(val v: T) data class MutObj(val v: T) fun lazySequence(vararg init: Pair, default: Obj?, f: (Int, (Int) -> T) -> T): IndexableSequence = object : IndexableSequence { val map = mutableMapOf(*init) var current: Int? = null fun comp(iIn: Int): T { val i = max(0, iIn) if (current == i) return (default ?: throw Exception("recursion detected")).v return map[i] ?: let { current = i val res = f(i, ::comp) map[i] = res current = null res } } override fun get(index: Int) = comp(index) override fun iterator(): Iterator = object : Iterator { override fun hasNext() = true private var i = 0 override fun next(): T = comp(i ++) } } fun easySequence(vararg init: Pair, f: (Int, (Int) -> T?) -> T?): Sequence = lazySequence(*init, default = Obj(null)) { i, ff -> f(i) { index -> var indexC = index var v: T? = null while (indexC > 0 && v == null) v = ff(indexC --) v } } fun Sequence.easyMappingSequence(vararg init: Pair, f: (Int, (Int) -> T?, (Int) -> I) -> T?): Sequence { val indexable = this.asIndexable() return easySequence(*init) { i, ff -> f(i, ff, indexable::get) }.limitBy(indexable) .removeNull() } fun IndexableSequence.modifier(mod: (Sequence) -> Sequence) = object : IndexableSequence { val other = mod(this@modifier) override fun iterator(): Iterator = other.iterator() override fun get(index: Int): T = this@modifier[index] } fun Sequence.removeNull(): Sequence = mapNotNull { it } fun IndexableSequence.removeNull(): IndexableSequence = modifier { it.removeNull() } fun Sequence.limitBy(other: Sequence): Sequence = object : Sequence { override fun iterator(): Iterator = object : Iterator { val s = this@limitBy.iterator() val o = other.iterator() override fun hasNext(): Boolean = o.hasNext() && s.hasNext() override fun next(): A = s.next().also { o.next() } } } fun IndexableSequence.limitBy(other: Sequence): IndexableSequence = modifier { it.limitBy(other) } fun Sequence.asIndexable(): IndexableSequence { if (this is IndexableSequence) return this return object : IndexableSequence { val iter = this@asIndexable.iterator() val values = mutableListOf() override fun get(index: Int): T { if (index >= values.size) { repeat(index + 1 - values.size) { values.add(iter.next()) } } return values[index] } override fun iterator(): Iterator = object : Iterator { var i = 0 override fun hasNext(): Boolean = i < values.size || iter.hasNext() override fun next(): T = get(i ++) } } } typealias Operator = (I) -> O fun caching(tiedGet: () -> T, calc: (T) -> O) = object : Lazy { private var lastTiedV = tiedGet() private var lastV: O? = null override val value: O get() { val nTied = tiedGet() if (lastTiedV != nTied) { lastTiedV = nTied lastV = calc(nTied) return lastV!! } if (lastV == null) lastV = calc(nTied) return lastV!! } override fun isInitialized(): Boolean = lastTiedV == tiedGet() && lastV != null } fun selfInitializingSequence(block: () -> Sequence): Sequence = object : Sequence { val seq by lazy(block) inner class Iter : Iterator { val iter = seq.iterator() override fun hasNext(): Boolean = iter.hasNext() override fun next(): T = iter.next() } override fun iterator(): Iterator = Iter() } class OperationChain private constructor( private val impl: Impl = Impl() ) { private var until = 0 private class Impl { val seqe = mutableListOf<(Sequence) -> Sequence>() var finalized = false fun add(op: Operator<*, *>) { seqe += { seq: Sequence -> seq.map(op as Operator) } } fun addFlat(op: Operator<*, Sequence<*>>) { seqe += { seq: Sequence -> seq.flatMap(op as Operator>) } } } fun map(op: Operator): OperationChain = OperationChain(impl.also { it.add(op) }) .also { it.until = this.until + 1 } fun flatMap(op: Operator>): OperationChain = OperationChain(impl.also { it.addFlat(op) }) .also { it.until = this.until + 1 } fun map(op: OperationChain): OperationChain { if (!op.impl.finalized) throw Exception("Can not map un-finalized operation chain onto operation chain!") return flatMap(op::process) } fun modifier(op: Operator, Sequence>): OperationChain = OperationChain(impl.also { it.seqe.add(op as (Sequence) -> Sequence) }) .also { it.until = this.until + 1 } fun finalize(): OperationChain { if (impl.finalized) throw Exception("Can't finalize a finalized OperationChain!") impl.finalized = true return this } fun process(v: I): Sequence = selfInitializingSequence { var seq = sequenceOf(v) impl.seqe .asSequence() .take(until) .forEach { op -> seq = op(seq) } seq as Sequence } fun processAll(v: Sequence): Sequence = v.flatMap { process(it) } companion object { internal fun create(): OperationChain = OperationChain() } } class Contents internal constructor( private val iterable: Iterable ): Iterable { override fun iterator(): Iterator = iterable.iterator() override fun equals(other: Any?): Boolean { if (other !is Contents<*>) return false val it1 = this.iterable.iterator() val it2 = other.iterable.iterator() while (true) { val hasNext1 = it1.hasNext() val hasNext2 = it2.hasNext() if ((hasNext1 && !hasNext2) || (hasNext2 && !hasNext1)) return false if (!hasNext1) return true if (it1.next() != it2.next()) return false } } override fun hashCode(): Int = iterable.hashCode() override fun toString(): String = joinToString( separator = ", ", prefix = "[", postfix = "]" ) { it.toString() } } val Iterable.contents get() = Contents(this) val Sequence.contents get() = Contents(this.asIterable()) val Array.contents get() = Contents(this.asIterable()) fun Sequence.map(chain: OperationChain): Sequence = chain.processAll(this) fun chain(): OperationChain = OperationChain.create() fun OperationChain.chunked(size: Int): OperationChain> = modifier { it.chunked(size) } fun OperationChain.chunked(size: Int, transform: (List) -> R): OperationChain = modifier { it.chunked(size, transform) } fun OperationChain.filter(predicate: (O) -> Boolean): OperationChain = modifier { it.filter(predicate) } fun MutableList.removeFirst(count: Int) { repeat(count) { removeFirst() } } fun MutableList.removeLast(count: Int) { repeat(count) { removeLast() } } interface BatchIterator: Iterator { fun next(limit: Int): List fun next(dest: Array): Int fun next(dest: MutableList, limit: Int) } interface ByteBatchIterator: BatchIterator { fun nextBytes(limit: Int): ByteArray fun nextBytes(dest: ByteArray): Int } interface BatchSequence: Sequence { override fun iterator(): BatchIterator } interface ByteBatchSequence: BatchSequence { override fun iterator(): ByteBatchIterator } /** * Batches all get operations on the sequence. */ fun BatchSequence.batched(count: Int): BatchSequence = object : BatchSequence { inner class Iter: BatchIterator { val parent = this@batched.iterator() var batch = mutableListOf() override fun next(limit: Int): List { if (!hasNext()) throw Exception("no next") val c = min(limit, batch.size) val ret = batch.take(c) batch.removeFirst(c) return ret } override fun next(dest: MutableList, limit: Int) { if (!hasNext()) throw Exception("no next") val c = min(limit, batch.size) dest.addAll(batch.subList(0, max(0, c-1))) batch.removeFirst(c) return } override fun next(dest: Array): Int { if (!hasNext()) throw Exception("no next") val c = min(dest.size, batch.size) batch.subList(0, max(0, c-1)).forEachIndexed { i, t -> dest[i] = t } batch.removeFirst(c) return c } override fun next(): T { if (!hasNext()) throw Exception("no next") val v = batch.first() batch.removeFirst() return v } override fun hasNext(): Boolean { while (batch.isEmpty()) { if (!parent.hasNext()) return false parent.next(batch, count) } return true } } override fun iterator(): BatchIterator = Iter() } fun Sequence.asBatch(): BatchSequence = object : BatchSequence { inner class Iter: BatchIterator { var iter = this@asBatch.iterator() override fun next(limit: Int): List = mutableListOf() .also { next(it, limit) } override fun next(dest: MutableList, limit: Int) { for (i in 0..): Int { var i = 0 while (i < dest.size) { if (!iter.hasNext()) break dest[i ++] = iter.next() } return i } override fun next(): T { return iter.next() } override fun hasNext(): Boolean { return iter.hasNext() } } override fun iterator(): BatchIterator = Iter() } /* # Batched sequences ## Source You should make all your sources return `BatchSequence` and then you can use the `.batched(count: Int)` function to drastically decrease the amount of single reads in the original source. Example: ```kt File("text.txt") // File .openRead() // BatchSequence .batched(64) // BatchSequence ``` with this, if `.openRead()` returns a dumb sequence that always only gets one byte at once, you can speed up the reading process by a lot ## Sink You should make all your sinks take `BatchSequence` and then you can use the `.asBatch()` function to allow the sink to get multiple bytes at once Example: ```kt val data = myData // Sequence .asBatch() // BatchSequence File("text.txt") .write(data) ``` # Lazy Sequences When writing recursive functions like Fibonacci, it is often easier and faster to use lazy sequences. Example: ```kt val fib = lazySequence(0 to 1) { i, f -> f(i-1) + f(i-2) } println(fib[10]) ``` Note: If we call f for any number below 0, it will call f(0) instead. # Operation Chains TODO # Contents TODO # Monads TODO # Easy Sequence TODO # Easy Mapping Sequence TODO # Obj and MutObj TODO */ data class Monad( val impure: () -> O ) fun unit(v: O): Monad = Monad { v } fun unit(): Monad = Monad { Unit } fun Monad.bind(op: (I) -> O): Monad = Monad { op(this@bind.impure()) } fun Monad.print() = bind { print(it) } fun Monad.asPath() = bind { Path(it) } fun ByteBatchSequence.stringify(batch: Int = 64): Sequence { val iter = iterator() return generateSequence { if (iter.hasNext()) iter.nextBytes(batch).decodeToString() else null } } fun (() -> RawSource).readerSequence(): ByteBatchSequence = object : ByteBatchSequence { inner class Iter: ByteBatchIterator { val buffered = this@readerSequence().buffered() override fun nextBytes(limit: Int): ByteArray { val out = ByteArray(limit) var i = 0 while (!(buffered.exhausted() || i == limit - 1)) out[i ++] = buffered.readByte() return out.sliceArray(0..i) } override fun nextBytes(dest: ByteArray): Int = nextBytes(dest.size).also { it.copyInto(dest) }.size override fun next(limit: Int): List = nextBytes(limit).toList() override fun next(dest: MutableList, limit: Int) { for (x in nextBytes(limit)) { dest.add(x) } } override fun next(dest: Array): Int { var i = 0 for (x in nextBytes(dest.size)) { dest[i ++] = x } return i } override fun next(): Byte = buffered.readByte() override fun hasNext(): Boolean = !buffered.exhausted() } override fun iterator(): ByteBatchIterator = Iter() } fun Iterable>.rewrap(): Monad> = Monad { val iter = this@rewrap.iterator() generateSequence { if (iter.hasNext())iter.next().impure() else null } } fun Sequence>.rewrap(): Monad> = Monad { val iter = this@rewrap.iterator() sequence { if (iter.hasNext()) yield(iter.next().impure()) } } fun Sequence>.combine(): Monad = Monad { this@combine.forEach { it.impure() } } fun Iterable>.combineIter(): Monad = Monad { this@combineIter.forEach { it.impure() } } fun Monad>>.combine(): Monad = Monad { this@combine.impure().forEach { it.impure() } } fun Monad>>.combineIter(): Monad = Monad { this@combineIter.impure().forEach { it.impure() } } fun Monad>.mapIter(transform: (T) -> R): Monad> = bind { it.map { x -> transform(x) } } fun Monad>.map(transform: (T) -> R): Monad> = bind { it.map { x -> transform(x) } } fun Monad>>.flatten(): Monad> = bind { it.flatten() } fun Monad.stringify(batch: Int = 64): Monad> = bind { it.stringify(batch) } fun Monad.read() = bind { p -> { SystemFileSystem.source(p) }.readerSequence() } fun readIn() = Monad { generateSequence { readln() } } /* fun main() { val chain = chain() .map(Int::toString) .map(String::reversed) .finalize() println(chain.process(120).contents) }*/