From 6f80ab30a3d44007a86cb6a1e014f07344b607f3 Mon Sep 17 00:00:00 2001 From: SuperCraftAlex <63254202+alex-s168@users.noreply.github.com> Date: Sat, 9 Mar 2024 18:34:25 +0100 Subject: [PATCH] clean up --- build.gradle.kts | 2 +- doc/batched_sequences.md | 26 + doc/lazy_seq.md | 13 + gradlew | 35 +- gradlew.bat | 183 +++-- settings.gradle.kts | 1 + src/main/kotlin/blitz/Batched.kt | 128 +++ src/main/kotlin/blitz/BatchedUtils.kt | 10 + src/main/kotlin/blitz/Contents.kt | 52 ++ src/main/kotlin/blitz/Defer.kt | 46 ++ src/main/kotlin/blitz/DelegateProperties.kt | 21 + src/main/kotlin/blitz/Either.kt | 54 ++ .../alex_s168/kotlin_bits => blitz}/Fnp.kt | 2 +- src/main/kotlin/blitz/ListOps.kt | 13 + src/main/kotlin/blitz/Obj.kt | 11 + src/main/kotlin/blitz/OperationChain.kt | 85 ++ src/main/kotlin/blitz/SequenceBase.kt | 42 + src/main/kotlin/blitz/SequenceCreators.kt | 75 ++ src/main/kotlin/blitz/SequenceOps.kt | 25 + src/main/kotlin/blitz/Types.kt | 5 + src/main/kotlin/blitz/func/Combine.kt | 13 + src/main/kotlin/blitz/func/Map.kt | 7 + src/main/kotlin/blitz/func/Monad.kt | 14 + src/main/kotlin/blitz/func/Reduce.kt | 14 + src/main/kotlin/blitz/func/Rewrap.kt | 16 + src/main/kotlin/blitz/func/Utils.kt | 10 + src/main/kotlin/blitz/func/io/Console.kt | 9 + src/main/kotlin/blitz/func/io/File.kt | 13 + src/main/kotlin/blitz/io/Raw.kt | 51 ++ .../kotlin/me/alex_s168/kotlin_bits/Clazz.kt | 739 ------------------ .../kotlin/me/alex_s168/kotlin_bits/Term.kt | 35 - 31 files changed, 860 insertions(+), 890 deletions(-) create mode 100644 doc/batched_sequences.md create mode 100644 doc/lazy_seq.md create mode 100644 src/main/kotlin/blitz/Batched.kt create mode 100644 src/main/kotlin/blitz/BatchedUtils.kt create mode 100644 src/main/kotlin/blitz/Contents.kt create mode 100644 src/main/kotlin/blitz/Defer.kt create mode 100644 src/main/kotlin/blitz/DelegateProperties.kt create mode 100644 src/main/kotlin/blitz/Either.kt rename src/main/kotlin/{me/alex_s168/kotlin_bits => blitz}/Fnp.kt (94%) create mode 100644 src/main/kotlin/blitz/ListOps.kt create mode 100644 src/main/kotlin/blitz/Obj.kt create mode 100644 src/main/kotlin/blitz/OperationChain.kt create mode 100644 src/main/kotlin/blitz/SequenceBase.kt create mode 100644 src/main/kotlin/blitz/SequenceCreators.kt create mode 100644 src/main/kotlin/blitz/SequenceOps.kt create mode 100644 src/main/kotlin/blitz/Types.kt create mode 100644 src/main/kotlin/blitz/func/Combine.kt create mode 100644 src/main/kotlin/blitz/func/Map.kt create mode 100644 src/main/kotlin/blitz/func/Monad.kt create mode 100644 src/main/kotlin/blitz/func/Reduce.kt create mode 100644 src/main/kotlin/blitz/func/Rewrap.kt create mode 100644 src/main/kotlin/blitz/func/Utils.kt create mode 100644 src/main/kotlin/blitz/func/io/Console.kt create mode 100644 src/main/kotlin/blitz/func/io/File.kt create mode 100644 src/main/kotlin/blitz/io/Raw.kt delete mode 100644 src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt delete mode 100644 src/main/kotlin/me/alex_s168/kotlin_bits/Term.kt diff --git a/build.gradle.kts b/build.gradle.kts index 6ccdfbe..d9a07d1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,5 +25,5 @@ kotlin { } application { - mainClass.set("me.alex_s168.kotlin_bits.FnpKt") + mainClass.set("blitz.FnpKt") } diff --git a/doc/batched_sequences.md b/doc/batched_sequences.md new file mode 100644 index 0000000..7fbe109 --- /dev/null +++ b/doc/batched_sequences.md @@ -0,0 +1,26 @@ +# 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 +``` + +## 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) +``` \ No newline at end of file diff --git a/doc/lazy_seq.md b/doc/lazy_seq.md new file mode 100644 index 0000000..9439bb2 --- /dev/null +++ b/doc/lazy_seq.md @@ -0,0 +1,13 @@ +# 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. \ No newline at end of file diff --git a/gradlew b/gradlew index 1aa94a4..a69d9cb 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,11 +80,13 @@ do esac done -# This is normally unused -# shellcheck disable=SC2034 +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -131,29 +133,22 @@ location of your Java installation." fi else JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." - fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -198,15 +193,11 @@ if "$cygwin" || "$msys" ; then done fi - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..53a6b23 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,91 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts index 2754e44..0fc5bbe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,6 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" } + rootProject.name = "kotlin-bits" diff --git a/src/main/kotlin/blitz/Batched.kt b/src/main/kotlin/blitz/Batched.kt new file mode 100644 index 0000000..882b0d5 --- /dev/null +++ b/src/main/kotlin/blitz/Batched.kt @@ -0,0 +1,128 @@ +package blitz + +import kotlin.math.max +import kotlin.math.min + +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() + } \ No newline at end of file diff --git a/src/main/kotlin/blitz/BatchedUtils.kt b/src/main/kotlin/blitz/BatchedUtils.kt new file mode 100644 index 0000000..f6e2f61 --- /dev/null +++ b/src/main/kotlin/blitz/BatchedUtils.kt @@ -0,0 +1,10 @@ +package blitz + +fun ByteBatchSequence.stringify(batch: Int = 64): Sequence { + val iter = iterator() + return generateSequence { + if (iter.hasNext()) + iter.nextBytes(batch).decodeToString() + else null + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/Contents.kt b/src/main/kotlin/blitz/Contents.kt new file mode 100644 index 0000000..9b91d54 --- /dev/null +++ b/src/main/kotlin/blitz/Contents.kt @@ -0,0 +1,52 @@ +package blitz + +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()) \ No newline at end of file diff --git a/src/main/kotlin/blitz/Defer.kt b/src/main/kotlin/blitz/Defer.kt new file mode 100644 index 0000000..2b24f81 --- /dev/null +++ b/src/main/kotlin/blitz/Defer.kt @@ -0,0 +1,46 @@ +package blitz + +fun interface DeferScope { + fun defer(block: () -> Unit) +} + +interface ExecutionScope: DeferScope { + fun onError(block: () -> Unit) + + fun error() + + companion object { + fun create( + defer: (block: () -> Unit) -> Unit, + onError: (block: () -> Unit) -> Unit, + error: () -> Unit, + ) = object : ExecutionScope { + override fun defer(block: () -> Unit) = + defer(block) + + override fun onError(block: () -> Unit) = + onError(block) + + override fun error() = + error() + } + } +} + +fun resourceScoped(block: ExecutionScope.() -> R): R { + val defer = mutableListOf<() -> Unit>() + val onError = mutableListOf<() -> Unit>() + val scope = ExecutionScope.create(defer::add, onError::add) { + throw Exception("Manual error triggered") + } + val ex: Exception + try { + return block(scope) + } catch (e: Exception) { + ex = e + onError.forEach { it.invoke() } + } finally { + defer.forEach { it.invoke() } + } + throw ex +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/DelegateProperties.kt b/src/main/kotlin/blitz/DelegateProperties.kt new file mode 100644 index 0000000..be5baf9 --- /dev/null +++ b/src/main/kotlin/blitz/DelegateProperties.kt @@ -0,0 +1,21 @@ +package blitz + +fun caching(tiedGet: Provider, 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 +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/Either.kt b/src/main/kotlin/blitz/Either.kt new file mode 100644 index 0000000..e4b3dc1 --- /dev/null +++ b/src/main/kotlin/blitz/Either.kt @@ -0,0 +1,54 @@ +package blitz + +class Either private constructor( + private val a: Obj?, + private val b: Obj? +) { + fun getAOrNull(): A? = + a?.v + + fun getA(): A = + (a ?: throw Exception("Value of Either is not of type A!")).v + + fun getAOr(prov: Provider): A = + getAOrNull() ?: prov() + + fun getBOrNull(): B? = + b?.v + + fun getB(): B = + (b ?: throw Exception("Value of Either is not of type B!")).v + + fun getBOr(prov: Provider): B = + getBOrNull() ?: prov() + + val isA: Boolean = + a != null + + val isB: Boolean = + b != null + + fun then(af: (A) -> R, bf: (B) -> R): R = + if (isA) af(a!!.v) else bf(b!!.v) + + fun mapA(transform: (A) -> RA): Either = + Either(a.map(transform), b) + + fun mapB(transform: (B) -> RB): Either = + Either(a, b.map(transform)) + + override fun toString(): String = + if (isA) "Either($a)" + else "Either($b)" + + companion object { + fun ofA(a: A): Either = + Either(Obj(a), null) + + fun ofB(b: B): Either = + Either(null, Obj(b)) + } +} + +fun Either.commonize(): R where A: R, B: R = + getAOrNull() ?: getB() \ No newline at end of file diff --git a/src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt b/src/main/kotlin/blitz/Fnp.kt similarity index 94% rename from src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt rename to src/main/kotlin/blitz/Fnp.kt index 648834b..f722d30 100644 --- a/src/main/kotlin/me/alex_s168/kotlin_bits/Fnp.kt +++ b/src/main/kotlin/blitz/Fnp.kt @@ -1,4 +1,4 @@ -package me.alex_s168.kotlin_bits +package blitz fun main(args: Array) { // pureCat(args) diff --git a/src/main/kotlin/blitz/ListOps.kt b/src/main/kotlin/blitz/ListOps.kt new file mode 100644 index 0000000..598cbd0 --- /dev/null +++ b/src/main/kotlin/blitz/ListOps.kt @@ -0,0 +1,13 @@ +package blitz + +fun MutableList.removeFirst(count: Int) { + repeat(count) { + removeFirst() + } +} + +fun MutableList.removeLast(count: Int) { + repeat(count) { + removeLast() + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/Obj.kt b/src/main/kotlin/blitz/Obj.kt new file mode 100644 index 0000000..2b11455 --- /dev/null +++ b/src/main/kotlin/blitz/Obj.kt @@ -0,0 +1,11 @@ +package blitz + +data class Obj(val v: T) + +fun Obj?.mapNotNull(transform: (I) -> O): Obj? = + this?.v?.let { Obj(transform(it)) } + +fun Obj.map(transform: (I) -> O): Obj = + Obj(transform(v)) + +data class MutObj(var v: T) \ No newline at end of file diff --git a/src/main/kotlin/blitz/OperationChain.kt b/src/main/kotlin/blitz/OperationChain.kt new file mode 100644 index 0000000..584a300 --- /dev/null +++ b/src/main/kotlin/blitz/OperationChain.kt @@ -0,0 +1,85 @@ +package blitz + +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() + } +} + +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) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/SequenceBase.kt b/src/main/kotlin/blitz/SequenceBase.kt new file mode 100644 index 0000000..c8899df --- /dev/null +++ b/src/main/kotlin/blitz/SequenceBase.kt @@ -0,0 +1,42 @@ +package blitz + +interface IndexableSequence: Sequence { + operator fun get(index: Int): T +} + +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.asIndexable(): IndexableSequence = + 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 ++) + } + } \ No newline at end of file diff --git a/src/main/kotlin/blitz/SequenceCreators.kt b/src/main/kotlin/blitz/SequenceCreators.kt new file mode 100644 index 0000000..958fafa --- /dev/null +++ b/src/main/kotlin/blitz/SequenceCreators.kt @@ -0,0 +1,75 @@ +package blitz + +import kotlin.math.max + +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 selfInitializingSequence(block: Provider>): 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() + } \ No newline at end of file diff --git a/src/main/kotlin/blitz/SequenceOps.kt b/src/main/kotlin/blitz/SequenceOps.kt new file mode 100644 index 0000000..e747cb7 --- /dev/null +++ b/src/main/kotlin/blitz/SequenceOps.kt @@ -0,0 +1,25 @@ +package blitz + +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) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/Types.kt b/src/main/kotlin/blitz/Types.kt new file mode 100644 index 0000000..d3ae566 --- /dev/null +++ b/src/main/kotlin/blitz/Types.kt @@ -0,0 +1,5 @@ +package blitz + +typealias Provider = () -> T + +typealias Operator = (I) -> O \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/Combine.kt b/src/main/kotlin/blitz/func/Combine.kt new file mode 100644 index 0000000..d6181f5 --- /dev/null +++ b/src/main/kotlin/blitz/func/Combine.kt @@ -0,0 +1,13 @@ +package blitz.func + +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() } } \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/Map.kt b/src/main/kotlin/blitz/func/Map.kt new file mode 100644 index 0000000..6c28364 --- /dev/null +++ b/src/main/kotlin/blitz/func/Map.kt @@ -0,0 +1,7 @@ +package blitz.func + +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) } } \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/Monad.kt b/src/main/kotlin/blitz/func/Monad.kt new file mode 100644 index 0000000..4844a65 --- /dev/null +++ b/src/main/kotlin/blitz/func/Monad.kt @@ -0,0 +1,14 @@ +package blitz.func + +class Monad internal constructor( + val impure: () -> O +) + +fun unit(v: O): Monad = + Monad { v } + +fun unit(): Monad = + Monad { } + +fun Monad.bind(op: (I) -> O): Monad = + Monad { op(this@bind.impure()) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/Reduce.kt b/src/main/kotlin/blitz/func/Reduce.kt new file mode 100644 index 0000000..77c382e --- /dev/null +++ b/src/main/kotlin/blitz/func/Reduce.kt @@ -0,0 +1,14 @@ +package blitz.func + +fun Monad>.reduce(operation: (acc: S, T) -> S): Monad = + bind { it.reduce(operation) } + +fun Monad>.reduceIter(operation: (acc: S, T) -> S): Monad = + bind { it.reduce(operation) } + +fun Monad>.reduce(each: (T) -> Unit): Monad = + Monad { this@reduce.impure().forEach { each(it) } } + + +fun Monad>.reduceIter(each: (T) -> Unit): Monad = + Monad { this@reduceIter.impure().forEach { each(it) } } \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/Rewrap.kt b/src/main/kotlin/blitz/func/Rewrap.kt new file mode 100644 index 0000000..85a5bc7 --- /dev/null +++ b/src/main/kotlin/blitz/func/Rewrap.kt @@ -0,0 +1,16 @@ +package blitz.func + +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()) } + } diff --git a/src/main/kotlin/blitz/func/Utils.kt b/src/main/kotlin/blitz/func/Utils.kt new file mode 100644 index 0000000..529ba40 --- /dev/null +++ b/src/main/kotlin/blitz/func/Utils.kt @@ -0,0 +1,10 @@ +package blitz.func + +import blitz.ByteBatchSequence +import blitz.stringify + +fun Monad>>.flatten(): Monad> = + bind { it.flatten() } + +fun Monad.stringify(batch: Int = 64): Monad> = + bind { it.stringify(batch) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/io/Console.kt b/src/main/kotlin/blitz/func/io/Console.kt new file mode 100644 index 0000000..9958bf0 --- /dev/null +++ b/src/main/kotlin/blitz/func/io/Console.kt @@ -0,0 +1,9 @@ +package blitz.func.io + +import blitz.func.* + +fun Monad.print() = + bind { print(it) } + +fun readIn() = + Monad { generateSequence { readln() } } \ No newline at end of file diff --git a/src/main/kotlin/blitz/func/io/File.kt b/src/main/kotlin/blitz/func/io/File.kt new file mode 100644 index 0000000..d13b880 --- /dev/null +++ b/src/main/kotlin/blitz/func/io/File.kt @@ -0,0 +1,13 @@ +package blitz.func.io + +import blitz.func.Monad +import blitz.func.bind +import blitz.io.readerSequence +import kotlinx.io.files.Path +import kotlinx.io.files.SystemFileSystem + +fun Monad.asPath() = + bind { Path(it) } + +fun Monad.read() = + bind { p -> { SystemFileSystem.source(p) }.readerSequence() } \ No newline at end of file diff --git a/src/main/kotlin/blitz/io/Raw.kt b/src/main/kotlin/blitz/io/Raw.kt new file mode 100644 index 0000000..7ee063a --- /dev/null +++ b/src/main/kotlin/blitz/io/Raw.kt @@ -0,0 +1,51 @@ +package blitz.io + +import kotlinx.io.RawSource +import kotlinx.io.buffered +import blitz.ByteBatchIterator +import blitz.ByteBatchSequence +import blitz.Provider + +fun Provider.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() + } \ No newline at end of file diff --git a/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt b/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt deleted file mode 100644 index 608faad..0000000 --- a/src/main/kotlin/me/alex_s168/kotlin_bits/Clazz.kt +++ /dev/null @@ -1,739 +0,0 @@ -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) - -fun Obj?.map(transform: (I) -> O): Obj? = - this?.v?.let { Obj(transform(it)) } - -fun Obj.map(transform: (I) -> O): Obj = - Obj(transform(v)) - -data class MutObj(var v: T) - -typealias Provider = () -> T - -class Either private constructor( - private val a: Obj?, - private val b: Obj? -) { - fun getAOrNull(): A? = - a?.v - - fun getA(): A = - (a ?: throw Exception("Value of Either is not of type A!")).v - - fun getAOr(prov: Provider): A = - getAOrNull() ?: prov() - - fun getBOrNull(): B? = - b?.v - - fun getB(): B = - (b ?: throw Exception("Value of Either is not of type B!")).v - - fun getBOr(prov: Provider): B = - getBOrNull() ?: prov() - - val isA: Boolean = - a != null - - val isB: Boolean = - b != null - - fun then(af: (A) -> R, bf: (B) -> R): R = - if (isA) af(a!!.v) else bf(b!!.v) - - fun mapA(transform: (A) -> RA): Either = - Either(a.map(transform), b) - - fun mapB(transform: (B) -> RB): Either = - Either(a, b.map(transform)) - - override fun toString(): String = - if (isA) "Either($a)" - else "Either($b)" - - companion object { - fun ofA(a: A): Either = - Either(Obj(a), null) - - fun ofB(b: B): Either = - Either(null, Obj(b)) - } -} - -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 = - 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: Provider, 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: Provider>): 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 { } - -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 Provider.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>.reduce(operation: (acc: S, T) -> S): Monad = - bind { it.reduce(operation) } - -fun Monad>.reduceIter(operation: (acc: S, T) -> S): Monad = - bind { it.reduce(operation) } - -fun Monad>.reduce(each: (T) -> Unit): Monad = - Monad { this@reduce.impure().forEach { each(it) } } - - -fun Monad>.reduceIter(each: (T) -> Unit): Monad = - Monad { this@reduceIter.impure().forEach { each(it) } } - -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 interface DeferScope { - fun defer(block: () -> Unit) -} - -interface ExecutionScope: DeferScope { - fun onError(block: () -> Unit) - - fun error() - - companion object { - fun create( - defer: (block: () -> Unit) -> Unit, - onError: (block: () -> Unit) -> Unit, - error: () -> Unit, - ) = object : ExecutionScope { - override fun defer(block: () -> Unit) = - defer(block) - - override fun onError(block: () -> Unit) = - onError(block) - - override fun error() = - error() - } - } -} - -fun resourceScoped(block: ExecutionScope.() -> R): R { - val defer = mutableListOf<() -> Unit>() - val onError = mutableListOf<() -> Unit>() - val scope = ExecutionScope.create(defer::add, onError::add) { - throw Exception("Manual error triggered") - } - val ex: Exception - try { - return block(scope) - } catch (e: Exception) { - ex = e - onError.forEach { it.invoke() } - } finally { - defer.forEach { it.invoke() } - } - throw ex -} - -/* -fun main() { - val chain = chain() - .map(Int::toString) - .map(String::reversed) - .finalize() - println(chain.process(120).contents) -}*/ diff --git a/src/main/kotlin/me/alex_s168/kotlin_bits/Term.kt b/src/main/kotlin/me/alex_s168/kotlin_bits/Term.kt deleted file mode 100644 index 5f42af8..0000000 --- a/src/main/kotlin/me/alex_s168/kotlin_bits/Term.kt +++ /dev/null @@ -1,35 +0,0 @@ -package me.alex_s168.kotlin_bits - -object Ansi { - const val ESC = (0x1B).toChar() - - object Cursor { - fun home() = - print("$ESC[H") - - fun goto(line: Int, col: Int) = - print("$ESC[${line};${col}H") - - fun up(lines: Int) = - print("$ESC[${lines}A") - - fun down(lines: Int) = - print("$ESC[${lines}B") - - fun right(cols: Int) = - print("$ESC[${cols}C") - - fun left(cols: Int) = - print("$ESC[${cols}D") - } - - fun printAndBack(text: String) { - print(text) - Cursor.left(text.length) - } -} - -fun main() { - Ansi.printAndBack("001") - print("002") -} \ No newline at end of file