c
This commit is contained in:
@@ -12,7 +12,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("me.alex_s168:blitz:0.21")
|
||||
implementation("me.alex_s168:blitz:0.22h2")
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -5,7 +5,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "me.alex_s168"
|
||||
version = "0.20"
|
||||
version = "0.22h2"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -15,9 +15,6 @@ dependencies {
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.3.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-io-bytestring:0.3.1")
|
||||
|
||||
// https://mvnrepository.com/artifact/org.json/json
|
||||
implementation("org.json:json:20240303")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
|
@@ -114,3 +114,11 @@ fun <A: Any, BA: Any, BB: Any> Either<A, Either<BA, BB>>.getBAOrNull(): BA? =
|
||||
|
||||
fun <A: Any, BA: Any, BB: Any> Either<A, Either<BA, BB>>.getBBOrNull(): BB? =
|
||||
b?.b
|
||||
|
||||
inline fun <A: Any, B: Any, RA: Any, RB: Any> Either<A, B>.map(fa: (A) -> RA, fb: (B) -> RB): Either<RA, RB> =
|
||||
if (a != null) Either.ofA(fa(a!!))
|
||||
else Either.ofB(fb(b!!))
|
||||
|
||||
inline fun <A: Any, B: Any, R> Either<A, B>.flatMap(fa: (A) -> R, fb: (B) -> R): R =
|
||||
if (a != null) fa(a!!)
|
||||
else fb(b!!)
|
26
src/main/kotlin/blitz/Switch.kt
Normal file
26
src/main/kotlin/blitz/Switch.kt
Normal file
@@ -0,0 +1,26 @@
|
||||
package blitz
|
||||
|
||||
data class SwitchCase<C, T: Any, R>(
|
||||
val cond: (C) -> Pair<Boolean, T?>,
|
||||
val then: (T) -> R,
|
||||
)
|
||||
|
||||
inline infix fun <C, T: Any, R> ((C)->Pair<Boolean, T?>).case(noinline then: (T) -> R) =
|
||||
SwitchCase(this, then)
|
||||
|
||||
infix fun <R> Regex.startsWithCase(then: (MatchResult) -> R): SwitchCase<String, MatchResult, R> =
|
||||
{ it: String ->
|
||||
this.matchAt(it, 0)?.let {
|
||||
true to it
|
||||
} ?: (false to null)
|
||||
} case then
|
||||
|
||||
inline fun <T, R> T.switch(vararg cases: SwitchCase<T, *, R>, default: (T) -> R): R {
|
||||
cases.forEach { (cond, then) ->
|
||||
val (b, v) = cond(this)
|
||||
if (b) {
|
||||
return (then as (Any) -> R)(v!!)
|
||||
}
|
||||
}
|
||||
return default(this)
|
||||
}
|
7
src/main/kotlin/blitz/Utils.kt
Normal file
7
src/main/kotlin/blitz/Utils.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package blitz
|
||||
|
||||
fun unreachable(): Nothing =
|
||||
error("this should be unreachable")
|
||||
|
||||
inline fun <reified R> Any?.cast(): R? =
|
||||
this?.let { if (it is R) it else null }
|
@@ -18,6 +18,9 @@ class ByteVec(private val initCap: Int = 0): Vec<Byte>, ByteBatchSequence {
|
||||
}
|
||||
}
|
||||
|
||||
fun unsafeBackingArr(): ByteArray =
|
||||
array
|
||||
|
||||
fun copyAsArray(): ByteArray =
|
||||
array.copyOfRange(0, size)
|
||||
|
||||
|
156
src/main/kotlin/blitz/collections/CharVec.kt
Normal file
156
src/main/kotlin/blitz/collections/CharVec.kt
Normal file
@@ -0,0 +1,156 @@
|
||||
package blitz.collections
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class CharVec(private val initCap: Int = 0): Vec<Char>, BatchSequence<Char> {
|
||||
override var size = 0
|
||||
private var cap = initCap
|
||||
private var array = CharArray(initCap)
|
||||
|
||||
override fun clear() {
|
||||
size = 0
|
||||
if (array.size <= initCap) {
|
||||
cap = array.size
|
||||
} else {
|
||||
cap = initCap
|
||||
array = CharArray(initCap)
|
||||
}
|
||||
}
|
||||
|
||||
fun copyAsArray(): CharArray =
|
||||
array.copyOfRange(0, size)
|
||||
|
||||
fun copyIntoArray(arr: CharArray, destOff: Int = 0, startOff: Int = 0) =
|
||||
array.copyInto(arr, destOff, startOff, size)
|
||||
|
||||
override fun copy(): CharVec =
|
||||
CharVec(size).also {
|
||||
copyIntoArray(it.array)
|
||||
}
|
||||
|
||||
override fun reserve(amount: Int) {
|
||||
if (amount > 0 && cap - size >= amount)
|
||||
return
|
||||
array = array.copyOf(size + amount)
|
||||
cap = size + amount
|
||||
}
|
||||
|
||||
override fun reserve(need: Int, wantIfRealloc: Int) {
|
||||
if (need > 0 && cap - size >= need)
|
||||
return
|
||||
cap = size + wantIfRealloc
|
||||
array = array.copyOf(cap)
|
||||
}
|
||||
|
||||
override fun popBack(): Char =
|
||||
array[size - 1].also {
|
||||
reserve(-1)
|
||||
size --
|
||||
}
|
||||
|
||||
fun tryPopPack(dest: CharArray, destOff: Int = 0): Int {
|
||||
val can = kotlin.math.min(size, dest.size - destOff)
|
||||
copyIntoArray(dest, destOff, size - can)
|
||||
reserve(-can)
|
||||
size -= can
|
||||
return can
|
||||
}
|
||||
|
||||
fun popBack(dest: CharArray, destOff: Int = 0) {
|
||||
val destCopySize = dest.size - destOff
|
||||
require(size >= destCopySize)
|
||||
copyIntoArray(dest, destOff, size - destCopySize)
|
||||
reserve(-destCopySize)
|
||||
size -= destCopySize
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBack(batching: CharArray, fn: (CharArray, Int) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
fn(batching, rem)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun consumePopBack(batching: CharArray, fn: (Char) -> Unit) =
|
||||
consumePopBack(batching) { batch, count ->
|
||||
repeat(count) {
|
||||
fn(batch[it])
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBackSlicedBatches(batching: CharArray, fn: (CharArray) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
if (rem == batching.size)
|
||||
fn(batching)
|
||||
else
|
||||
fn(batching.copyOf(rem))
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(index: Int): Char =
|
||||
array[index]
|
||||
|
||||
override fun flip() {
|
||||
array = array.reversedArray()
|
||||
}
|
||||
|
||||
fun pushBack(arr: CharArray) {
|
||||
reserve(arr.size)
|
||||
arr.copyInto(array, size)
|
||||
size += arr.size
|
||||
}
|
||||
|
||||
override fun pushBack(elem: Char) {
|
||||
reserve(1, 8)
|
||||
array[size] = elem
|
||||
size ++
|
||||
}
|
||||
|
||||
override fun iterator(): BatchIterator<Char> =
|
||||
array.asSequence().asBatch().iterator()
|
||||
|
||||
override fun toString(): String =
|
||||
String(array, 0, size)
|
||||
|
||||
fun subViewToString(from: Int, num: Int = size - from): String =
|
||||
String(array, from, num)
|
||||
|
||||
override fun set(index: Int, value: Char) {
|
||||
array[index] = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(data: String) =
|
||||
CharVec(data.length).also {
|
||||
data.toCharArray().copyInto(it.array)
|
||||
it.size = data.length
|
||||
}
|
||||
|
||||
fun from(bytes: CharArray) =
|
||||
CharVec(bytes.size).also {
|
||||
bytes.copyInto(it.array)
|
||||
it.size += bytes.size
|
||||
}
|
||||
|
||||
fun from(bytes: Sequence<Char>) =
|
||||
CharVec().also { bv ->
|
||||
bytes.forEach(bv::pushBack)
|
||||
}
|
||||
}
|
||||
}
|
23
src/main/kotlin/blitz/collections/Compare.kt
Normal file
23
src/main/kotlin/blitz/collections/Compare.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
package blitz.collections
|
||||
|
||||
fun <T> List<T>.containsAt(at: Int, other: List<T>): Boolean {
|
||||
if (at + other.size > size)
|
||||
return false
|
||||
for (i in at..<at+other.size)
|
||||
if (this[i] != other[i-at])
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun <T> List<T>.startsWith(other: List<T>): Boolean =
|
||||
containsAt(0, other)
|
||||
|
||||
fun String.startsWith(re: Regex): Boolean =
|
||||
re.matchesAt(this, 0)
|
||||
|
||||
fun String.substringAfter(m: MatchResult): String =
|
||||
this.drop(m.value.length)
|
||||
|
||||
fun String.substringAfter(re: Regex): String? =
|
||||
re.matchAt(this, 0)
|
||||
?.let(this::substringAfter)
|
147
src/main/kotlin/blitz/collections/IntVec.kt
Normal file
147
src/main/kotlin/blitz/collections/IntVec.kt
Normal file
@@ -0,0 +1,147 @@
|
||||
package blitz.collections
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class IntVec(private val initCap: Int = 0): Vec<Int>, BatchSequence<Int> {
|
||||
override var size = 0
|
||||
private var cap = initCap
|
||||
private var array = IntArray(initCap)
|
||||
|
||||
override fun clear() {
|
||||
size = 0
|
||||
if (array.size <= initCap) {
|
||||
cap = array.size
|
||||
} else {
|
||||
cap = initCap
|
||||
array = IntArray(initCap)
|
||||
}
|
||||
}
|
||||
|
||||
fun copyAsArray(): IntArray =
|
||||
array.copyOfRange(0, size)
|
||||
|
||||
fun copyIntoArray(arr: IntArray, destOff: Int = 0, startOff: Int = 0) =
|
||||
array.copyInto(arr, destOff, startOff, size)
|
||||
|
||||
override fun copy(): IntVec =
|
||||
IntVec(size).also {
|
||||
copyIntoArray(it.array)
|
||||
}
|
||||
|
||||
override fun reserve(amount: Int) {
|
||||
if (amount > 0 && cap - size >= amount)
|
||||
return
|
||||
array = array.copyOf(size + amount)
|
||||
cap = size + amount
|
||||
}
|
||||
|
||||
override fun reserve(need: Int, wantIfRealloc: Int) {
|
||||
if (need > 0 && cap - size >= need)
|
||||
return
|
||||
cap = size + wantIfRealloc
|
||||
array = array.copyOf(cap)
|
||||
}
|
||||
|
||||
override fun popBack(): Int =
|
||||
array[size - 1].also {
|
||||
reserve(-1)
|
||||
size --
|
||||
}
|
||||
|
||||
fun tryPopPack(dest: IntArray, destOff: Int = 0): Int {
|
||||
val can = kotlin.math.min(size, dest.size - destOff)
|
||||
copyIntoArray(dest, destOff, size - can)
|
||||
reserve(-can)
|
||||
size -= can
|
||||
return can
|
||||
}
|
||||
|
||||
fun popBack(dest: IntArray, destOff: Int = 0) {
|
||||
val destCopySize = dest.size - destOff
|
||||
require(size >= destCopySize)
|
||||
copyIntoArray(dest, destOff, size - destCopySize)
|
||||
reserve(-destCopySize)
|
||||
size -= destCopySize
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBack(batching: IntArray, fn: (IntArray, Int) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
fn(batching, rem)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun consumePopBack(batching: IntArray, fn: (Int) -> Unit) =
|
||||
consumePopBack(batching) { batch, count ->
|
||||
repeat(count) {
|
||||
fn(batch[it])
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBackSlicedBatches(batching: IntArray, fn: (IntArray) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
if (rem == batching.size)
|
||||
fn(batching)
|
||||
else
|
||||
fn(batching.copyOf(rem))
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(index: Int): Int =
|
||||
array[index]
|
||||
|
||||
override fun flip() {
|
||||
array = array.reversedArray()
|
||||
}
|
||||
|
||||
fun pushBack(arr: IntArray) {
|
||||
reserve(arr.size)
|
||||
arr.copyInto(array, size)
|
||||
size += arr.size
|
||||
}
|
||||
|
||||
override fun pushBack(elem: Int) {
|
||||
reserve(1, 8)
|
||||
array[size] = elem
|
||||
size ++
|
||||
}
|
||||
|
||||
override fun iterator(): BatchIterator<Int> =
|
||||
array.asSequence().asBatch().iterator()
|
||||
|
||||
override fun toString(): String =
|
||||
contents.toString()
|
||||
|
||||
override fun set(index: Int, value: Int) {
|
||||
array[index] = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(bytes: IntArray) =
|
||||
IntVec(bytes.size).also {
|
||||
bytes.copyInto(it.array)
|
||||
it.size += bytes.size
|
||||
}
|
||||
|
||||
fun from(bytes: Sequence<Int>) =
|
||||
IntVec().also { bv ->
|
||||
bytes.forEach(bv::pushBack)
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,3 +31,39 @@ fun <T> MutableList<T>.addFront(value: T) =
|
||||
|
||||
fun <T: Any> Iterable<T?>.countNotNull() =
|
||||
count { it != null }
|
||||
|
||||
fun <T> Iterable<Iterable<T>>.intersections(dest: MutableList<T> = mutableListOf()): MutableList<T> =
|
||||
reduce { acc, li -> acc.intersect(li) }
|
||||
.forEach { dest += it }
|
||||
.let { dest }
|
||||
|
||||
fun <T> Iterable<T>.removeAtIndexes(idc: Iterable<Int>, dest: MutableList<T> = mutableListOf()): MutableList<T> =
|
||||
filterIndexedTo(dest) { index, _ -> index !in idc }
|
||||
|
||||
fun <T> List<T>.gather(idc: Iterable<Int>): MutableList<T> {
|
||||
val dest = mutableListOf<T>()
|
||||
idc.forEach {
|
||||
dest += get(it)
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
fun <T> List<T>.before(idx: Int): List<T> =
|
||||
take(idx)
|
||||
|
||||
fun <T> List<T>.after(idx: Int): List<T> =
|
||||
drop(idx + 1)
|
||||
|
||||
inline fun <I, reified O> Collection<I>.mapToArray(fn: (I) -> O): Array<O> {
|
||||
val iter = this.iterator()
|
||||
return Array(this.size) {
|
||||
fn(iter.next())
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <I, reified O> Collection<I>.mapIndexedToArray(fn: (Int, I) -> O): Array<O> {
|
||||
val iter = this.iterator()
|
||||
return Array(this.size) {
|
||||
fn(it, iter.next())
|
||||
}
|
||||
}
|
147
src/main/kotlin/blitz/collections/LongVec.kt
Normal file
147
src/main/kotlin/blitz/collections/LongVec.kt
Normal file
@@ -0,0 +1,147 @@
|
||||
package blitz.collections
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class LongVec(private val initCap: Int = 0): Vec<Long>, BatchSequence<Long> {
|
||||
override var size = 0
|
||||
private var cap = initCap
|
||||
private var array = LongArray(initCap)
|
||||
|
||||
override fun clear() {
|
||||
size = 0
|
||||
if (array.size <= initCap) {
|
||||
cap = array.size
|
||||
} else {
|
||||
cap = initCap
|
||||
array = LongArray(initCap)
|
||||
}
|
||||
}
|
||||
|
||||
fun copyAsArray(): LongArray =
|
||||
array.copyOfRange(0, size)
|
||||
|
||||
fun copyIntoArray(arr: LongArray, destOff: Int = 0, startOff: Int = 0) =
|
||||
array.copyInto(arr, destOff, startOff, size)
|
||||
|
||||
override fun copy(): LongVec =
|
||||
LongVec(size).also {
|
||||
copyIntoArray(it.array)
|
||||
}
|
||||
|
||||
override fun reserve(amount: Int) {
|
||||
if (amount > 0 && cap - size >= amount)
|
||||
return
|
||||
array = array.copyOf(size + amount)
|
||||
cap = size + amount
|
||||
}
|
||||
|
||||
override fun reserve(need: Int, wantIfRealloc: Int) {
|
||||
if (need > 0 && cap - size >= need)
|
||||
return
|
||||
cap = size + wantIfRealloc
|
||||
array = array.copyOf(cap)
|
||||
}
|
||||
|
||||
override fun popBack(): Long =
|
||||
array[size - 1].also {
|
||||
reserve(-1)
|
||||
size --
|
||||
}
|
||||
|
||||
fun tryPopPack(dest: LongArray, destOff: Int = 0): Int {
|
||||
val can = kotlin.math.min(size, dest.size - destOff)
|
||||
copyIntoArray(dest, destOff, size - can)
|
||||
reserve(-can)
|
||||
size -= can
|
||||
return can
|
||||
}
|
||||
|
||||
fun popBack(dest: LongArray, destOff: Int = 0) {
|
||||
val destCopySize = dest.size - destOff
|
||||
require(size >= destCopySize)
|
||||
copyIntoArray(dest, destOff, size - destCopySize)
|
||||
reserve(-destCopySize)
|
||||
size -= destCopySize
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBack(batching: LongArray, fn: (LongArray, Int) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
fn(batching, rem)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun consumePopBack(batching: LongArray, fn: (Long) -> Unit) =
|
||||
consumePopBack(batching) { batch, count ->
|
||||
repeat(count) {
|
||||
fn(batch[it])
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBackSlicedBatches(batching: LongArray, fn: (LongArray) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
if (rem == batching.size)
|
||||
fn(batching)
|
||||
else
|
||||
fn(batching.copyOf(rem))
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(index: Int): Long =
|
||||
array[index]
|
||||
|
||||
override fun flip() {
|
||||
array = array.reversedArray()
|
||||
}
|
||||
|
||||
fun pushBack(arr: LongArray) {
|
||||
reserve(arr.size)
|
||||
arr.copyInto(array, size)
|
||||
size += arr.size
|
||||
}
|
||||
|
||||
override fun pushBack(elem: Long) {
|
||||
reserve(1, 8)
|
||||
array[size] = elem
|
||||
size ++
|
||||
}
|
||||
|
||||
override fun iterator(): BatchIterator<Long> =
|
||||
array.asSequence().asBatch().iterator()
|
||||
|
||||
override fun toString(): String =
|
||||
contents.toString()
|
||||
|
||||
override fun set(index: Int, value: Long) {
|
||||
array[index] = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(bytes: LongArray) =
|
||||
LongVec(bytes.size).also {
|
||||
bytes.copyInto(it.array)
|
||||
it.size += bytes.size
|
||||
}
|
||||
|
||||
fun from(bytes: Sequence<Long>) =
|
||||
LongVec().also { bv ->
|
||||
bytes.forEach(bv::pushBack)
|
||||
}
|
||||
}
|
||||
}
|
@@ -89,6 +89,18 @@ class RefVec<T>(private val initCap: Int = 0): Vec<T> {
|
||||
(_array as Array<Any?>)[index] = value
|
||||
}
|
||||
|
||||
inline fun <R, C: MutableCollection<R>> mapTo(dest: C, fn: (T) -> R): C {
|
||||
_array?.let {
|
||||
for (i in 0 until size) {
|
||||
dest.add(fn(it[i] as T))
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
inline fun <R> map(fn: (T) -> R): MutableList<R> =
|
||||
MutableList(size) { fn(this[it]) }
|
||||
|
||||
companion object {
|
||||
fun <T> from(data: Array<T>) =
|
||||
RefVec<T>(data.size).also {
|
||||
@@ -102,8 +114,9 @@ class RefVec<T>(private val initCap: Int = 0): Vec<T> {
|
||||
}
|
||||
|
||||
inline fun <T> of(vararg elements: T): RefVec<T> =
|
||||
RefVec<T>(elements.size shl 2).also {
|
||||
RefVec<T>(elements.size shl 1).also {
|
||||
it._array?.let { elements.copyInto(it) }
|
||||
it.size += elements.size
|
||||
}
|
||||
}
|
||||
}
|
147
src/main/kotlin/blitz/collections/ShortVec.kt
Normal file
147
src/main/kotlin/blitz/collections/ShortVec.kt
Normal file
@@ -0,0 +1,147 @@
|
||||
package blitz.collections
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class ShortVec(private val initCap: Int = 0): Vec<Short>, BatchSequence<Short> {
|
||||
override var size = 0
|
||||
private var cap = initCap
|
||||
private var array = ShortArray(initCap)
|
||||
|
||||
override fun clear() {
|
||||
size = 0
|
||||
if (array.size <= initCap) {
|
||||
cap = array.size
|
||||
} else {
|
||||
cap = initCap
|
||||
array = ShortArray(initCap)
|
||||
}
|
||||
}
|
||||
|
||||
fun copyAsArray(): ShortArray =
|
||||
array.copyOfRange(0, size)
|
||||
|
||||
fun copyIntoArray(arr: ShortArray, destOff: Int = 0, startOff: Int = 0) =
|
||||
array.copyInto(arr, destOff, startOff, size)
|
||||
|
||||
override fun copy(): ShortVec =
|
||||
ShortVec(size).also {
|
||||
copyIntoArray(it.array)
|
||||
}
|
||||
|
||||
override fun reserve(amount: Int) {
|
||||
if (amount > 0 && cap - size >= amount)
|
||||
return
|
||||
array = array.copyOf(size + amount)
|
||||
cap = size + amount
|
||||
}
|
||||
|
||||
override fun reserve(need: Int, wantIfRealloc: Int) {
|
||||
if (need > 0 && cap - size >= need)
|
||||
return
|
||||
cap = size + wantIfRealloc
|
||||
array = array.copyOf(cap)
|
||||
}
|
||||
|
||||
override fun popBack(): Short =
|
||||
array[size - 1].also {
|
||||
reserve(-1)
|
||||
size --
|
||||
}
|
||||
|
||||
fun tryPopPack(dest: ShortArray, destOff: Int = 0): Int {
|
||||
val can = kotlin.math.min(size, dest.size - destOff)
|
||||
copyIntoArray(dest, destOff, size - can)
|
||||
reserve(-can)
|
||||
size -= can
|
||||
return can
|
||||
}
|
||||
|
||||
fun popBack(dest: ShortArray, destOff: Int = 0) {
|
||||
val destCopySize = dest.size - destOff
|
||||
require(size >= destCopySize)
|
||||
copyIntoArray(dest, destOff, size - destCopySize)
|
||||
reserve(-destCopySize)
|
||||
size -= destCopySize
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBack(batching: ShortArray, fn: (ShortArray, Int) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
fn(batching, rem)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun consumePopBack(batching: ShortArray, fn: (Short) -> Unit) =
|
||||
consumePopBack(batching) { batch, count ->
|
||||
repeat(count) {
|
||||
fn(batch[it])
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun consumePopBackSlicedBatches(batching: ShortArray, fn: (ShortArray) -> Unit) {
|
||||
contract {
|
||||
callsInPlace(fn)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
val rem = tryPopPack(batching)
|
||||
if (rem == 0) break
|
||||
|
||||
if (rem == batching.size)
|
||||
fn(batching)
|
||||
else
|
||||
fn(batching.copyOf(rem))
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(index: Int): Short =
|
||||
array[index]
|
||||
|
||||
override fun flip() {
|
||||
array = array.reversedArray()
|
||||
}
|
||||
|
||||
fun pushBack(arr: ShortArray) {
|
||||
reserve(arr.size)
|
||||
arr.copyInto(array, size)
|
||||
size += arr.size
|
||||
}
|
||||
|
||||
override fun pushBack(elem: Short) {
|
||||
reserve(1, 8)
|
||||
array[size] = elem
|
||||
size ++
|
||||
}
|
||||
|
||||
override fun iterator(): BatchIterator<Short> =
|
||||
array.asSequence().asBatch().iterator()
|
||||
|
||||
override fun toString(): String =
|
||||
contents.toString()
|
||||
|
||||
override fun set(index: Int, value: Short) {
|
||||
array[index] = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(bytes: ShortArray) =
|
||||
ShortVec(bytes.size).also {
|
||||
bytes.copyInto(it.array)
|
||||
it.size += bytes.size
|
||||
}
|
||||
|
||||
fun from(bytes: Sequence<Short>) =
|
||||
ShortVec().also { bv ->
|
||||
bytes.forEach(bv::pushBack)
|
||||
}
|
||||
}
|
||||
}
|
11
src/main/kotlin/blitz/collections/SmartVec.kt
Normal file
11
src/main/kotlin/blitz/collections/SmartVec.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package blitz.collections
|
||||
|
||||
inline fun <reified T> SmartVec(initCap: Int = 0): Vec<T> =
|
||||
when (T::class.java) {
|
||||
Char::class.java -> CharVec(initCap) as Vec<T>
|
||||
Byte::class.java -> ByteVec(initCap) as Vec<T>
|
||||
Short::class.java -> ShortVec(initCap) as Vec<T>
|
||||
Int::class.java -> IntVec(initCap) as Vec<T>
|
||||
Long::class.java -> LongVec(initCap) as Vec<T>
|
||||
else -> RefVec(initCap)
|
||||
}
|
@@ -1,10 +1,9 @@
|
||||
package blitz.parse
|
||||
|
||||
import blitz.collections.RefVec
|
||||
import blitz.collections.contents
|
||||
import blitz.parse.comb2.*
|
||||
import org.json.JSONObject
|
||||
import kotlin.math.min
|
||||
import kotlin.system.measureNanoTime
|
||||
import blitz.unreachable
|
||||
|
||||
object JSON {
|
||||
|
||||
@@ -27,8 +26,10 @@ object JSON {
|
||||
val jsonArray: Parser<Char, Element> =
|
||||
thenIgnore(
|
||||
thenIgnore(
|
||||
thenOverwrite(just('['),
|
||||
mapValue(delimitedBy(jsonElement, just(',')), Element::newArr)),
|
||||
thenOverwrite(
|
||||
thenIgnore(just('['), whitespaces),
|
||||
mapValue(delimitedBy(jsonElement,
|
||||
chain(whitespaces, ignoreSeq(","), whitespaces)), Element::newArr)),
|
||||
whitespaces),
|
||||
just(']')
|
||||
)
|
||||
@@ -91,6 +92,17 @@ object JSON {
|
||||
inline fun newObj(v: Map<String, Element>): Element =
|
||||
Element(OBJ, _boxed = v)
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
when (kind) {
|
||||
NUM -> uncheckedAsNum().toString()
|
||||
BOOL -> uncheckedAsBool().toString()
|
||||
NULL -> "null"
|
||||
ARR -> uncheckedAsArr().contents.toString()
|
||||
STR -> "\"${uncheckedAsStr()}\""
|
||||
OBJ -> uncheckedAsObj().map { "${it.key}: ${it.value}" }.joinToString(prefix = "{", postfix = "}")
|
||||
else -> unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Element.uncheckedAsNum(): Double =
|
||||
@@ -129,211 +141,6 @@ object JSON {
|
||||
return _boxed as Map<String, Element>
|
||||
}
|
||||
|
||||
fun parse(string: String): ParseResult<Element> {
|
||||
val ctx = ParseCtx(string.toList(), 0)
|
||||
val v = jsonElement(ctx)
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val json = """
|
||||
{
|
||||
"clinical_study": {
|
||||
"brief_summary": {
|
||||
"textblock": "CLEAR SYNERGY is an international multi center 2x2 randomized placebo controlled trial of"
|
||||
},
|
||||
"brief_title": "CLEAR SYNERGY Neutrophil Substudy",
|
||||
"overall_status": "Recruiting",
|
||||
"eligibility": {
|
||||
"study_pop": {
|
||||
"textblock": "Patients who are randomized to the drug RCT portion of the CLEAR SYNERGY (OASIS 9) trial"
|
||||
},
|
||||
"minimum_age": "19 Years",
|
||||
"sampling_method": "Non-Probability Sample",
|
||||
"gender": "All",
|
||||
"criteria": {
|
||||
"textblock": "Inclusion Criteria:"
|
||||
},
|
||||
"healthy_volunteers": "No",
|
||||
"maximum_age": "110 Years"
|
||||
},
|
||||
"number_of_groups": "2",
|
||||
"source": "NYU Langone Health",
|
||||
"location_countries": {
|
||||
"country": "United States"
|
||||
},
|
||||
"study_design_info": {
|
||||
"time_perspective": "Prospective",
|
||||
"observational_model": "Other"
|
||||
},
|
||||
"last_update_submitted_qc": "September 10, 2019",
|
||||
"intervention_browse": {
|
||||
"mesh_term": "Colchicine"
|
||||
},
|
||||
"official_title": "Studies on the Effects of Colchicine on Neutrophil Biology in Acute Myocardial Infarction: A Substudy of the CLEAR SYNERGY (OASIS 9) Trial",
|
||||
"primary_completion_date": {
|
||||
"type": "Anticipated",
|
||||
"content": "February 1, 2021"
|
||||
},
|
||||
"sponsors": {
|
||||
"lead_sponsor": {
|
||||
"agency_class": "Other",
|
||||
"agency": "NYU Langone Health"
|
||||
},
|
||||
"collaborator": [
|
||||
{
|
||||
"agency_class": "Other",
|
||||
"agency": "Population Health Research Institute"
|
||||
},
|
||||
{
|
||||
"agency_class": "NIH",
|
||||
"agency": "National Heart, Lung, and Blood Institute (NHLBI)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overall_official": {
|
||||
"role": "Principal Investigator",
|
||||
"affiliation": "NYU School of Medicine",
|
||||
"last_name": "Binita Shah, MD"
|
||||
},
|
||||
"overall_contact_backup": {
|
||||
"last_name": "Binita Shah, MD"
|
||||
},
|
||||
"condition_browse": {
|
||||
"mesh_term": [
|
||||
"Myocardial Infarction",
|
||||
"ST Elevation Myocardial Infarction",
|
||||
"Infarction"
|
||||
]
|
||||
},
|
||||
"overall_contact": {
|
||||
"phone": "646-501-9648",
|
||||
"last_name": "Fatmira Curovic",
|
||||
"email": "fatmira.curovic@nyumc.org"
|
||||
},
|
||||
"responsible_party": {
|
||||
"responsible_party_type": "Principal Investigator",
|
||||
"investigator_title": "Assistant Professor of Medicine",
|
||||
"investigator_full_name": "Binita Shah",
|
||||
"investigator_affiliation": "NYU Langone Health"
|
||||
},
|
||||
"study_first_submitted_qc": "March 12, 2019",
|
||||
"start_date": {
|
||||
"type": "Actual",
|
||||
"content": "March 4, 2019"
|
||||
},
|
||||
"has_expanded_access": "No",
|
||||
"study_first_posted": {
|
||||
"type": "Actual",
|
||||
"content": "March 14, 2019"
|
||||
},
|
||||
"arm_group": [
|
||||
{
|
||||
"arm_group_label": "Colchicine"
|
||||
},
|
||||
{
|
||||
"arm_group_label": "Placebo"
|
||||
}
|
||||
],
|
||||
"primary_outcome": {
|
||||
"measure": "soluble L-selectin",
|
||||
"time_frame": "between baseline and 3 months",
|
||||
"description": "Change in soluble L-selectin between baseline and 3 mo after STEMI in the placebo vs. colchicine groups."
|
||||
},
|
||||
"secondary_outcome": [
|
||||
{
|
||||
"measure": "Other soluble markers of neutrophil activity",
|
||||
"time_frame": "between baseline and 3 months",
|
||||
"description": "Other markers of neutrophil activity will be evaluated at baseline and 3 months after STEMI (myeloperoxidase, matrix metalloproteinase-9, neutrophil gelatinase-associated lipocalin, neutrophil elastase, intercellular/vascular cellular adhesion molecules)"
|
||||
},
|
||||
{
|
||||
"measure": "Markers of systemic inflammation",
|
||||
"time_frame": "between baseline and 3 months",
|
||||
"description": "Markers of systemic inflammation will be evaluated at baseline and 3 months after STEMI (high sensitive CRP, IL-1β)"
|
||||
},
|
||||
{
|
||||
"measure": "Neutrophil-driven responses that may further propagate injury",
|
||||
"time_frame": "between baseline and 3 months",
|
||||
"description": "Neutrophil-driven responses that may further propagate injury will be evaluated at baseline and 3 months after STEMI (neutrophil extracellular traps, neutrophil-derived microparticles)"
|
||||
}
|
||||
],
|
||||
"oversight_info": {
|
||||
"is_fda_regulated_drug": "No",
|
||||
"is_fda_regulated_device": "No",
|
||||
"has_dmc": "No"
|
||||
},
|
||||
"last_update_posted": {
|
||||
"type": "Actual",
|
||||
"content": "September 12, 2019"
|
||||
},
|
||||
"id_info": {
|
||||
"nct_id": "NCT03874338",
|
||||
"org_study_id": "18-01323",
|
||||
"secondary_id": "1R01HL146206"
|
||||
},
|
||||
"enrollment": {
|
||||
"type": "Anticipated",
|
||||
"content": "670"
|
||||
},
|
||||
"study_first_submitted": "March 12, 2019",
|
||||
"condition": [
|
||||
"Neutrophils.Hypersegmented | Bld-Ser-Plas",
|
||||
"STEMI - ST Elevation Myocardial Infarction"
|
||||
],
|
||||
"study_type": "Observational",
|
||||
"required_header": {
|
||||
"download_date": "ClinicalTrials.gov processed this data on July 19, 2020",
|
||||
"link_text": "Link to the current ClinicalTrials.gov record.",
|
||||
"url": "https://clinicaltrials.gov/show/NCT03874338"
|
||||
},
|
||||
"last_update_submitted": "September 10, 2019",
|
||||
"completion_date": {
|
||||
"type": "Anticipated",
|
||||
"content": "February 1, 2022"
|
||||
},
|
||||
"location": {
|
||||
"contact": {
|
||||
"phone": "646-501-9648",
|
||||
"last_name": "Fatmira Curovic",
|
||||
"email": "fatmira.curovic@nyumc.org"
|
||||
},
|
||||
"facility": {
|
||||
"address": {
|
||||
"zip": "10016",
|
||||
"country": "United States",
|
||||
"city": "New York",
|
||||
"state": "New York"
|
||||
},
|
||||
"name": "NYU School of Medicine"
|
||||
},
|
||||
"status": "Recruiting",
|
||||
"contact_backup": {
|
||||
"last_name": "Binita Shah, MD"
|
||||
}
|
||||
},
|
||||
"intervention": {
|
||||
"intervention_type": "Drug",
|
||||
"arm_group_label": [
|
||||
"Colchicine",
|
||||
"Placebo"
|
||||
],
|
||||
"description": "Participants in the main CLEAR SYNERGY trial are randomized to colchicine/spironolactone versus placebo in a 2x2 factorial design. The substudy is interested in the evaluation of biospecimens obtained from patients in the colchicine vs placebo group.",
|
||||
"intervention_name": "Colchicine Pill"
|
||||
},
|
||||
"patient_data": {
|
||||
"sharing_ipd": "No"
|
||||
},
|
||||
"verification_date": "September 2019"
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
var minAlex = Long.MAX_VALUE
|
||||
var minJson = Long.MAX_VALUE
|
||||
while (true) {
|
||||
minAlex = min(measureNanoTime { JSON.parse(json).a!! }, minAlex)
|
||||
minJson = min(measureNanoTime { JSONObject(json) }, minJson)
|
||||
println("alex: $minAlex ns, json-java: $minJson ns ; alex is ${ minJson.toFloat() / minAlex.toFloat() } times as fast as json-java")
|
||||
}
|
||||
fun parse(string: String): ParseResult<Element> =
|
||||
jsonElement.run(string.toList())
|
||||
}
|
@@ -2,6 +2,8 @@ package blitz.parse.comb2
|
||||
|
||||
import blitz.*
|
||||
import blitz.collections.RefVec
|
||||
import blitz.collections.containsAt
|
||||
import blitz.parse.JSON.jsonElement
|
||||
import blitz.str.charsToString
|
||||
|
||||
data class ParseCtx<I>(
|
||||
@@ -192,9 +194,29 @@ fun <I, O: Any> chain(parsers: List<Parser<I, O>>): Parser<I, RefVec<O>> =
|
||||
else Either.ofA(results)
|
||||
}
|
||||
|
||||
inline fun <I, O: Any> chain(vararg parsers: Parser<I, O>): Parser<I, RefVec<O>> =
|
||||
chain(parsers.toList())
|
||||
|
||||
inline fun <I: Any> seq(want: List<I>): Parser<I, RefVec<I>> =
|
||||
chain(want.map(::just))
|
||||
|
||||
inline fun seq(want: String): Parser<Char, RefVec<Char>> =
|
||||
chain(want.map(::just))
|
||||
|
||||
inline fun ignoreSeq(want: String): Parser<Char, Unit> =
|
||||
{ ctx ->
|
||||
if (ctx.idx >= ctx.input.size) {
|
||||
Either.ofB(ParseError(ctx.idx, "unexpected end of file"))
|
||||
} else {
|
||||
if (ctx.input.containsAt(ctx.idx, want.toList())) {
|
||||
ctx.idx += want.length
|
||||
Either.ofA(Unit)
|
||||
} else {
|
||||
Either.ofB(ParseError(ctx.idx, "expected $want"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <I: Any> filter(msg: String, crossinline filter: (I) -> Boolean): Parser<I, I> =
|
||||
{ ctx ->
|
||||
if (ctx.idx >= ctx.input.size) {
|
||||
@@ -254,3 +276,12 @@ fun <O: Any> regex(pattern: String, fn: (groups: MatchGroupCollection) -> O): Pa
|
||||
regex(Regex(pattern), fn)
|
||||
|
||||
fun regex(pattern: String) = regex(pattern) { it[0]!!.value }
|
||||
|
||||
fun <O: Any> ParseResult<O>.unwrap(): O =
|
||||
flatMap(
|
||||
{ it },
|
||||
{ throw Exception("at ${it.loc}: ${it.message}") }
|
||||
)
|
||||
|
||||
fun <I, O: Any> Parser<I, O>.run(input: List<I>): ParseResult<O> =
|
||||
this(ParseCtx(input, 0))
|
@@ -14,24 +14,24 @@ val digit: Parser<Char, Char> =
|
||||
filter("expected digit") { it >= '0' && it <= '9' }
|
||||
|
||||
val uintLit: Parser<Char, RefVec<Char>> =
|
||||
verifyValueWithSpan(withSpan(repeated(digit)))
|
||||
verifyValue(repeated(digit))
|
||||
{ if (it.size == 0) "need digits after sign in num lit" else null }
|
||||
|
||||
val intLit: Parser<Char, Int> =
|
||||
mapValue(then(choose<Char,Int> {
|
||||
val intLit: Parser<Char, Long> =
|
||||
mapValue(then(choose<Char, Int> {
|
||||
it(mapValue(just('+')) { +1 })
|
||||
it(mapValue(just('-')) { -1 })
|
||||
it(value(+1))
|
||||
}, uintLit))
|
||||
{ (sign, v) -> sign * v.charsToString().toInt() }
|
||||
{ (sign, v) -> sign * (v.charsToString().toLongOrNull() ?: Long.MAX_VALUE) }
|
||||
|
||||
val floatLit: Parser<Char, Double> =
|
||||
mapValue(
|
||||
then(
|
||||
thenIgnore(
|
||||
intLit,
|
||||
just('.')),
|
||||
orElseVal(uintLit, RefVec.of('0'))))
|
||||
orElseVal(
|
||||
thenOverwrite(just('.'), uintLit),
|
||||
RefVec.of('0'))))
|
||||
{ (pre, post) ->
|
||||
var p = post.charsToString().toDouble()
|
||||
while (p.absoluteValue >= 1) {
|
||||
|
@@ -1,13 +1,21 @@
|
||||
package blitz.str
|
||||
|
||||
import blitz.collections.ByteVec
|
||||
import blitz.collections.CharVec
|
||||
import blitz.collections.Vec
|
||||
|
||||
fun Collection<Char>.charsToString(): String =
|
||||
String(this.toCharArray())
|
||||
|
||||
fun Vec<Char>.charsToString(): String =
|
||||
String(CharArray(size) { this[it] })
|
||||
when (this) {
|
||||
is CharVec -> subViewToString(0)
|
||||
else -> String(CharArray(size) { this[it] })
|
||||
}
|
||||
|
||||
@JvmName("charsToString_VecByte")
|
||||
fun Vec<Byte>.charsToString(): String =
|
||||
String(CharArray(size) { this[it].toInt().toChar() })
|
||||
when (this) {
|
||||
is ByteVec -> String(unsafeBackingArr())
|
||||
else -> String(CharArray(size) { this[it].toInt().toChar() })
|
||||
}
|
Reference in New Issue
Block a user