Tables refactor to KType
This commit is contained in:
parent
cf0c934acf
commit
488cd5a939
@ -4,6 +4,7 @@
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- Kotlin-logging moved from common to JVM and JS. Replaced by console for native.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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{
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.mpp")
|
id("ru.mipt.npm.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
@ -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"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
@ -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>
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
@ -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)
|
||||||
}
|
}
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
@ -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)
|
@ -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)
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
}
|
}
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 {
|
||||||
|
@ -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
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user