mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
memoised dynamic luminosity
This commit is contained in:
@@ -7,6 +7,7 @@ import net.torvald.terrarum.gameworld.FluidType
|
|||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.utils.CSVFetcher
|
import net.torvald.terrarum.utils.CSVFetcher
|
||||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||||
|
import net.torvald.util.SortedArrayList
|
||||||
import org.apache.commons.csv.CSVRecord
|
import org.apache.commons.csv.CSVRecord
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@@ -17,6 +18,8 @@ object BlockCodex {
|
|||||||
|
|
||||||
private var blockProps = HashMap<Int, BlockProp>()
|
private var blockProps = HashMap<Int, BlockProp>()
|
||||||
|
|
||||||
|
val dynamicLights = SortedArrayList<Int>()
|
||||||
|
|
||||||
/** 4096 */
|
/** 4096 */
|
||||||
const val MAX_TERRAIN_TILES = GameWorld.TILES_SUPPORTED
|
const val MAX_TERRAIN_TILES = GameWorld.TILES_SUPPORTED
|
||||||
|
|
||||||
@@ -45,6 +48,10 @@ object BlockCodex {
|
|||||||
val id = intVal(it, "id")
|
val id = intVal(it, "id")
|
||||||
setProp(id, it)
|
setProp(id, it)
|
||||||
|
|
||||||
|
if ((blockProps[id]?.dynamicLuminosityFunction ?: 0) != 0) {
|
||||||
|
dynamicLights.add(id)
|
||||||
|
}
|
||||||
|
|
||||||
if (id > highestNumber)
|
if (id > highestNumber)
|
||||||
highestNumber = id
|
highestNumber = id
|
||||||
}
|
}
|
||||||
@@ -113,11 +120,11 @@ object BlockCodex {
|
|||||||
prop.strength = intVal(record, "str")
|
prop.strength = intVal(record, "str")
|
||||||
prop.density = intVal(record, "dsty")
|
prop.density = intVal(record, "dsty")
|
||||||
|
|
||||||
prop.lumColR = floatVal(record, "lumr") / LightmapRenderer.MUL_FLOAT
|
prop.baseLumColR = floatVal(record, "lumr") / LightmapRenderer.MUL_FLOAT
|
||||||
prop.lumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
|
prop.baseLumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
|
||||||
prop.lumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
prop.baseLumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
||||||
prop.lumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT
|
prop.baseLumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT
|
||||||
prop.internalLumCol = Cvec(prop.lumColR, prop.lumColG, prop.lumColB, prop.lumColA)
|
prop.baseLumCol.set(prop.baseLumColR, prop.baseLumColG, prop.baseLumColB, prop.baseLumColA)
|
||||||
|
|
||||||
prop.friction = intVal(record, "fr")
|
prop.friction = intVal(record, "fr")
|
||||||
prop.viscosity = intVal(record, "vscs")
|
prop.viscosity = intVal(record, "vscs")
|
||||||
|
|||||||
@@ -44,27 +44,24 @@ class BlockProp {
|
|||||||
|
|
||||||
|
|
||||||
/** 1.0f for 1023, 0.25f for 255 */
|
/** 1.0f for 1023, 0.25f for 255 */
|
||||||
var lumColR = 0f
|
internal var baseLumColR = 0f // base value used to calculate dynamic luminosity
|
||||||
var lumColG = 0f
|
internal var baseLumColG = 0f // base value used to calculate dynamic luminosity
|
||||||
var lumColB = 0f
|
internal var baseLumColB = 0f // base value used to calculate dynamic luminosity
|
||||||
var lumColA = 0f
|
internal var baseLumColA = 0f // base value used to calculate dynamic luminosity
|
||||||
lateinit var internalLumCol: Cvec
|
internal val baseLumCol = Cvec(0)
|
||||||
|
var lumColR = 0f // memoised value of dynamic luminosity
|
||||||
|
var lumColG = 0f // memoised value of dynamic luminosity
|
||||||
|
var lumColB = 0f // memoised value of dynamic luminosity
|
||||||
|
var lumColA = 0f // memoised value of dynamic luminosity
|
||||||
|
var lumCol = Cvec(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param luminosity
|
* @param luminosity
|
||||||
*/
|
*/
|
||||||
inline val luminosity: Cvec
|
//inline val luminosity: Cvec
|
||||||
get() = BlockPropUtil.getDynamicLumFunc(internalLumCol, dynamicLuminosityFunction)
|
// get() = BlockPropUtil.getDynamicLumFunc(internalLumCol, dynamicLuminosityFunction)
|
||||||
|
|
||||||
fun getLum(channel: Int) = BlockPropUtil.getDynamicLumFuncByChan(
|
fun getLum(channel: Int) = lumCol.getElem(channel)
|
||||||
when (channel) {
|
|
||||||
0 -> lumColR
|
|
||||||
1 -> lumColG
|
|
||||||
2 -> lumColB
|
|
||||||
3 -> lumColA
|
|
||||||
else -> throw IllegalArgumentException("Invalid channel $channel")
|
|
||||||
}, dynamicLuminosityFunction, channel
|
|
||||||
)
|
|
||||||
|
|
||||||
var drop: Int = 0
|
var drop: Int = 0
|
||||||
|
|
||||||
|
|||||||
@@ -86,13 +86,28 @@ object BlockPropUtil {
|
|||||||
|
|
||||||
// pulsate-related vars
|
// pulsate-related vars
|
||||||
if (pulsateFuncX > pulsateCycleDuration) pulsateFuncX -= pulsateCycleDuration
|
if (pulsateFuncX > pulsateCycleDuration) pulsateFuncX -= pulsateCycleDuration
|
||||||
|
|
||||||
|
// update the memoised values in props
|
||||||
|
for (key in BlockCodex.dynamicLights) {
|
||||||
|
try {
|
||||||
|
val prop = BlockCodex[key]
|
||||||
|
if (prop.dynamicLuminosityFunction != 0) {
|
||||||
|
prop.lumCol.set(getDynamicLumFunc(prop.baseLumCol, prop.dynamicLuminosityFunction))
|
||||||
|
prop.lumColR = prop.lumCol.r
|
||||||
|
prop.lumColG = prop.lumCol.g
|
||||||
|
prop.lumColB = prop.lumCol.b
|
||||||
|
prop.lumColA = prop.lumCol.a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (skip: NullPointerException) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNewRandom() = random.nextFloat().times(2).minus(1f) * flickerFuncRange
|
private fun getNewRandom() = random.nextFloat().times(2).minus(1f) * flickerFuncRange
|
||||||
|
|
||||||
private fun linearInterpolation1D(a: Float, b: Float, x: Float) = a * (1 - x) + b * x
|
private fun linearInterpolation1D(a: Float, b: Float, x: Float) = a * (1 - x) + b * x
|
||||||
|
|
||||||
fun getDynamicLumFunc(baseLum: Cvec, type: Int): Cvec {
|
private fun getDynamicLumFunc(baseLum: Cvec, type: Int): Cvec {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
1 -> getTorchFlicker(baseLum)
|
1 -> getTorchFlicker(baseLum)
|
||||||
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light
|
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light
|
||||||
@@ -106,7 +121,7 @@ object BlockPropUtil {
|
|||||||
/**
|
/**
|
||||||
* @param chan 0 for R, 1 for G, 2 for B, 3 for A
|
* @param chan 0 for R, 1 for G, 2 for B, 3 for A
|
||||||
*/
|
*/
|
||||||
fun getDynamicLumFuncByChan(baseLum: Float, type: Int, chan: Int): Float {
|
private fun getDynamicLumFuncByChan(baseLum: Float, type: Int, chan: Int): Float {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
1 -> getTorchFlicker(baseLum)
|
1 -> getTorchFlicker(baseLum)
|
||||||
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT).getElem(chan) // current global light
|
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT).getElem(chan) // current global light
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import java.util.*
|
|||||||
internal class FixtureTikiTorch : FixtureBase(BlockBox(BlockBox.NO_COLLISION, 1, 2)), Luminous {
|
internal class FixtureTikiTorch : FixtureBase(BlockBox(BlockBox.NO_COLLISION, 1, 2)), Luminous {
|
||||||
|
|
||||||
override var color: Cvec
|
override var color: Cvec
|
||||||
get() = BlockCodex[Block.TORCH].luminosity
|
get() = BlockCodex[Block.TORCH].lumCol
|
||||||
set(value) {
|
set(value) {
|
||||||
throw UnsupportedOperationException()
|
throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/net/torvald/terrarum/tests/SortedArrayListTest.kt
Normal file
15
src/net/torvald/terrarum/tests/SortedArrayListTest.kt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package net.torvald.terrarum.tests
|
||||||
|
|
||||||
|
import net.torvald.util.SortedArrayList
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val t = SortedArrayList<Int>()
|
||||||
|
|
||||||
|
t.add(5)
|
||||||
|
t.add(1)
|
||||||
|
t.add(4)
|
||||||
|
t.add(2)
|
||||||
|
t.add(3)
|
||||||
|
|
||||||
|
t.forEach { print(it) }
|
||||||
|
}
|
||||||
@@ -24,6 +24,8 @@ import net.torvald.terrarum.modulebasegame.ui.abs
|
|||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer.convX
|
import net.torvald.terrarum.worlddrawer.LightmapRenderer.convX
|
||||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer.convY
|
import net.torvald.terrarum.worlddrawer.LightmapRenderer.convY
|
||||||
|
import net.torvald.util.SortedArrayList
|
||||||
|
import kotlin.math.sign
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,7 +102,7 @@ object LightmapRenderer {
|
|||||||
//private var lightmap: Array<Cvec> = Array(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
|
//private var lightmap: Array<Cvec> = Array(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
|
||||||
private val lanternMap = HashMap<BlockAddress, Cvec>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
private val lanternMap = HashMap<BlockAddress, Cvec>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||||
|
|
||||||
private val lightsourceMap = HashMap<BlockAddress, Cvec>(256)
|
private val lightsourceMap = ArrayList<Pair<BlockAddress, Cvec>>(256)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
LightmapHDRMap.invoke()
|
LightmapHDRMap.invoke()
|
||||||
@@ -245,13 +247,13 @@ object LightmapRenderer {
|
|||||||
else
|
else
|
||||||
colourNull.cpy()
|
colourNull.cpy()
|
||||||
// are you a light source?
|
// are you a light source?
|
||||||
lightlevel.maxAndAssign(BlockCodex[tile].luminosity)
|
lightlevel.maxAndAssign(BlockCodex[tile].lumCol)
|
||||||
// there will be a way to slightly optimise this following line but hey, let's make everything working right first...
|
// there will be a way to slightly optimise this following line but hey, let's make everything working right first...
|
||||||
lightlevel.maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
lightlevel.maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
||||||
|
|
||||||
if (!lightlevel.nonZero()) {
|
if (!lightlevel.nonZero()) {
|
||||||
// mark the tile as a light source
|
// mark the tile as a light source
|
||||||
lightsourceMap[LandUtil.getBlockAddr(world, x, y)] = lightlevel
|
lightsourceMap.add(LandUtil.getBlockAddr(world, x, y) to lightlevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
val lx = x.convX(); val ly = y.convY()
|
val lx = x.convX(); val ly = y.convY()
|
||||||
@@ -269,32 +271,32 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
fun r1() {
|
fun r1() {
|
||||||
// Round 1
|
// Round 1
|
||||||
for (y in for_y_start - overscan_open..for_y_end + overscan_open) {
|
for (y in for_y_start - overscan_open..for_y_end) {
|
||||||
for (x in for_x_start - overscan_open..for_x_end + overscan_open) {
|
for (x in for_x_start - overscan_open..for_x_end) {
|
||||||
calculateAndAssign(lightmap, x, y)
|
calculateAndAssign(lightmap, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun r2() {
|
fun r2() {
|
||||||
// Round 2
|
// Round 2
|
||||||
for (y in for_y_end + overscan_open downTo for_y_start - overscan_open) {
|
for (y in for_y_end + overscan_open downTo for_y_start) {
|
||||||
for (x in for_x_start - overscan_open..for_x_end + overscan_open) {
|
for (x in for_x_start - overscan_open..for_x_end) {
|
||||||
calculateAndAssign(lightmap, x, y)
|
calculateAndAssign(lightmap, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun r3() {
|
fun r3() {
|
||||||
// Round 3
|
// Round 3
|
||||||
for (y in for_y_end + overscan_open downTo for_y_start - overscan_open) {
|
for (y in for_y_end + overscan_open downTo for_y_start) {
|
||||||
for (x in for_x_end + overscan_open downTo for_x_start - overscan_open) {
|
for (x in for_x_end + overscan_open downTo for_x_start) {
|
||||||
calculateAndAssign(lightmap, x, y)
|
calculateAndAssign(lightmap, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun r4() {
|
fun r4() {
|
||||||
// Round 4
|
// Round 4
|
||||||
for (y in for_y_start - overscan_open..for_y_end + overscan_open) {
|
for (y in for_y_start - overscan_open..for_y_end) {
|
||||||
for (x in for_x_end + overscan_open downTo for_x_start - overscan_open) {
|
for (x in for_x_end + overscan_open downTo for_x_start) {
|
||||||
calculateAndAssign(lightmap, x, y)
|
calculateAndAssign(lightmap, x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +313,7 @@ object LightmapRenderer {
|
|||||||
AppLoader.measureDebugTime("Renderer.LightTotal") {
|
AppLoader.measureDebugTime("Renderer.LightTotal") {
|
||||||
|
|
||||||
|
|
||||||
//r1();r2();r3();r4()
|
r3();r4();r1();r2();
|
||||||
|
|
||||||
|
|
||||||
// ANECDOTES
|
// ANECDOTES
|
||||||
@@ -322,7 +324,7 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
|
|
||||||
// per-channel operation for bit more aggressive optimisation
|
// per-channel operation for bit more aggressive optimisation
|
||||||
for (lightsource in lightsourceMap) {
|
/*for (lightsource in lightsourceMap) {
|
||||||
val (lsx, lsy) = LandUtil.resolveBlockAddr(world, lightsource.key)
|
val (lsx, lsy) = LandUtil.resolveBlockAddr(world, lightsource.key)
|
||||||
|
|
||||||
// lightmap MUST BE PRE-SEEDED from known lightsources!
|
// lightmap MUST BE PRE-SEEDED from known lightsources!
|
||||||
@@ -356,7 +358,7 @@ object LightmapRenderer {
|
|||||||
if (skip) break
|
if (skip) break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (world.worldIndex != -1) { // to avoid updating on the null world
|
else if (world.worldIndex != -1) { // to avoid updating on the null world
|
||||||
@@ -608,7 +610,7 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
// regarding the issue #26
|
// regarding the issue #26
|
||||||
try {
|
try {
|
||||||
val fuck = BlockCodex[thisTerrain].luminosity
|
val fuck = BlockCodex[thisTerrain].lumCol
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
catch (e: NullPointerException) {
|
||||||
System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain")
|
System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain")
|
||||||
@@ -631,13 +633,13 @@ object LightmapRenderer {
|
|||||||
if (thisFluid.type != Fluid.NULL) {
|
if (thisFluid.type != Fluid.NULL) {
|
||||||
fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount)
|
fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount)
|
||||||
|
|
||||||
thisTileLuminosity.set(BlockCodex[thisTerrain].luminosity)
|
thisTileLuminosity.set(BlockCodex[thisTerrain].lumCol)
|
||||||
thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].luminosity.mul(fluidAmountToCol)) // already been div by four
|
thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].lumCol.mul(fluidAmountToCol)) // already been div by four
|
||||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
||||||
thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four
|
thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
thisTileLuminosity.set(BlockCodex[thisTerrain].luminosity)
|
thisTileLuminosity.set(BlockCodex[thisTerrain].lumCol)
|
||||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,7 +664,7 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
// regarding the issue #26
|
// regarding the issue #26
|
||||||
try {
|
try {
|
||||||
val fuck = BlockCodex[thisTerrain].luminosity
|
val fuck = BlockCodex[thisTerrain].lumCol
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {
|
catch (e: NullPointerException) {
|
||||||
System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain")
|
System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import java.util.concurrent.locks.ReentrantLock
|
|||||||
*
|
*
|
||||||
* Created by minjaesong on 2019-03-12.
|
* Created by minjaesong on 2019-03-12.
|
||||||
*/
|
*/
|
||||||
class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) {
|
class SortedArrayList<T>(initialSize: Int = 10) : Iterable<T> {
|
||||||
|
|
||||||
val arrayList = ArrayList<T>(initialSize)
|
val arrayList = ArrayList<T>(initialSize)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) {
|
|||||||
while (low < high) {
|
while (low < high) {
|
||||||
val mid = (low + high).ushr(1)
|
val mid = (low + high).ushr(1)
|
||||||
|
|
||||||
if (arrayList[mid] > elem)
|
if ((arrayList[mid] as Comparable<T>).compareTo(elem) > 0)
|
||||||
high = mid
|
high = mid
|
||||||
else
|
else
|
||||||
low = mid + 1
|
low = mid + 1
|
||||||
@@ -56,7 +56,7 @@ class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) {
|
|||||||
|
|
||||||
val midVal = get(mid)
|
val midVal = get(mid)
|
||||||
|
|
||||||
if (element > midVal)
|
if ((element as Comparable<T>).compareTo(midVal) > 0)
|
||||||
low = mid + 1
|
low = mid + 1
|
||||||
else if (element < midVal)
|
else if (element < midVal)
|
||||||
high = mid - 1
|
high = mid - 1
|
||||||
@@ -100,7 +100,7 @@ class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) {
|
|||||||
*/
|
*/
|
||||||
fun <R: Comparable<R>> searchFor(searchQuery: R, searchHow: (T) -> R): T? = getOrNull(searchForIndex(searchQuery, searchHow))
|
fun <R: Comparable<R>> searchFor(searchQuery: R, searchHow: (T) -> R): T? = getOrNull(searchForIndex(searchQuery, searchHow))
|
||||||
|
|
||||||
inline fun iterator() = arrayList.iterator()
|
override fun iterator() = arrayList.iterator()
|
||||||
inline fun forEach(action: (T) -> Unit) = arrayList.forEach(action)
|
inline fun forEach(action: (T) -> Unit) = arrayList.forEach(action)
|
||||||
inline fun forEachIndexed(action: (Int, T) -> Unit) = arrayList.forEachIndexed(action)
|
inline fun forEachIndexed(action: (Int, T) -> Unit) = arrayList.forEachIndexed(action)
|
||||||
|
|
||||||
@@ -116,42 +116,12 @@ class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) {
|
|||||||
|
|
||||||
inline fun <reified R> filterIsInstance() = arrayList.filterIsInstance<R>()
|
inline fun <reified R> filterIsInstance() = arrayList.filterIsInstance<R>()
|
||||||
|
|
||||||
/**
|
|
||||||
* Select one unsorted element from the array and put it onto the sorted spot.
|
|
||||||
*
|
|
||||||
* The list must be fully sorted except for that one "renegade", otherwise the operation is undefined behaviour.
|
|
||||||
*/
|
|
||||||
private fun sortThisRenegade(index: Int) {
|
|
||||||
if (
|
|
||||||
(index == arrayList.lastIndex && arrayList[index - 1] <= arrayList[index]) ||
|
|
||||||
(index == 0 && arrayList[index] <= arrayList[index + 1]) ||
|
|
||||||
(arrayList[index - 1] <= arrayList[index] && arrayList[index] <= arrayList[index + 1])
|
|
||||||
) return
|
|
||||||
|
|
||||||
// modified binary search
|
|
||||||
ReentrantLock().lock {
|
|
||||||
val renegade = arrayList.removeAt(index)
|
|
||||||
|
|
||||||
var low = 0
|
|
||||||
var high = arrayList.size
|
|
||||||
|
|
||||||
while (low < high) {
|
|
||||||
val mid = (low + high).ushr(1)
|
|
||||||
|
|
||||||
if (arrayList[mid] > renegade)
|
|
||||||
high = mid
|
|
||||||
else
|
|
||||||
low = mid + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayList.add(low, renegade)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does NOT create copies!
|
* Does NOT create copies!
|
||||||
*/
|
*/
|
||||||
fun toArrayList() = arrayList
|
fun toArrayList() = arrayList
|
||||||
|
|
||||||
|
fun clear() = arrayList.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T: Comparable<T>> sortedArrayListOf(vararg elements: T): SortedArrayList<T> {
|
fun <T: Comparable<T>> sortedArrayListOf(vararg elements: T): SortedArrayList<T> {
|
||||||
|
|||||||
Reference in New Issue
Block a user