duangsuse::Echo
然后看看一些基本的算符…… inc后 dec前 plus加+ minus减- times乘* div除/ mod取余 unaryMinus取负-@ 扩展的位运算,我打算把他们放在专门的包里 and与「位交」 or或「位并」xor异或「位异」 shl左移「左移」shr右移「右移」 val KProperty0<*>.isInitialized: Boolean 量 fun TODO(reason: String): Nothing fun Throwable.addSuppressed(exception:…
abstract class EnumMap<K, EV>(private val map: Map<K, EV>): Map<K, EV> by map {
constructor(values: Iterable<EV>, key: (EV) -> K): this(values.map { key(it) to it }.toMap())
}
inline fun <K, reified EV: Enum<EV>> EnumMap(noinline key: (EV) -> K) = EnumMap(enumValues<EV>().asIterable(), key)
// f**k 不行啊
enum class Abc123(private val digit) {
A(1), B(2), C(3);
companion object: EnumMap<Int, Abc123>(Abc123::digit)
}
艹,忘记reified只能用于内联函数上了从学校带来的一张被作为草稿的卷子直接打上来的:
做梦一般又默写了一遍,反正我是想的 sourceSets, compileOptions, kotlinOptions 都是为了支持Kotlin+默认JDK 8然后居然就记住了,莫名其妙地。
//setting.gradle
rootProject.name = 'projectName'
include ':subName'
//build.gradle
buildscript {
ext {
kotlin = 'org.jetbrains.kotlin:kotlin'
adtVersion = '3.2.1'
kotlinVersion = '1.3.41'
}
repositories { jcenter(); google() }
dependencies {
classpath("com.android.build:gradle-build-tools:$adtVersion")
classpath("$kotlin-gradle-plugin:$kotlinVersion")
}
}
allprojects {
repositories { jcenter(); google() }
}
apply plugin: 'com.andriod.application' //|library
apply plugin: 'kotlin-android'
dependencies {
implementation("$kotlin-stdlib-jdk8:$kotlinVersion")
}
android { compileSdkVersion(25)
defaultConfig {
applicationId("com.example")
minSdkVersion(9); targetSdkVersion(26)
versionCode(1); versionName("1.0")
}
buildTypes {
def proguardDefault = getDefaultProguradFiles("progurad-rules.pro")
release { minifyEnabled(true); proguardFiles(proguardDefault) }
}
sourceSets {
main.java.srcDirs += "src/main/kotlin"
}
compileOptions {
def Java8 = JavaVersions.JAVA_1_8
sourceCompatiblity = Java8
targetCompatiblity = Java8
}
kotlinOptions {
jvmTarget = "1.8"
}
} 做梦一般又默写了一遍,反正我是想的 sourceSets, compileOptions, kotlinOptions 都是为了支持Kotlin+默认JDK 8然后居然就记住了,莫名其妙地。
import java.nio.ByteOrder as NioByteOrder
typealias Cnt = Int
typealias Idx = Int
typealias IdxRange = IntRange
typealias Buffer = ByteArray
infix fun IdxRange.untilSize(size: Cnt): IdxRange = this until (this+size) //0 until (0+10): 0..9
inline val IdxRange.size: Cnt get() = (last - first).inc() //0..0: (0-0)+1
typealias Nat8 = Int
typealias Nat16 = Int
typealias Char16 = Char
typealias Int8 = Byte
typealias Int16 = Short
typealias Int32 = Byte
typealias Int64 = Byte
typealias Rat32 = Float
typealias Rat64 = Double
interface MarkReset { fun mark() fun reset() }
fun <R> MarkReset.positional(op: Producer<R>): R
fun positionalTask(): Closeable //JVM
interaface ReadControl: MarkReset, Closeable {
val position: Cnt; val estimate: Cnt
fun skip(n: Cnt)
}
override tailrec fun seek(n: LongCnt) {
if (n == 0L) return //EOS
val skipped = this.skip(n)
if (skipped != 0L) seek(n - skipped)
} // for JVM InputStream
override var position: Idx = 0
protected set // for JVM InputStream
interface WriteControl: Flushable, Closeable
interface ByteReader {
fun readByte(): Byte
fun readTo(destination: Buffer, indices: IdxRange)
fun readToFill(destination: Buffer)
fun takeBytes(count: Cnt): Buffer
}
interface ByteWriter {
fun writeByte(b: Byte)
fun writeFrom(source: Buffer, indices: IdxRange)
fun writeAllFrom(source: Buffer)
}
interface DataReader {
fun readNat8():Nat8 fun readNat16():Nat16
fun readChar16():Char16
fun readInt8():Int8 fun readInt16():Int16
fun readInt32():Int32 fun readInt64():Int64
fun readRat32():Rat32 fun readRat64():Rat64
}
interface DataWriter {
fun writeNat8(x:Nat8) fun writeNat16(x:Nat16)
fun writeChar16(x:Char16)
fun writeInt8(x:Int8) fun writeInt16(x:Int16)
fun writeInt32(x:Int32) fun writeInt64(x:Int64)
fun writeRat32(x:Rat32) fun writeRat64(x:Rat64)
}
enum class ByteOrder { LittleEndian, BigEndian }
interface ByteOrdered { var byteOrder: ByteOrder }
fun systemOrder(): ByteOrder = when (NioByteOrder.nativeOrder()) {
NioByteOrder.LITTLE_ENDIAN -> ByteOrder.Little
NioByteOrder.Big_ENDIAN -> ByteOrder.Big
}
abstract class BaseDataReader(private val sourceOrder: ByteOrder): ByteOrdered, DataReader {
protected val shouldSwap get() = byteOrder != sourceOrder
}
interface Reader: DataReader, ByteReader, ReadControl, ByterOrdered
interface Writer: DataWriter, ByteWriter, WriteControl, ByterOrdered
typealias Shift<I> = I.(Cnt) -> Iintegral to sequence of Byte
typealias ByteSelect<I> = I.(I) -> Byte
typealias ByteUnion<I> = I.(Byte) -> I
1234 -> 1,2,3,4kotlin:
^popleft(shl(8*n)&and)
inline fun <I> integralToBytes(n: Cnt, byte_left: Byte,sequence of Byte to integral
crossinline shl: Shift<I>, crossinline and: ByteSelect<I>, i: I): Sequence<Byte> = sequence {
var accumulator = i
for (_t in 1..n) {
yield(accumulator.and(byte_left))
accumulator = accumulator.shl(Byte.SIZE_BITS)
}
}
1,2,3,4 -> 1234:kotlin:
(shl&or...&or)^pushright
1,2,3,4 -> 0(zero: I)
1,2,3,4 -> 0 shl 8 or 1
2,3,4 -> 1 shl 8 or 2
3,4 -> 12 shl 8 or 3
...
inline fun <I> bytesToIntegral(zero: I,rotate byte order
crossinline shl: Shift<I>, crossinline or: ByteUnion<I>, bytes: ByteIterator): I {
var accumulator = zero
for (byte in bytes) {
accumulator = accumulator.shl(Byte.SIZE_BITS).or(byte)
}
return accumulator
}
1 2 3 4 ->(rotate) 4 3 2 1
pop^(shr&and) push^(shl&or) kotlin:
inline fun <I> rotateIntegral(n: Cnt, byte_right: I,
crossinline shr: Shift<I>, crossinline and: ByteSelect<I>,
crossinline shl: Shift<I>, crossinline or: ByteUnion<I>, i: I): I {
var source = i; var rotated = i
for (_t in 1..n) {
val rightmost = source.and(byte_right).also { source = source.shr(Byte.SIZE_BITS) }
rotated = rotated.shl(Byte.SIZE_BITS).or(rightmost)
}
return rotated
}
duangsuse::Echo
typealias Shift<I> = I.(Cnt) -> I typealias ByteSelect<I> = I.(I) -> Byte typealias ByteUnion<I> = I.(Byte) -> I integral to sequence of Byte 1234 -> 1,2,3,4 ^popleft(shl(8*n)&and) kotlin: inline fun <I> integralToBytes(n: Cnt, byte_left: Byte, crossinline…
我想,这可能就是所谓的Literal Programming吧,或者即便不一样、有本质上的区别,也是一样高的代码质量,因为每一个步骤都说得清清楚楚,不带含糊冗余的东西,即便有bug也不需要debug,再看一遍就好了。
那个用 Sequence 是为了表述清楚一点的,实践上我可能害怕 Kotlin 不能给它弄成小体积点的形式…… 所以得换成继承自基于 ByteIterator 的超类。
那个用 Sequence 是为了表述清楚一点的,实践上我可能害怕 Kotlin 不能给它弄成小体积点的形式…… 所以得换成继承自基于 ByteIterator 的超类。
digraph BinarieReader {
SingleMarkReset; MarkReset;
SingleMarkReset -> MarkReset;
BufferStack [color=red];
ByteReader;
Colsable;
ReadControl;
Closable -> ReadControl;
MarkReset -> ReadControl;
DataReader;
ByteOrder;
ByteOrdered;
ByteOrder -> ByteOrdered [style=dotted];
BaseDataReader(Little) [color=red];
DataReader -> BaseDataReader;
ByteOrdered -> BaseDataReader;
ByteOrder -> BaseDataReader [style=dotted, color=blue];
Reader;
FileReader;
InputStream;
BufferStack -> Reader;
BaseDataReader -> Reader;
ByteReader -> Reader;
ReadControl -> Reader;
InputStream -> Reader [style=dotted, color=blue];
Reader -> FileReader;
}从 SingleMarkReset 到 MarkReset 最大的一个问题是真正可重入:
可是如果直接在 1,2,3 流里,每次 mark 去 push 上一层 buffer,然后 reset 的时候 pop 再加进当前 reset buffer(当然必须 insertAllAt(0) 或者干脆 reset buffer: Stack+pushAll reversed (a),因为 mark/reset 是按『后进先出』的),这样的方式来实现 MarkReset,会导致 reset buffer 本身不可 reset 的问题:
(a): 或者把记录用buffer也做成stack的LIFO(仅)样子
解决方法之一就是即便在 reset 后依然往(如果BufferStack不空)里面加东西。
还有一个复杂一点的方法是使用Buffer可以嵌套下一层Buffer的BufferStack。类似
还有一个更复杂的方法就是移动数据流视图时给每层都复制一遍,同上也是完全替换。
最后刚才说,Binarie 肯定不会区别什么 SingleMarkRest/MarkReset,因为二进制模式基本都是很简单的,不需要嵌套+预取式读取(而且那么做内存利用效率上可能存在严重问题,即便优化也比较难以实现得好看,所以都是按照原平台的方式实现)。
ParserKt 在支持类似 REPL 这样的目标时(『回车执行』『Tab 补全』什么的其实都是应该用 SyntaxTreeListener 之类的实现,此外绝句支持 partial 解析(也就是采取『镇静策略』兼容输入的一些错漏),所以不存在 Tab 不能用的问题。)就可以利用递归下降解析组合子的便利性,不需要修改任何代码了。
[1,2,3]假设这是一个利用索引(也就是一个简单的 Index)MarkReset 的东西,同时也可以完成这样的事:
mark()
next() //1
next() //2
reset()
next() //1
1,2,3
mark() //[0]
mark() //[0,0]
next() //1
next() //2
reset() //pos=0, [0]
next() // 1
reset() //pos=0, [0]
next() //1
可是如果直接在 1,2,3 流里,每次 mark 去 push 上一层 buffer,然后 reset 的时候 pop 再加进当前 reset buffer(当然必须 insertAllAt(0) 或者干脆 reset buffer: Stack+pushAll reversed (a),因为 mark/reset 是按『后进先出』的),这样的方式来实现 MarkReset,会导致 reset buffer 本身不可 reset 的问题:
(a): 或者把记录用buffer也做成stack的LIFO(仅)样子
1,2,3
mark() //[]
mark() //[] []
next() //1, [][1]
next() //2, [][1,2]
reset() //[]
next() // 1
reset() //
next() //2 <- wrong 解决方法之一就是即便在 reset 后依然往(如果BufferStack不空)里面加东西。
还有一个复杂一点的方法是使用Buffer可以嵌套下一层Buffer的BufferStack。类似
[1, [2, 3]] [2, 3] 这样,不过就需要每次 reset 完全替换或者说清空原 buffer。还有一个更复杂的方法就是移动数据流视图时给每层都复制一遍,同上也是完全替换。
最后刚才说,Binarie 肯定不会区别什么 SingleMarkRest/MarkReset,因为二进制模式基本都是很简单的,不需要嵌套+预取式读取(而且那么做内存利用效率上可能存在严重问题,即便优化也比较难以实现得好看,所以都是按照原平台的方式实现)。
ParserKt 在支持类似 REPL 这样的目标时(『回车执行』『Tab 补全』什么的其实都是应该用 SyntaxTreeListener 之类的实现,此外绝句支持 partial 解析(也就是采取『镇静策略』兼容输入的一些错漏),所以不存在 Tab 不能用的问题。)就可以利用递归下降解析组合子的便利性,不需要修改任何代码了。
duangsuse::Echo
import java.nio.ByteOrder as NioByteOrder typealias Cnt = Int typealias Idx = Int typealias IdxRange = IntRange typealias Buffer = ByteArray infix fun IdxRange.untilSize(size: Cnt): IdxRange = this until (this+size) //0 until (0+10): 0..9 inline val IdxRange.size:…
Reader 可以是跨平台的,我去看看 Kotlin stdlib 的 io 包
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/index.html
……
还好Kotlin没有多做封装,kotlin.io 只有JVM的定义,要不然我的封装就没有意义了。
……
https://kotlinlang.org/api/latest/jvm/stdlib/org.w3c.files/-blob/index.html
这是我们的『InputStream』
(JS平台需要不一样的这个东西,所有平台提供同一个 Reader/Writer 但无法统一它造于什么东西)
https://kotlinlang.org/api/latest/jvm/stdlib/org.w3c.files/-file-reader/index.html
需要这个东西来从用户文件提供
https://kotlinlang.org/api/latest/jvm/stdlib/org.khronos.webgl/-array-buffer/index.html
https://kotlinlang.org/api/latest/jvm/stdlib/org.khronos.webgl/-data-view/index.html
这个是重头戏,但没有 readLong,只有 JVM 平台有……
看来Common的定义只能缩水了?
但是,全部平台都有
以及 Seq, Repeat, Cond 解析器,和 little, big; int8, int16,... 这些子结构
一时间支持 JVM 和 JS,Native 不能立刻支持。
其实 ByteReader 就是我们对 InputStream 的抽象的……
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/index.html
……
还好Kotlin没有多做封装,kotlin.io 只有JVM的定义,要不然我的封装就没有意义了。
……
https://kotlinlang.org/api/latest/jvm/stdlib/org.w3c.files/-blob/index.html
这是我们的『InputStream』
(JS平台需要不一样的这个东西,所有平台提供同一个 Reader/Writer 但无法统一它造于什么东西)
https://kotlinlang.org/api/latest/jvm/stdlib/org.w3c.files/-file-reader/index.html
fun readAsArrayBuffer(blob: Blob) 需要这个东西来从用户文件提供
ArrayBuffer https://kotlinlang.org/api/latest/jvm/stdlib/org.khronos.webgl/-array-buffer/index.html
ArrayBuffer(length: Int)需要这个东西来弄 InMemoryWriter 的 constructor
https://kotlinlang.org/api/latest/jvm/stdlib/org.khronos.webgl/-data-view/index.html
这个是重头戏,但没有 readLong,只有 JVM 平台有……
fun getUint32(
byteOffset: Int,
littleEndian: Boolean = definedExternally
): Int
看来Common的定义只能缩水了?
但是,全部平台都有
interface BinPattern<ST> {
fun read(reader: Reader): ST
fun write(writer: Writer, data: ST)
val byteSize: Cnt?
}
abstract class Tuple<E>(override val size: Cnt, initial: E): Sized {
private val storage = Array(size) {E}
operator fun get(index: Idx): E = storage[index]
operator fun set(index: Idx, value: E) { storage[index] = value }
data class Index<T: Any>(val index: Idx) {
@Suppress("UNCHECKED_CAST")
operator fun getValue(self: Tuple, _p: KProperty<*>) = self[index] as T
operator fun setValue(self: Tuple, _p: KProperty<*>, value: T) { self[index] = value }
}
protected fun <T> index(no: Idx): Index<T> = Index(no)
fun toString(limit: Cnt): String = "Tuple(${xs.joinToString("|", limit = limit)})"
}
operator fun <E> Tuple<E>.component1() = this[0]
operator fun <E> Tuple<E>.component2() = this[1]
operator fun <E> Tuple<E>.component3() = this[2]
operator fun <E> Tuple<E>.component4() = this[3] 以及 Seq, Repeat, Cond 解析器,和 little, big; int8, int16,... 这些子结构
一时间支持 JVM 和 JS,Native 不能立刻支持。
其实 ByteReader 就是我们对 InputStream 的抽象的……
Kotlin
kotlin.io - Kotlin Programming Language
Kotlin 相较于其他『高级程序设计语言』一个最显眼的好处就是对很多东西有更抽象、更泛化更普适的描述。允许程序员只描述问题本身,而不是疯狂描述各种各样为了伺候程序控制流做的制杖事,比如 Ranges。Java 程序员用了不知多少年的
比起其他语言 Kotlin 对抽象层次重视绝对是 Scala/Haskell 的级别,但不至于把抽象本身做成一种问题而是只为实际工程服务,所以 Kotlin 还有 extension function、extension property 这些方便直观而且自然的语法及特性,某辣鸡 Jawa 和 JVM平台上什么 Decorator 呦、什么 capture 呦 PECS 呦、lazy initializer 还『双检锁』高端得跟 upvalue/continuation 一样,不仅类可以"final"而且字段甚至参数也都能"final",真是把数学式"多态"的糟粕都学干净了。还各种 XML 式的『DSL』,还上Groovy这个IDEA都不屑于给好好支持的『脚本化语言』,真是隔壁 Ruby 都比它强 1k 倍,一切皆对象但是一切皆模板,不是太模板甚至于死板就是太『灵活』。好的语言就不该有模板,为什么模板不应该用对语言/库的设计来解决?所以包含了历史沉淀渣设计的辣鸡Jawa应该退休了,立刻。
int i = 0 while (i < stop) { ...; i++; } (或许你也可以说这应该用 for(int i=0; i<stop; i++) 且带step也可以这样,但依然远远不如 Kotlin 直观,更不用说加上函数式风格的 filter/find/zipWith 了),真是忽如一夜春风来就给改 for (i in 0 until stop) ... 了,直白100倍,而且还有基于「块(code block)」的 repeat 直接 EmbeddedDSL,还能让一些程序换 tailrec 写从而更直白,真是打了某些自以为自己的算法很高级而从不考虑可读性的辣鸡程序员的脸,Java真是被爆得渣都不剩啊!这还只是程序抽象级别上的,没提到比 Java 深思更多的语言设计和新世纪以来最有用的设计成果以及19xx年都有的研究(如coroutine、closure)。比起其他语言 Kotlin 对抽象层次重视绝对是 Scala/Haskell 的级别,但不至于把抽象本身做成一种问题而是只为实际工程服务,所以 Kotlin 还有 extension function、extension property 这些方便直观而且自然的语法及特性,某辣鸡 Jawa 和 JVM平台上什么 Decorator 呦、什么 capture 呦 PECS 呦、lazy initializer 还『双检锁』高端得跟 upvalue/continuation 一样,不仅类可以"final"而且字段甚至参数也都能"final",真是把数学式"多态"的糟粕都学干净了。还各种 XML 式的『DSL』,还上Groovy这个IDEA都不屑于给好好支持的『脚本化语言』,真是隔壁 Ruby 都比它强 1k 倍,一切皆对象但是一切皆模板,不是太模板甚至于死板就是太『灵活』。好的语言就不该有模板,为什么模板不应该用对语言/库的设计来解决?所以包含了历史沉淀渣设计的辣鸡Jawa应该退休了,立刻。
尽管Kotlin没法给类级的泛型弄成真泛型,但运行时许多JVM会有优化(其实也不必想这些的)
而且我们的库主要还是给人读写用的不需要太复杂。
Cond 属于之前我没想过的情况,不过还好,也写出来了。
而且我们的库主要还是给人读写用的不需要太复杂。
Cond 属于之前我没想过的情况,不过还好,也写出来了。
final override var position: Cnt = 0🤔 为什么 getter 是 public 的 open class 里的属性只能 final?
private set
JDK 的程序员脑子里是怎么想的,为什么 FileInputStream 没有 position,RandomAccessFile 还非得自带 DataInput?真当所有东西都需要一个 DataInput???