package ru.dbotthepony.kstarbound.util import it.unimi.dsi.fastutil.objects.ObjectSpliterators import java.util.Arrays import java.util.stream.Stream import java.util.stream.StreamSupport import kotlin.reflect.KClass class TwoDimensionalArray(clazz: KClass, private val width: Int, private val height: Int) { data class Entry( val x: Int, val y: Int, val value: T, ) private val memory: Array = java.lang.reflect.Array.newInstance(clazz.java, width * height) as Array fun isOutside(x: Int, y: Int): Boolean { return (x !in 0 until width) || (y !in 0 until height) } operator fun get(x: Int, y: Int): T? { if (x !in 0 until width) { throw IndexOutOfBoundsException("X $x is out of bounds between 0 and $width") } if (y !in 0 until height) { throw IndexOutOfBoundsException("Y $y is out of bounds between 0 and $height") } return memory[x + y * width] } operator fun set(x: Int, y: Int, value: T?): T? { if (x !in 0 until width) { throw IndexOutOfBoundsException("X $x is out of bounds between 0 and $width") } if (y !in 0 until height) { throw IndexOutOfBoundsException("Y $y is out of bounds between 0 and $height") } val old = memory[x + y * width] memory[x + y * width] = value return old } fun stream(): Stream { return Arrays.stream(memory) } fun indexedStream(): Stream> { return StreamSupport.stream(IndexedArraySpliterator(memory), false).map { val x = it.index % width val y = (it.index - x) / width Entry(x, y, it.value) } } } inline fun TwoDimensionalArray(width: Int, height: Int) = TwoDimensionalArray(T::class, width, height)