All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ai.platon.pulsar.common.OpenMapTable.kt Maven / Gradle / Ivy

package ai.platon.pulsar.common

import kotlin.reflect.KProperty

/**
 * A simple excel like table, every column, every row and every cell can hold metadata and variables
 * */
class OpenMapTable(
        val numColumns: Int,
        val ident: Int = -1
) {
    /**
     * The metadata for columns.
     * */
    val metadata = Metadata(numColumns, ident)
    /**
     * The underlying rows, each row is associated with a key.
     * */
    val map = mutableMapOf()
    
    /**
     * The attributes.
     * */
    val attributes = mutableMapOf()
    /**
     * The column collection.
     * */
    val columns get() = metadata.columns
    /**
     * The row collection.
     * */
    val rows get() = map.values
    
    val keys: Set get() = map.keys
    val numRows: Int get() = map.size
    val isEmpty: Boolean get() = numRows == 0
    val isNotEmpty: Boolean get() = !isEmpty

    /**
     * Get the row associated with [key].
     * */
    operator fun get(key: String) = map[key]

    /**
     * Associated a [row] with [key].
     * */
    operator fun set(key: String, row: Row) {
        map[key] = row
    }

    fun computeIfAbsent(key: String) = map.computeIfAbsent(key) { Row(key, numColumns) }

    fun computeIfAbsent(key: String, init: (Row) -> Unit) = map.computeIfAbsent(key) { Row(key, numColumns, init) }

    fun count(predicate: (Row) -> Boolean) = rows.count(predicate)

    class Metadata(val columns: Array) {

        constructor(numColumns: Int, tableId: Int = -1): this(
            IntRange(1, numColumns).map { i -> Column(if (tableId < 0) "C$i" else "T${tableId}C$i") }.toTypedArray()
        )

        operator fun get(j: Int): Column {
            return columns[j]
        }

        operator fun set(j: Int, column: Column) {
            columns[j] = column
        }

        fun attributeRow(key: String): List {
            return columns.map { it.attributes[key] }
        }
    }

    class Column(
            var name: String = "",
            var description: String = "",
            val attributes: MutableMap = mutableMapOf()
    )

    class Cell(var j: Int = 0, var value: Any? = null) {
        val attributes: MutableMap = mutableMapOf()
        override fun toString() = value?.toString()?:""
    }

    class Row(var key: String = "", numColumns: Int) {
        constructor(key: String, numColumns: Int, init: (Row) -> Unit): this(key, numColumns) {
            init(this)
        }

        val cells: Array = arrayOfNulls(numColumns)
        val attributes: MutableMap = mutableMapOf()
        val values get() = cells.map { it?.value }

        /**
         * Get the cell of the j-th column, 0 based
         * */
        operator fun get(j: Int) = cells[j]

        /**
         * Set the cell of the j-th column, 0 based
         * */
        operator fun set(j: Int, cell: Cell) {
            require(j < cells.size) { "Cell index out of boundary, total size ${cells.size}, index $j" }
            require(j == cell.j) { "Cell index not match, required $j actual ${cell.j}" }
            cells[j] = cell
        }

        /**
         * Get the cell value of the j-th column, 0 based
         * */
        fun getValue(j: Int) = cells[j]?.value

        /**
         * Set the cell value of the j-th column, 0 based
         * */
        fun setValue(j: Int, value: Any?) {
            require(j < cells.size)
            cells[j] = Cell(j, value)
        }
    }

    companion object {
        @Deprecated("Use EMPTY instead", ReplaceWith("EMPTY"))
        val empty = OpenMapTable(0)
        val EMPTY = OpenMapTable(0)
    }
}

class TableAttribute(val initializer: (OpenMapTable) -> T) {
    operator fun getValue(thisRef: OpenMapTable, property: KProperty<*>): T =
            thisRef.attributes[property.name] as? T ?: setValue(thisRef, property, initializer(thisRef))

    operator fun setValue(thisRef: OpenMapTable, property: KProperty<*>, value: T): T {
        thisRef.attributes[property.name] = value
        return value
    }
}

class ColumnAttribute(val initializer: (OpenMapTable.Column) -> T) {
    operator fun getValue(thisRef: OpenMapTable.Column, property: KProperty<*>): T =
            thisRef.attributes[property.name] as? T ?: setValue(thisRef, property, initializer(thisRef))

    operator fun setValue(thisRef: OpenMapTable.Column, property: KProperty<*>, value: T): T {
        thisRef.attributes[property.name] = value
        return value
    }
}

class RowAttribute(val initializer: (OpenMapTable.Row) -> T) {
    operator fun getValue(thisRef: OpenMapTable.Row, property: KProperty<*>): T =
            thisRef.attributes[property.name] as? T ?: setValue(thisRef, property, initializer(thisRef))

    operator fun setValue(thisRef: OpenMapTable.Row, property: KProperty<*>, value: T): T {
        thisRef.attributes[property.name] = value
        return value
    }
}

class CellAttribute(val initializer: (OpenMapTable.Cell) -> T) {
    operator fun getValue(thisRef: OpenMapTable.Cell, property: KProperty<*>): T =
            thisRef.attributes[property.name] as? T ?: setValue(thisRef, property, initializer(thisRef))

    operator fun setValue(thisRef: OpenMapTable.Cell, property: KProperty<*>, value: T): T {
        thisRef.attributes[property.name] = value
        return value
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy