Tables refactor to KType

This commit is contained in:
Alexander Nozik 2021-02-23 17:40:28 +03:00
parent cf0c934acf
commit 488cd5a939
29 changed files with 177 additions and 145 deletions

View File

@ -4,6 +4,7 @@
### Added ### Added
### Changed ### Changed
- Kotlin-logging moved from common to JVM and JS. Replaced by console for native.
### Deprecated ### Deprecated

View File

@ -1,20 +1,20 @@
plugins { plugins {
id("ru.mipt.npm.project") id("ru.mipt.npm.gradle.project")
} }
val dataforgeVersion by extra("0.3.0")
allprojects { allprojects {
group = "hep.dataforge" group = "hep.dataforge"
version = dataforgeVersion version = "0.3.1"
apply<org.jetbrains.dokka.gradle.DokkaPlugin>() apply<org.jetbrains.dokka.gradle.DokkaPlugin>()
} }
subprojects { subprojects {
apply(plugin = "ru.mipt.npm.publish") apply(plugin = "ru.mipt.npm.gradle.publish")
repositories{
maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://dl.bintray.com/mipt-npm/dev")
}
} }
readme { readme {

View File

@ -95,6 +95,10 @@ public final class hep/dataforge/context/Global : hep/dataforge/context/Context
public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext;
} }
public final class hep/dataforge/context/LoggingJvmKt {
public static final fun buildLogger (Lhep/dataforge/context/Context;Ljava/lang/String;)Lmu/KLogger;
}
public final class hep/dataforge/context/LoggingKt { public final class hep/dataforge/context/LoggingKt {
public static final fun getLogger (Lhep/dataforge/context/Context;)Lmu/KLogger; public static final fun getLogger (Lhep/dataforge/context/Context;)Lmu/KLogger;
public static final fun getLogger (Lhep/dataforge/context/ContextAware;)Lmu/KLogger; public static final fun getLogger (Lhep/dataforge/context/ContextAware;)Lmu/KLogger;

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
description = "Context and provider definitions" description = "Context and provider definitions"
@ -11,22 +11,33 @@ kscience {
kotlin { kotlin {
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting{
dependencies { dependencies {
api(project(":dataforge-meta")) api(project(":dataforge-meta"))
api("io.github.microutils:kotlin-logging:1.9.0-dev-npm-2")
} }
} }
val jvmMain by getting { jvmMain {
dependencies { dependencies {
api(kotlin("reflect")) api(kotlin("reflect"))
api("ch.qos.logback:logback-classic:1.2.3") api("io.github.microutils:kotlin-logging-jvm:2.0.4")
implementation("ch.qos.logback:logback-classic:1.2.3")
} }
} }
val jsMain by getting { jsMain {
dependencies { dependencies {
api("io.github.microutils:kotlin-logging-js:2.0.4")
} }
} }
//
// val nativeMain by getting{
// dependsOn(commonMain)
// }
// val mingwX64Main by getting{
// dependsOn(nativeMain)
// }
// val linuxX64Main by getting{
// dependsOn(nativeMain)
// }
} }
} }

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
kscience{ kscience{

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
description = "IO module" description = "IO module"

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
// id("ru.mipt.npm.native") // id("ru.mipt.npm.gradle.native")
} }
description = "YAML meta IO" description = "YAML meta IO"

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
kscience { kscience {

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
kotlin { kotlin {

View File

@ -1,5 +1,5 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
} }
kotlin { kotlin {

View File

@ -1,14 +1,16 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
kotlin { kotlin {
sourceSets { sourceSets {
val commonMain by getting{ commonMain{
dependencies { dependencies {
api(project(":dataforge-context")) api(project(":dataforge-context"))
api(project(":dataforge-io")) api(project(":dataforge-io"))
api(kotlin("reflect"))
} }
} }
} }

View File

@ -1,10 +1,10 @@
package hep.dataforge.tables package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import kotlin.reflect.KClass import kotlin.reflect.KType
public data class ColumnDef<out T : Any>( public data class ColumnDef<out T : Any>(
override val name: String, override val name: String,
override val type: KClass<out T>, override val type: KType,
override val meta: Meta override val meta: Meta
): ColumnHeader<T> ): ColumnHeader<T>

View File

@ -6,7 +6,7 @@ import hep.dataforge.meta.int
import hep.dataforge.meta.string import hep.dataforge.meta.string
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import kotlin.reflect.KClass import kotlin.reflect.KType
public typealias TableHeader<C> = List<ColumnHeader<C>> public typealias TableHeader<C> = List<ColumnHeader<C>>
@ -14,13 +14,13 @@ public typealias ValueTableHeader = List<ColumnHeader<Value>>
public interface ColumnHeader<out T : Any> { public interface ColumnHeader<out T : Any> {
public val name: String public val name: String
public val type: KClass<out T> public val type: KType
public val meta: Meta public val meta: Meta
} }
public data class SimpleColumnHeader<T : Any>( public data class SimpleColumnHeader<T : Any>(
override val name: String, override val name: String,
override val type: KClass<out T>, override val type: KType,
override val meta: Meta override val meta: Meta
) : ColumnHeader<T> ) : ColumnHeader<T>

View File

@ -13,11 +13,11 @@ public class ColumnTable<T : Any>(override val columns: Collection<Column<T>>) :
override val rows: List<Row<T>> override val rows: List<Row<T>>
get() = (0 until rowsNum).map { VirtualRow(this, it) } get() = (0 until rowsNum).map { VirtualRow(this, it) }
override fun getValue(row: Int, column: String): T? = columns[column]?.get(row) override fun get(row: Int, column: String): T? = columns[column]?.get(row)
} }
internal class VirtualRow<T : Any>(val table: Table<T>, val index: Int) : Row<T> { internal class VirtualRow<T : Any>(val table: Table<T>, val index: Int) : Row<T> {
override fun getValue(column: String): T? = table.getValue(index, column) override fun get(column: String): T? = table.get(index, column)
// override fun <T : C> get(columnHeader: ColumnHeader<T>): T? { // override fun <T : C> get(columnHeader: ColumnHeader<T>): T? {
// return table.co[columnHeader][index] // return table.co[columnHeader][index]

View File

@ -1,12 +1,13 @@
package hep.dataforge.tables package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import kotlin.reflect.KClass import kotlin.reflect.KType
import kotlin.reflect.typeOf
public class ListColumn<T : Any>( public class ListColumn<T : Any>(
override val name: String, override val name: String,
private val data: List<T?>, private val data: List<T?>,
override val type: KClass<out T>, override val type: KType,
override val meta: Meta override val meta: Meta
) : Column<T> { ) : Column<T> {
override val size: Int get() = data.size override val size: Int get() = data.size
@ -18,7 +19,7 @@ public class ListColumn<T : Any>(
name: String, name: String,
def: ColumnScheme, def: ColumnScheme,
data: List<T?> data: List<T?>
): ListColumn<T> = ListColumn(name, data, T::class, def.toMeta()) ): ListColumn<T> = ListColumn(name, data, typeOf<T>(), def.toMeta())
public inline operator fun <reified T : Any> invoke( public inline operator fun <reified T : Any> invoke(
name: String, name: String,
@ -31,5 +32,5 @@ public class ListColumn<T : Any>(
public inline fun <T : Any, reified R : Any> Column<T>.map(meta: Meta = this.meta, noinline block: (T?) -> R): Column<R> { public inline fun <T : Any, reified R : Any> Column<T>.map(meta: Meta = this.meta, noinline block: (T?) -> R): Column<R> {
val data = List(size) { block(get(it)) } val data = List(size) { block(get(it)) }
return ListColumn(name, data, R::class, meta) return ListColumn(name, data, typeOf<R>(), meta)
} }

View File

@ -11,7 +11,7 @@ public class MutableColumnTable<C: Any>(public val size: Int) : Table<C> {
VirtualRow(this, it) VirtualRow(this, it)
} }
override fun getValue(row: Int, column: String): C? = columns[column]?.get(row) override fun get(row: Int, column: String): C? = columns[column]?.get(row)
/** /**
* Add a fixed column to the end of the table * Add a fixed column to the end of the table

View File

@ -1,27 +1,36 @@
package hep.dataforge.tables package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.invoke
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlin.reflect.KClass import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public class MutableTable<C : Any>( public class MutableTable<C : Any>(
override val rows: MutableList<Row<C>>, override val rows: MutableList<Row<C>>,
override val header: MutableList<ColumnHeader<C>> override val headers: MutableList<ColumnHeader<C>>,
) : RowTable<C>(rows, header) { ) : RowTable<C>(rows, headers) {
public fun <R : C> column(name: String, type: KClass<out R>, meta: Meta): ColumnHeader<R> { @PublishedApi
val column = SimpleColumnHeader(name, type, meta) internal fun <T : C> addColumn(name: String, type: KType, meta: Meta): ColumnHeader<T> {
header.add(column) val column = SimpleColumnHeader<T>(name, type, meta)
headers.add(column)
return column return column
} }
public inline fun <reified T : C> column( public inline fun <reified T : C> addColumn(
name: String, name: String,
noinline columnMetaBuilder: ColumnScheme.() -> Unit = {},
): ColumnHeader<T> = addColumn(name, typeOf<T>(), ColumnScheme(columnMetaBuilder).toMeta())
public inline fun <reified T : C> column(
noinline columnMetaBuilder: ColumnScheme.() -> Unit = {} noinline columnMetaBuilder: ColumnScheme.() -> Unit = {}
): ColumnHeader<T> { ): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ColumnHeader<T>>> =
return column(name, T::class, ColumnScheme(columnMetaBuilder).toMeta()) PropertyDelegateProvider { _, property ->
} val res = addColumn<T>(property.name, columnMetaBuilder)
ReadOnlyProperty { _, _ -> res }
}
public fun row(map: Map<String, C?>): Row<C> { public fun row(map: Map<String, C?>): Row<C> {
val row = MapRow(map) val row = MapRow(map)
@ -37,5 +46,5 @@ public fun MutableTable<Value>.row(vararg pairs: Pair<ColumnHeader<Value>, Any?>
row(pairs.associate { it.first.name to Value.of(it.second) }) row(pairs.associate { it.first.name to Value.of(it.second) })
public fun <C : Any> Table<C>.edit(block: MutableTable<C>.() -> Unit): Table<C> { public fun <C : Any> Table<C>.edit(block: MutableTable<C>.() -> Unit): Table<C> {
return MutableTable(rows.toMutableList(), header.toMutableList()).apply(block) return MutableTable(rows.toMutableList(), headers.toMutableList()).apply(block)
} }

View File

@ -2,25 +2,31 @@ package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import kotlin.reflect.KClass import kotlin.reflect.KType
public inline class MapRow<C : Any>(private val values: Map<String, C?>) : Row<C> { public inline class MapRow<C : Any>(private val values: Map<String, C?>) : Row<C> {
override fun getValue(column: String): C? = values[column] override fun get(column: String): C? = values[column]
} }
internal class RowTableColumn<C : Any, T : C>(val table: Table<C>, val header: ColumnHeader<T>) : Column<T> { internal class RowTableColumn<T : Any, R : T>(val table: Table<T>, val header: ColumnHeader<R>) : Column<R> {
init {
require(header in table.headers){"Header $header does not belong to $table"}
}
override val name: String get() = header.name override val name: String get() = header.name
override val type: KClass<out T> get() = header.type override val type: KType get() = header.type
override val meta: Meta get() = header.meta override val meta: Meta get() = header.meta
override val size: Int get() = table.rows.size override val size: Int get() = table.rows.size
override fun get(index: Int): T? = table.rows[index].getValue(name, type) @Suppress("UNCHECKED_CAST")
override fun get(index: Int): R? = table[index, name]?.let { it as R}
} }
public open class RowTable<C : Any>(override val rows: List<Row<C>>, override val header: List<ColumnHeader<C>>) : Table<C> { public open class RowTable<C : Any>(override val rows: List<Row<C>>, override val headers: List<ColumnHeader<C>>) :
override fun getValue(row: Int, column: String): C? = rows[row].getValue(column) Table<C> {
override fun get(row: Int, column: String): C? = rows[row].get(column)
override val columns: List<Column<C>> get() = header.map { RowTableColumn(this, it) } override val columns: List<Column<C>> get() = headers.map { RowTableColumn(this, it) }
} }
public suspend fun <C : Any> Rows<C>.collect(): Table<C> = this as? Table<C> ?: RowTable(rowFlow().toList(), header) public suspend fun <C : Any> Rows<C>.collect(): Table<C> = this as? Table<C> ?: RowTable(rowFlow().toList(), headers)

View File

@ -2,22 +2,20 @@ package hep.dataforge.tables
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.asFlow
import kotlin.reflect.KClass
import kotlin.reflect.cast
/** /**
* Finite or infinite row set. Rows are produced in a lazy suspendable [Flow]. * Finite or infinite row set. Rows are produced in a lazy suspendable [Flow].
* Each row must contain at least all the fields mentioned in [header]. * Each row must contain at least all the fields mentioned in [headers].
*/ */
public interface Rows<out T : Any> { public interface Rows<out T : Any> {
public val header: TableHeader<T> public val headers: TableHeader<T>
public fun rowFlow(): Flow<Row<T>> public fun rowFlow(): Flow<Row<T>>
} }
public interface Table<out T : Any> : Rows<T> { public interface Table<out T : Any> : Rows<T> {
public fun getValue(row: Int, column: String): T? public operator fun get(row: Int, column: String): T?
public val columns: Collection<Column<T>> public val columns: Collection<Column<T>>
override val header: TableHeader<T> get() = columns.toList() override val headers: TableHeader<T> get() = columns.toList()
public val rows: List<Row<T>> public val rows: List<Row<T>>
override fun rowFlow(): Flow<Row<T>> = rows.asFlow() override fun rowFlow(): Flow<Row<T>> = rows.asFlow()
@ -31,16 +29,13 @@ public interface Table<out T : Any> : Rows<T> {
} }
} }
public fun <C : Any, T : C> Table<C>.getValue(row: Int, column: String, type: KClass<out T>): T? =
type.cast(getValue(row, column))
public operator fun <T : Any> Collection<Column<T>>.get(name: String): Column<T>? = find { it.name == name } public operator fun <T : Any> Collection<Column<T>>.get(name: String): Column<T>? = find { it.name == name }
public inline operator fun <C : Any, reified T : C> Table<C>.get(row: Int, column: String): T? =
getValue(row, column, T::class)
public operator fun <C : Any, T : C> Table<C>.get(row: Int, column: ColumnHeader<T>): T? = public inline operator fun <T : Any, reified R : T> Table<T>.get(row: Int, column: ColumnHeader<R>): R? {
getValue(row, column.name, column.type) require(headers.contains(column)) { "Column $column is not in table headers" }
return get(row, column.name) as? R
}
public interface Column<out T : Any> : ColumnHeader<T> { public interface Column<out T : Any> : ColumnHeader<T> {
public val size: Int public val size: Int
@ -56,10 +51,7 @@ public operator fun <T : Any> Column<T>.iterator(): Iterator<T?> = iterator {
} }
public interface Row<out T : Any> { public interface Row<out T : Any> {
public fun getValue(column: String): T? public operator fun get(column: String): T?
} }
public fun <C : Any, T : C> Row<C>.getValue(column: String, type: KClass<out T>): T? = type.cast(getValue(column)) public inline operator fun <T : Any, reified R : T> Row<T>.get(column: ColumnHeader<R>): R? = get(column.name) as? R
public inline operator fun <reified T : Any> Row<T>.get(column: String): T? = T::class.cast(getValue(column))
public operator fun <C : Any, T : C> Row<C>.get(column: ColumnHeader<T>): T? = getValue(column.name, column.type)

View File

@ -1,17 +1,18 @@
package hep.dataforge.tables package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import kotlin.reflect.KClass import kotlin.reflect.KType
import kotlin.reflect.typeOf
/** /**
* A virtual column obtained by transforming Given row to a single value * A virtual column obtained by transforming Given row to a single value
*/ */
public class TransformationColumn<T : Any, R : Any>( public class TransformationColumn<T : Any, R : Any>(
public val table: Table<T>, public val table: Table<T>,
override val type: KClass<out R>, override val type: KType,
override val name: String, override val name: String,
override val meta: Meta, override val meta: Meta,
public val mapper: (Row<T>) -> R? public val mapper: (Row<T>) -> R?,
) : Column<R> { ) : Column<R> {
override val size: Int get() = table.rows.size override val size: Int get() = table.rows.size
@ -25,10 +26,10 @@ public class TransformationColumn<T : Any, R : Any>(
*/ */
public class CachedTransformationColumn<T : Any, R : Any>( public class CachedTransformationColumn<T : Any, R : Any>(
public val table: Table<T>, public val table: Table<T>,
override val type: KClass<out R>, override val type: KType,
override val name: String, override val name: String,
override val meta: Meta, override val meta: Meta,
public val mapper: (Row<T>) -> R? public val mapper: (Row<T>) -> R?,
) : Column<R> { ) : Column<R> {
override val size: Int get() = table.rows.size override val size: Int get() = table.rows.size
private val values: HashMap<Int, R?> = HashMap() private val values: HashMap<Int, R?> = HashMap()
@ -42,14 +43,18 @@ public inline fun <T : Any, reified R : Any> Table<T>.mapRows(
name: String, name: String,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
cache: Boolean = false, cache: Boolean = false,
noinline mapper: (Row<T>) -> R? noinline mapper: (Row<T>) -> R?,
): Column<R> = if (cache) { ): Column<R> = if (cache) {
CachedTransformationColumn(this, R::class, name, meta, mapper) CachedTransformationColumn(this, typeOf<R>(), name, meta, mapper)
} else { } else {
TransformationColumn(this, R::class, name, meta, mapper) TransformationColumn(this, typeOf<R>(), name, meta, mapper)
} }
public fun <T : Any> Table<T>.mapRowsToDouble(name: String, meta: Meta = Meta.EMPTY, block: (Row<T>) -> Double): RealColumn { public fun <T : Any> Table<T>.mapRowsToDouble(
name: String,
meta: Meta = Meta.EMPTY,
block: (Row<T>) -> Double,
): RealColumn {
val data = DoubleArray(rows.size) { block(rows[it]) } val data = DoubleArray(rows.size) { block(rows[it]) }
return RealColumn(name, data, meta) return RealColumn(name, data, meta)
} }

View File

@ -32,7 +32,7 @@ private fun readLine(header: ValueTableHeader, line: String): Row<Value> {
* Finite or infinite [Rows] created from a fixed width text binary * Finite or infinite [Rows] created from a fixed width text binary
*/ */
@ExperimentalIoApi @ExperimentalIoApi
public class TextRows(override val header: ValueTableHeader, private val binary: Binary) : Rows<Value> { public class TextRows(override val headers: ValueTableHeader, private val binary: Binary) : Rows<Value> {
/** /**
* A flow of indexes of string start offsets ignoring empty strings * A flow of indexes of string start offsets ignoring empty strings
@ -52,7 +52,7 @@ public class TextRows(override val header: ValueTableHeader, private val binary:
flow { flow {
forEachUtf8Line { line -> forEachUtf8Line { line ->
if (line.isNotBlank()) { if (line.isNotBlank()) {
val row = readLine(header, line) val row = readLine(headers, line)
emit(row) emit(row)
} }
} }
@ -73,25 +73,25 @@ public suspend fun TextRows.buildRowIndex(): List<Int> = indexFlow().toList()
*/ */
@ExperimentalIoApi @ExperimentalIoApi
public class TextTable( public class TextTable(
override val header: ValueTableHeader, override val headers: ValueTableHeader,
private val binary: Binary, private val binary: Binary,
public val index: List<Int> public val index: List<Int>
) : Table<Value> { ) : Table<Value> {
override val columns: Collection<Column<Value>> get() = header.map { RowTableColumn(this, it) } override val columns: Collection<Column<Value>> get() = headers.map { RowTableColumn(this, it) }
override val rows: List<Row<Value>> get() = index.map { readAt(it) } override val rows: List<Row<Value>> get() = index.map { readAt(it) }
override fun rowFlow(): Flow<Row<Value>> = TextRows(header, binary).rowFlow() override fun rowFlow(): Flow<Row<Value>> = TextRows(headers, binary).rowFlow()
private fun readAt(offset: Int): Row<Value> { private fun readAt(offset: Int): Row<Value> {
return binary.read(offset) { return binary.read(offset) {
val line = readUtf8Line() val line = readUtf8Line()
return@read readLine(header, line) return@read readLine(headers, line)
} }
} }
override fun getValue(row: Int, column: String): Value? { override fun get(row: Int, column: String): Value? {
val offset = index[row] val offset = index[row]
return readAt(offset)[column] return readAt(offset)[column]
} }
@ -132,11 +132,11 @@ private fun Output.writeValue(value: Value, width: Int, left: Boolean = true) {
* Write rows without header to the output * Write rows without header to the output
*/ */
public suspend fun Output.writeRows(rows: Rows<Value>) { public suspend fun Output.writeRows(rows: Rows<Value>) {
val widths: List<Int> = rows.header.map { val widths: List<Int> = rows.headers.map {
it.textWidth it.textWidth
} }
rows.rowFlow().collect { row -> rows.rowFlow().collect { row ->
rows.header.forEachIndexed { index, columnHeader -> rows.headers.forEachIndexed { index, columnHeader ->
writeValue(row[columnHeader] ?: Null, widths[index]) writeValue(row[columnHeader] ?: Null, widths[index])
} }
writeUtf8String("\r\n") writeUtf8String("\r\n")

View File

@ -10,12 +10,13 @@ import kotlinx.io.Binary
import kotlinx.io.ByteArrayOutput import kotlinx.io.ByteArrayOutput
import kotlinx.io.ExperimentalIoApi import kotlinx.io.ExperimentalIoApi
import kotlinx.io.asBinary import kotlinx.io.asBinary
import kotlin.reflect.typeOf
@ExperimentalIoApi @ExperimentalIoApi
public suspend fun Table<Value>.wrap(): Envelope = Envelope { public suspend fun Table<Value>.toEnvelope(): Envelope = Envelope {
meta { meta {
header.forEachIndexed { index, columnHeader -> headers.forEachIndexed { index, columnHeader ->
set("column", index.toString(), Meta { set("column", index.toString(), Meta {
"name" put columnHeader.name "name" put columnHeader.name
if (!columnHeader.meta.isEmpty()) { if (!columnHeader.meta.isEmpty()) {
@ -26,9 +27,9 @@ public suspend fun Table<Value>.wrap(): Envelope = Envelope {
} }
type = "table.value" type = "table.value"
dataID = "valueTable[${this@wrap.hashCode()}]" dataID = "valueTable[${this@toEnvelope.hashCode()}]"
data = ByteArrayOutput().apply { writeRows(this@wrap) }.toByteArray().asBinary() data = ByteArrayOutput().apply { writeRows(this@toEnvelope) }.toByteArray().asBinary()
} }
@DFExperimental @DFExperimental
@ -37,7 +38,7 @@ public fun TextRows.Companion.readEnvelope(envelope: Envelope): TextRows {
val header = envelope.meta.getIndexed("column") val header = envelope.meta.getIndexed("column")
.entries.sortedBy { it.key?.toInt() } .entries.sortedBy { it.key?.toInt() }
.map { (_, item) -> .map { (_, item) ->
SimpleColumnHeader(item.node["name"].string!!, Value::class, item.node["meta"].node ?: Meta.EMPTY) SimpleColumnHeader<Value>(item.node["name"].string!!, typeOf<Value>(), item.node["meta"].node ?: Meta.EMPTY)
} }
return TextRows(header, envelope.data ?: Binary.EMPTY) return TextRows(header, envelope.data ?: Binary.EMPTY)
} }

View File

@ -1,8 +1,8 @@
package hep.dataforge.tables package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.invoke import kotlin.reflect.KType
import kotlin.reflect.KClass import kotlin.reflect.typeOf
public class RealColumn( public class RealColumn(
@ -10,7 +10,7 @@ public class RealColumn(
public val data: DoubleArray, public val data: DoubleArray,
override val meta: Meta = Meta.EMPTY override val meta: Meta = Meta.EMPTY
) : Column<Double> { ) : Column<Double> {
override val type: KClass<out Double> get() = Double::class override val type: KType get() = typeOf<Double>()
override val size: Int get() = data.size override val size: Int get() = data.size
@ -49,7 +49,7 @@ public class IntColumn(
public val data: IntArray, public val data: IntArray,
override val meta: Meta = Meta.EMPTY override val meta: Meta = Meta.EMPTY
) : Column<Int> { ) : Column<Int> {
override val type: KClass<out Int> get() = Int::class override val type: KType get() = typeOf<Int>()
override val size: Int get() = data.size override val size: Int get() = data.size

View File

@ -2,30 +2,31 @@ package hep.dataforge.tables
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.KType
import kotlin.reflect.safeCast import kotlin.reflect.full.isSubtypeOf
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public fun <T : Any> Column<*>.cast(type: KClass<out T>): Column<T> { public fun <T : Any> Column<*>.cast(type: KType): Column<T> {
return if (type.isSubclassOf(this.type)) { return if (type.isSubtypeOf(this.type)) {
this as Column<T> this as Column<T>
} else { } else {
CastColumn(this, type) CastColumn(this, type)
} }
} }
public class CastColumn<T : Any>(private val origin: Column<*>, override val type: KClass<out T>) : Column<T> { private class CastColumn<T : Any>(private val origin: Column<*>, override val type: KType) : Column<T> {
override val name: String get() = origin.name override val name: String get() = origin.name
override val meta: Meta get() = origin.meta override val meta: Meta get() = origin.meta
override val size: Int get() = origin.size override val size: Int get() = origin.size
@Suppress("UNCHECKED_CAST")
override fun get(index: Int): T? = type.safeCast(origin[index]) override fun get(index: Int): T? = origin[index]?.let {
it as T
}
} }
public class ColumnProperty<C: Any, T : C>(public val table: Table<C>, public val type: KClass<T>) : ReadOnlyProperty<Any?, Column<T>> { public class ColumnProperty<C: Any, T : C>(public val table: Table<C>, public val type: KType) : ReadOnlyProperty<Any?, Column<T>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Column<T> { override fun getValue(thisRef: Any?, property: KProperty<*>): Column<T> {
val name = property.name val name = property.name
return (table.columns[name] ?: error("Column with name $name not found in the table")).cast(type) return (table.columns[name] ?: error("Column with name $name not found in the table")).cast(type)

View File

@ -2,7 +2,6 @@ package hep.dataforge.tables.io
import hep.dataforge.misc.DFExperimental import hep.dataforge.misc.DFExperimental
import hep.dataforge.tables.Table import hep.dataforge.tables.Table
import hep.dataforge.tables.get
import hep.dataforge.tables.row import hep.dataforge.tables.row
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.values.int import hep.dataforge.values.int
@ -19,22 +18,20 @@ import kotlin.test.assertEquals
@ExperimentalIoApi @ExperimentalIoApi
class TextRowsTest { class TextRowsTest {
val table = Table<Value> { val table = Table<Value> {
val a = column<Value>("a") val a by column<Value>()
val b = column<Value>("b") val b by column<Value>()
row(a to 1, b to "b1") row(a to 1, b to "b1")
row(a to 2, b to "b2") row(a to 2, b to "b2")
} }
@Test @Test
fun testTableWriteRead() { fun testTableWriteRead() = runBlocking {
runBlocking { val envelope = table.toEnvelope()
val envelope = table.wrap() val string = envelope.data!!.toByteArray().decodeToString()
val string = envelope.data!!.toByteArray().decodeToString() println(string)
println(string) val table = TextRows.readEnvelope(envelope)
val table = TextRows.readEnvelope(envelope) val rows = table.rowFlow().toList()
val rows = table.rowFlow().toList() assertEquals(1, rows[0]["a"]?.int)
assertEquals(1, rows[0]["a"]?.int) assertEquals("b2", rows[1]["b"]?.string)
assertEquals("b2", rows[1]["b"]?.string)
}
} }
} }

View File

@ -1,6 +1,6 @@
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.gradle.native")
} }
kotlin { kotlin {

View File

@ -1,9 +1,11 @@
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
//kotlin.native.enableDependencyPropagation=false
kotlin.mpp.stability.nowarn=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
org.gradle.parallel=true org.gradle.parallel=true
systemProp.org.gradle.internal.publish.checksums.insecure=true
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.stability.nowarn=true
bintrayPublish=true

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -1,6 +1,6 @@
pluginManagement { pluginManagement {
repositories { repositories {
mavenLocal() maven("https://repo.kotlin.link")
jcenter() jcenter()
gradlePluginPortal() gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-eap")
@ -10,15 +10,15 @@ pluginManagement {
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
val toolsVersion = "0.7.6" val toolsVersion = "0.8.3"
val kotlinVersion = "1.4.30" val kotlinVersion = "1.4.30"
plugins { plugins {
id("ru.mipt.npm.project") version toolsVersion id("ru.mipt.npm.gradle.project") version toolsVersion
id("ru.mipt.npm.mpp") version toolsVersion id("ru.mipt.npm.gradle.mpp") version toolsVersion
id("ru.mipt.npm.jvm") version toolsVersion id("ru.mipt.npm.gradle.jvm") version toolsVersion
id("ru.mipt.npm.js") version toolsVersion id("ru.mipt.npm.gradle.js") version toolsVersion
id("ru.mipt.npm.publish") version toolsVersion id("ru.mipt.npm.gradle.publish") version toolsVersion
kotlin("jvm") version kotlinVersion kotlin("jvm") version kotlinVersion
kotlin("js") version kotlinVersion kotlin("js") version kotlinVersion
} }