diff --git a/README.md b/README.md index a54fa2c..2648188 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ repositories { } dependencies { - implementation("me.alex_s168:blitz:0.21") + implementation("me.alex_s168:blitz:0.22h2") } ``` diff --git a/build.gradle.kts b/build.gradle.kts index bc69bdb..4129277 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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 { diff --git a/src/main/kotlin/blitz/Either.kt b/src/main/kotlin/blitz/Either.kt index 905a803..8fd6e09 100644 --- a/src/main/kotlin/blitz/Either.kt +++ b/src/main/kotlin/blitz/Either.kt @@ -113,4 +113,12 @@ fun Either>.getBAOrNull(): BA? = b?.a fun Either>.getBBOrNull(): BB? = - b?.b \ No newline at end of file + b?.b + +inline fun Either.map(fa: (A) -> RA, fb: (B) -> RB): Either = + if (a != null) Either.ofA(fa(a!!)) + else Either.ofB(fb(b!!)) + +inline fun Either.flatMap(fa: (A) -> R, fb: (B) -> R): R = + if (a != null) fa(a!!) + else fb(b!!) \ No newline at end of file diff --git a/src/main/kotlin/blitz/Switch.kt b/src/main/kotlin/blitz/Switch.kt new file mode 100644 index 0000000..ba936f7 --- /dev/null +++ b/src/main/kotlin/blitz/Switch.kt @@ -0,0 +1,26 @@ +package blitz + +data class SwitchCase( + val cond: (C) -> Pair, + val then: (T) -> R, +) + +inline infix fun ((C)->Pair).case(noinline then: (T) -> R) = + SwitchCase(this, then) + +infix fun Regex.startsWithCase(then: (MatchResult) -> R): SwitchCase = + { it: String -> + this.matchAt(it, 0)?.let { + true to it + } ?: (false to null) + } case then + +inline fun T.switch(vararg cases: SwitchCase, default: (T) -> R): R { + cases.forEach { (cond, then) -> + val (b, v) = cond(this) + if (b) { + return (then as (Any) -> R)(v!!) + } + } + return default(this) +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/Utils.kt b/src/main/kotlin/blitz/Utils.kt new file mode 100644 index 0000000..567b07a --- /dev/null +++ b/src/main/kotlin/blitz/Utils.kt @@ -0,0 +1,7 @@ +package blitz + +fun unreachable(): Nothing = + error("this should be unreachable") + +inline fun Any?.cast(): R? = + this?.let { if (it is R) it else null } \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/ByteVec.kt b/src/main/kotlin/blitz/collections/ByteVec.kt index a5e66d5..8faee02 100644 --- a/src/main/kotlin/blitz/collections/ByteVec.kt +++ b/src/main/kotlin/blitz/collections/ByteVec.kt @@ -18,6 +18,9 @@ class ByteVec(private val initCap: Int = 0): Vec, ByteBatchSequence { } } + fun unsafeBackingArr(): ByteArray = + array + fun copyAsArray(): ByteArray = array.copyOfRange(0, size) diff --git a/src/main/kotlin/blitz/collections/CharVec.kt b/src/main/kotlin/blitz/collections/CharVec.kt new file mode 100644 index 0000000..2e44a8d --- /dev/null +++ b/src/main/kotlin/blitz/collections/CharVec.kt @@ -0,0 +1,156 @@ +package blitz.collections + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +class CharVec(private val initCap: Int = 0): Vec, BatchSequence { + 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 = + 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) = + CharVec().also { bv -> + bytes.forEach(bv::pushBack) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/Compare.kt b/src/main/kotlin/blitz/collections/Compare.kt new file mode 100644 index 0000000..d495f05 --- /dev/null +++ b/src/main/kotlin/blitz/collections/Compare.kt @@ -0,0 +1,23 @@ +package blitz.collections + +fun List.containsAt(at: Int, other: List): Boolean { + if (at + other.size > size) + return false + for (i in at.. List.startsWith(other: List): 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) \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/IntVec.kt b/src/main/kotlin/blitz/collections/IntVec.kt new file mode 100644 index 0000000..7cb2c45 --- /dev/null +++ b/src/main/kotlin/blitz/collections/IntVec.kt @@ -0,0 +1,147 @@ +package blitz.collections + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +class IntVec(private val initCap: Int = 0): Vec, BatchSequence { + 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 = + 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) = + IntVec().also { bv -> + bytes.forEach(bv::pushBack) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/ListOps.kt b/src/main/kotlin/blitz/collections/ListOps.kt index 57f1fc8..49c5704 100644 --- a/src/main/kotlin/blitz/collections/ListOps.kt +++ b/src/main/kotlin/blitz/collections/ListOps.kt @@ -30,4 +30,40 @@ fun MutableList.addFront(value: T) = add(0, value) fun Iterable.countNotNull() = - count { it != null } \ No newline at end of file + count { it != null } + +fun Iterable>.intersections(dest: MutableList = mutableListOf()): MutableList = + reduce { acc, li -> acc.intersect(li) } + .forEach { dest += it } + .let { dest } + +fun Iterable.removeAtIndexes(idc: Iterable, dest: MutableList = mutableListOf()): MutableList = + filterIndexedTo(dest) { index, _ -> index !in idc } + +fun List.gather(idc: Iterable): MutableList { + val dest = mutableListOf() + idc.forEach { + dest += get(it) + } + return dest +} + +fun List.before(idx: Int): List = + take(idx) + +fun List.after(idx: Int): List = + drop(idx + 1) + +inline fun Collection.mapToArray(fn: (I) -> O): Array { + val iter = this.iterator() + return Array(this.size) { + fn(iter.next()) + } +} + +inline fun Collection.mapIndexedToArray(fn: (Int, I) -> O): Array { + val iter = this.iterator() + return Array(this.size) { + fn(it, iter.next()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/LongVec.kt b/src/main/kotlin/blitz/collections/LongVec.kt new file mode 100644 index 0000000..3c6f15a --- /dev/null +++ b/src/main/kotlin/blitz/collections/LongVec.kt @@ -0,0 +1,147 @@ +package blitz.collections + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +class LongVec(private val initCap: Int = 0): Vec, BatchSequence { + 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 = + 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) = + LongVec().also { bv -> + bytes.forEach(bv::pushBack) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/RefVec.kt b/src/main/kotlin/blitz/collections/RefVec.kt index fbd122b..dd33fbc 100644 --- a/src/main/kotlin/blitz/collections/RefVec.kt +++ b/src/main/kotlin/blitz/collections/RefVec.kt @@ -89,6 +89,18 @@ class RefVec(private val initCap: Int = 0): Vec { (_array as Array)[index] = value } + inline fun > 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 map(fn: (T) -> R): MutableList = + MutableList(size) { fn(this[it]) } + companion object { fun from(data: Array) = RefVec(data.size).also { @@ -102,8 +114,9 @@ class RefVec(private val initCap: Int = 0): Vec { } inline fun of(vararg elements: T): RefVec = - RefVec(elements.size shl 2).also { + RefVec(elements.size shl 1).also { it._array?.let { elements.copyInto(it) } + it.size += elements.size } } } \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/ShortVec.kt b/src/main/kotlin/blitz/collections/ShortVec.kt new file mode 100644 index 0000000..4534372 --- /dev/null +++ b/src/main/kotlin/blitz/collections/ShortVec.kt @@ -0,0 +1,147 @@ +package blitz.collections + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +class ShortVec(private val initCap: Int = 0): Vec, BatchSequence { + 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 = + 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) = + ShortVec().also { bv -> + bytes.forEach(bv::pushBack) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/collections/SmartVec.kt b/src/main/kotlin/blitz/collections/SmartVec.kt new file mode 100644 index 0000000..4d47990 --- /dev/null +++ b/src/main/kotlin/blitz/collections/SmartVec.kt @@ -0,0 +1,11 @@ +package blitz.collections + +inline fun SmartVec(initCap: Int = 0): Vec = + when (T::class.java) { + Char::class.java -> CharVec(initCap) as Vec + Byte::class.java -> ByteVec(initCap) as Vec + Short::class.java -> ShortVec(initCap) as Vec + Int::class.java -> IntVec(initCap) as Vec + Long::class.java -> LongVec(initCap) as Vec + else -> RefVec(initCap) + } \ No newline at end of file diff --git a/src/main/kotlin/blitz/parse/JSON.kt b/src/main/kotlin/blitz/parse/JSON.kt index e3b5655..dfe6163 100644 --- a/src/main/kotlin/blitz/parse/JSON.kt +++ b/src/main/kotlin/blitz/parse/JSON.kt @@ -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 = 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): 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 } - fun parse(string: String): ParseResult { - 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 = + jsonElement.run(string.toList()) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/parse/comb2/Parser.kt b/src/main/kotlin/blitz/parse/comb2/Parser.kt index f6f466f..1dfd098 100644 --- a/src/main/kotlin/blitz/parse/comb2/Parser.kt +++ b/src/main/kotlin/blitz/parse/comb2/Parser.kt @@ -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( @@ -192,9 +194,29 @@ fun chain(parsers: List>): Parser> = else Either.ofA(results) } +inline fun chain(vararg parsers: Parser): Parser> = + chain(parsers.toList()) + inline fun seq(want: List): Parser> = chain(want.map(::just)) +inline fun seq(want: String): Parser> = + chain(want.map(::just)) + +inline fun ignoreSeq(want: String): Parser = + { 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 filter(msg: String, crossinline filter: (I) -> Boolean): Parser = { ctx -> if (ctx.idx >= ctx.input.size) { @@ -253,4 +275,13 @@ fun regex(pattern: Regex) = regex(pattern) { it[0]!!.value } fun regex(pattern: String, fn: (groups: MatchGroupCollection) -> O): Parser = regex(Regex(pattern), fn) -fun regex(pattern: String) = regex(pattern) { it[0]!!.value } \ No newline at end of file +fun regex(pattern: String) = regex(pattern) { it[0]!!.value } + +fun ParseResult.unwrap(): O = + flatMap( + { it }, + { throw Exception("at ${it.loc}: ${it.message}") } + ) + +fun Parser.run(input: List): ParseResult = + this(ParseCtx(input, 0)) \ No newline at end of file diff --git a/src/main/kotlin/blitz/parse/comb2/Predef.kt b/src/main/kotlin/blitz/parse/comb2/Predef.kt index c77e949..f3df93f 100644 --- a/src/main/kotlin/blitz/parse/comb2/Predef.kt +++ b/src/main/kotlin/blitz/parse/comb2/Predef.kt @@ -14,24 +14,24 @@ val digit: Parser = filter("expected digit") { it >= '0' && it <= '9' } val uintLit: Parser> = - verifyValueWithSpan(withSpan(repeated(digit))) - { if (it.size == 0) "need digits after sign in num lit" else null } + verifyValue(repeated(digit)) + { if (it.size == 0) "need digits after sign in num lit" else null } -val intLit: Parser = - mapValue(then(choose { +val intLit: Parser = + mapValue(then(choose { 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 = mapValue( then( - thenIgnore( - intLit, - just('.')), - orElseVal(uintLit, RefVec.of('0')))) + intLit, + orElseVal( + thenOverwrite(just('.'), uintLit), + RefVec.of('0')))) { (pre, post) -> var p = post.charsToString().toDouble() while (p.absoluteValue >= 1) { diff --git a/src/main/kotlin/blitz/str/CharsToString.kt b/src/main/kotlin/blitz/str/CharsToString.kt index 5d17583..14dbd9e 100644 --- a/src/main/kotlin/blitz/str/CharsToString.kt +++ b/src/main/kotlin/blitz/str/CharsToString.kt @@ -1,13 +1,21 @@ package blitz.str +import blitz.collections.ByteVec +import blitz.collections.CharVec import blitz.collections.Vec fun Collection.charsToString(): String = String(this.toCharArray()) fun Vec.charsToString(): String = - String(CharArray(size) { this[it] }) + when (this) { + is CharVec -> subViewToString(0) + else -> String(CharArray(size) { this[it] }) + } @JvmName("charsToString_VecByte") fun Vec.charsToString(): String = - String(CharArray(size) { this[it].toInt().toChar() }) \ No newline at end of file + when (this) { + is ByteVec -> String(unsafeBackingArr()) + else -> String(CharArray(size) { this[it].toInt().toChar() }) + } \ No newline at end of file