diff --git a/gradle.properties b/gradle.properties index 4d5bbc6..e427997 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ kotlin.code.style=official specifyKotlinAsDependency=false projectGroup=ru.dbotthepony.kommons -projectVersion=2.17.2 +projectVersion=2.18.0 guavaDepVersion=33.0.0 gsonDepVersion=2.8.9 diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Boolean2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Boolean2DArray.kt index a0346d5..a7b53d7 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Boolean2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Boolean2DArray.kt @@ -44,9 +44,15 @@ abstract class Boolean2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: BitSet, ) : Boolean2DArray() { - private val mem = BitSet(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, BitSet(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.clone() as BitSet) override fun get(column: Int, row: Int): Boolean { if (column !in 0 until columns || row !in 0 until rows) @@ -74,12 +80,16 @@ abstract class Boolean2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.hashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Boolean2DArray" + super.toString() } } - private class View(private val parent: Boolean2DArray) : Boolean2DArray() { + private class View(val parent: Boolean2DArray) : Boolean2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -120,6 +130,31 @@ abstract class Boolean2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Boolean2DArray): Boolean2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Boolean2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Byte2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Byte2DArray.kt index de48e0c..1d58ab6 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Byte2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Byte2DArray.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.kommons.arrays import java.nio.ByteBuffer +import java.util.* abstract class Byte2DArray : Array2D() { abstract operator fun get(column: Int, row: Int): Byte @@ -43,9 +44,15 @@ abstract class Byte2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: ByteArray, ) : Byte2DArray() { - private val mem = ByteArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, ByteArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Byte { if (column !in 0 until columns || row !in 0 until rows) @@ -70,12 +77,16 @@ abstract class Byte2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Byte2DArray" + super.toString() } } - private class View(private val parent: Byte2DArray) : Byte2DArray() { + private class View(val parent: Byte2DArray) : Byte2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -116,6 +127,31 @@ abstract class Byte2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Byte2DArray): Byte2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Byte2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Char2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Char2DArray.kt index 8937f06..1e30fbe 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Char2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Char2DArray.kt @@ -48,9 +48,15 @@ abstract class Char2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: CharArray, ) : Char2DArray() { - private val mem = CharArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, CharArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Char { if (column !in 0 until columns || row !in 0 until rows) @@ -75,12 +81,16 @@ abstract class Char2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Char2DArray" + super.toString() } } - private class View(private val parent: Char2DArray) : Char2DArray() { + private class View(val parent: Char2DArray) : Char2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -121,6 +131,31 @@ abstract class Char2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Char2DArray): Char2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Char2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Double2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Double2DArray.kt index 536eb4c..76cc87d 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Double2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Double2DArray.kt @@ -95,9 +95,15 @@ abstract class Double2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: DoubleArray ) : Double2DArray() { - private val mem = DoubleArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, DoubleArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Double { if (column !in 0 until columns || row !in 0 until rows) @@ -122,12 +128,16 @@ abstract class Double2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Double2DArray" + super.toString() } } - private class View(private val parent: Double2DArray) : Double2DArray() { + private class View(val parent: Double2DArray) : Double2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -168,6 +178,31 @@ abstract class Double2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Double2DArray): Double2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Double2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Float2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Float2DArray.kt index 7a95cbc..df250ba 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Float2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Float2DArray.kt @@ -96,9 +96,15 @@ abstract class Float2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: FloatArray ) : Float2DArray() { - private val mem = FloatArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, FloatArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Float { if (column !in 0 until columns || row !in 0 until rows) @@ -123,12 +129,16 @@ abstract class Float2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Float2DArray" + super.toString() } } - private class View(private val parent: Float2DArray) : Float2DArray() { + private class View(val parent: Float2DArray) : Float2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -169,6 +179,31 @@ abstract class Float2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Float2DArray): Float2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Float2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Int2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Int2DArray.kt index 1d076d1..370f89f 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Int2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Int2DArray.kt @@ -95,9 +95,15 @@ abstract class Int2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: IntArray ) : Int2DArray() { - private val mem = IntArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, IntArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Int { if (column !in 0 until columns || row !in 0 until rows) @@ -122,12 +128,16 @@ abstract class Int2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Int2DArray" + super.toString() } } - private class View(private val parent: Int2DArray) : Int2DArray() { + private class View(val parent: Int2DArray) : Int2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -168,6 +178,31 @@ abstract class Int2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Int2DArray): Int2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Int2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Long2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Long2DArray.kt index 6b289f3..ad4dcd5 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Long2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Long2DArray.kt @@ -95,9 +95,15 @@ abstract class Long2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: LongArray ) : Long2DArray() { - private val mem = LongArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, LongArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Long { if (column !in 0 until columns || row !in 0 until rows) @@ -122,12 +128,16 @@ abstract class Long2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Long2DArray" + super.toString() } } - private class View(private val parent: Long2DArray) : Long2DArray() { + private class View(val parent: Long2DArray) : Long2DArray() { override val rows: Int get() = parent.rows override val columns: Int @@ -168,6 +178,31 @@ abstract class Long2DArray : Array2D() { return View(parent) } + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Long2DArray): Long2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Long2DArray = Impl(0, 0) } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Object2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Object2DArray.kt index 0db267a..d43d86d 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Object2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Object2DArray.kt @@ -46,7 +46,7 @@ class Object2DArray private constructor( constructor( parent: Object2DArray - ) : this(parent.columns, parent.rows, Array(parent.size) { parent.mem[it] }) + ) : this(parent.columns, parent.rows, parent.mem.copyOf()) init { require(columns >= 0 && rows >= 0) { "Invalid dimensions: $columns x $rows" } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Short2DArray.kt b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Short2DArray.kt index 5fcbd79..0942796 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/arrays/Short2DArray.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/arrays/Short2DArray.kt @@ -48,9 +48,15 @@ abstract class Short2DArray : Array2D() { private class Impl( override val columns: Int, - override val rows: Int + override val rows: Int, + private val mem: ShortArray ) : Short2DArray() { - private val mem = ShortArray(columns * rows) + constructor( + columns: Int, + rows: Int, + ) : this(columns, rows, ShortArray(columns * rows)) + + constructor(other: Impl) : this(other.columns, other.rows, other.mem.copyOf()) override fun get(column: Int, row: Int): Short { if (column !in 0 until columns || row !in 0 until rows) @@ -75,17 +81,81 @@ abstract class Short2DArray : Array2D() { return super.equals(other) } + override fun hashCode(): Int { + return mem.contentHashCode().rotateLeft(13) + columns * 31 + rows * 31 * 31 + } + override fun toString(): String { return "Short2DArray" + super.toString() } } + private class View(val parent: Short2DArray) : Short2DArray() { + override val rows: Int + get() = parent.rows + override val columns: Int + get() = parent.columns + + override fun get(column: Int, row: Int): Short { + return parent[column, row] + } + + override fun set(column: Int, row: Int, value: Short) { + throw UnsupportedOperationException("Read only view") + } + + override fun equals(other: Any?): Boolean { + return other is View && parent == other.parent + } + + override fun hashCode(): Int { + return parent.hashCode() + } + + override fun toString(): String { + return "View = $parent" + } + } + companion object { @JvmStatic fun allocate(columns: Int, rows: Int): Short2DArray { return Impl(columns, rows) } + @JvmStatic + fun unmodifiable(parent: Short2DArray): Short2DArray { + if (parent is View) + return parent + else + return View(parent) + } + + /** + * Copies specified 2D array. + * + * This method may be more efficient than doing it manually, + * and semantically is equivalent to next code: + * + * ```kotlin + * val result = allocate(value.columns, value.rows) + * result.load(value) + * return result + * ``` + */ + @JvmStatic + fun copy(value: Short2DArray): Short2DArray { + if (value is View) { + return copy(value.parent) + } else if (value is Impl) { + return Impl(value) + } else { + val result = Impl(value.columns, value.rows) + result.load(value) + return result + } + } + @JvmField val ZERO: Short2DArray = Impl(0, 0) }