Add a dedicated SpellList perst. data type for efficiency of ops

This commit is contained in:
Alwinfy 2022-05-11 13:17:18 -04:00 committed by yrsegal@gmail.com
parent 8241c351ce
commit f893fe2a69
17 changed files with 116 additions and 45 deletions

View file

@ -24,7 +24,7 @@ import java.util.*
* * [Double]
* * [Vec3][net.minecraft.world.phys.Vec3] as both position and (when normalized) direction
* * [Widget]; [Widget.NULL] is used as our null value
* * [List<SpellDatum<*>>][List]
* * [SpellList]
* * [HexPattern]! Yes, we have meta-evaluation everyone.
* The constructor guarantees we won't pass a type that isn't one of those types.
*
@ -50,7 +50,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
is Vec3 -> out.put(
TAG_VEC3, pl.serializeToNBT()
)
is ArrayList<*> -> {
is SpellList -> {
val subtag = ListTag()
for (elt in pl)
subtag.add((elt as SpellDatum<*>).serializeToNBT())
@ -92,7 +92,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
when (this.payload) {
is Entity -> DatumType.ENTITY
is Widget -> DatumType.WIDGET
is List<*> -> DatumType.LIST
is SpellList -> DatumType.LIST
is HexPattern -> DatumType.PATTERN
is Double -> DatumType.DOUBLE
is Vec3 -> DatumType.VEC
@ -102,15 +102,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
companion object {
@JvmStatic
fun make(payload: Any): SpellDatum<*> =
if (payload is List<*>) {
SpellDatum(payload.map {
when (it) {
null -> make(Widget.NULL)
is SpellDatum<*> -> it
else -> make(it)
}
})
} else if (payload is Vec3) {
if (payload is Vec3) {
SpellDatum(
Vec3(
HexUtils.FixNANs(payload.x),
@ -151,7 +143,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
// this is safe because otherwise we wouldn't have been able to get the list before
out.add(DeserializeFromNBT(subtag as CompoundTag, world))
}
SpellDatum(out)
SpellDatum(SpellList.LList(0, out))
}
TAG_WIDGET -> {
SpellDatum(Widget.valueOf(nbt.getString(key)))
@ -234,7 +226,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
Entity::class.java,
Double::class.java,
Vec3::class.java,
List::class.java,
SpellList::class.java,
Widget::class.java,
HexPattern::class.java,
)
@ -252,10 +244,10 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
const val TAG_ENTITY_NAME_CHEATY = "name"
fun <T : Any> IsValidType(checkee: T): Boolean =
if (checkee is List<*>) {
// note it should be impossible to pass a spell datum that doesn't contain a valid type,
if (checkee is SpellList) {
// note it should be impossible to pass a spelllist that doesn't contain a valid type,
// but we best make sure.
checkee.all { it is SpellDatum<*> && IsValidType(it.payload) }
checkee.all { IsValidType(it.payload) }
} else {
ValidTypes.any { clazz -> clazz.isAssignableFrom(checkee.javaClass) }
}

View file

@ -0,0 +1,75 @@
package at.petrak.hexcasting.api.spell
/**
* Restricted interface for functional lists.
*
* ...Surely this won't have any performance implications.
*/
sealed class SpellList: Iterable<SpellDatum<*>> {
abstract val nonEmpty: Boolean
abstract val car: SpellDatum<*>
abstract val cdr: SpellList
class LPair(override val car: SpellDatum<*>, override val cdr: SpellList): SpellList() {
override val nonEmpty = true
}
class LList(val idx: Int, val list: List<SpellDatum<*>>): SpellList() {
override val nonEmpty: Boolean
get() = idx < list.size
override val car: SpellDatum<*>
get() = list[idx]
override val cdr: SpellList
get() = LList(idx + 1, list)
}
fun modifyAt(startIdx: Int, modify: (SpellList) -> SpellList): SpellList {
val stack = mutableListOf<SpellDatum<*>>()
val ptr = iterator()
var idx = startIdx
if (idx < 0) {
return this
}
while (idx > 0) {
if (ptr.hasNext()) {
return this
}
idx--
stack.add(ptr.next())
}
var value = modify(ptr.list)
for (datum in stack.asReversed()) {
value = LPair(datum, value)
}
return value
}
fun getAt(startIdx: Int): SpellDatum<*> {
var ptr = this
var idx = startIdx
if (idx < 0) {
throw ArrayIndexOutOfBoundsException()
}
while (idx > 0) {
when (ptr) {
is LPair -> ptr = ptr.cdr
is LList -> return ptr.list[ptr.idx + idx]
}
idx--
}
return ptr.car
}
override fun iterator() = Iterator(this)
class Iterator(var list: SpellList): kotlin.collections.Iterator<SpellDatum<*>> {
override fun hasNext() = list.nonEmpty
override operator fun next(): SpellDatum<*> {
val car = list.car
list = list.cdr
return car
}
}
}

View file

@ -4,12 +4,13 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpAppend : ConstManaOperator {
override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0).toMutableList()
val list = args.getChecked<SpellList>(0).toMutableList()
val datum = args[1]
list.add(datum)
return spellListOf(list)

View file

@ -4,13 +4,14 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpConcat : ConstManaOperator {
override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = args.getChecked<List<SpellDatum<*>>>(0).toMutableList()
val rhs = args.getChecked<List<SpellDatum<*>>>(1)
val lhs = args.getChecked<SpellList>(0).toMutableList()
val rhs = args.getChecked<SpellList>(1)
lhs.addAll(rhs)
return spellListOf(lhs)
}

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.lists
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.Widget
import kotlin.math.roundToInt
@ -10,7 +11,7 @@ import kotlin.math.roundToInt
object OpIndex : ConstManaOperator {
override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0).toMutableList()
val list = args.getChecked<SpellList>(0).toMutableList()
val index = args.getChecked<Double>(1)
val x = list.getOrElse(index.roundToInt()) { SpellDatum.make(Widget.NULL) }
return listOf(x)

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpIndexOf : ConstManaOperator {
@ -11,7 +12,7 @@ object OpIndexOf : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0).toMutableList()
val list = args.getChecked<SpellList>(0).toMutableList()
val value = args[1]
return spellListOf(list.indexOf(value).toDouble())
}

View file

@ -4,12 +4,13 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
// it's still called beancounter's distillation in my heart
object OpListSize : ConstManaOperator {
override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
return spellListOf(args.getChecked<List<SpellDatum<*>>>(0).toList().size.toDouble()) // mmm one-liner
return spellListOf(args.getChecked<SpellList>(0).toList().size.toDouble()) // mmm one-liner
}
}

View file

@ -4,26 +4,16 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
import kotlin.math.roundToInt
object OpModifyInPlace : ConstManaOperator {
override val argc = 3
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0)
val list = args.getChecked<SpellList>(0)
val index = args.getChecked<Double>(1).roundToInt()
val iota = args[2]
if (0 > index || index > list.size)
return spellListOf(list)
val newList = list.toMutableList()
if (index == list.size)
newList.add(iota)
else
newList[index] = iota
return spellListOf(newList)
return spellListOf(list.modifyAt(index) { SpellList.LPair(iota, it.cdr) })
}
}

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpRemove : ConstManaOperator {
@ -11,7 +12,7 @@ object OpRemove : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0).toMutableList()
val list = args.getChecked<SpellList>(0).toMutableList()
val index = args.getChecked<Double>(1).toInt()
if (index < 0 || index >= list.size)
return list

View file

@ -4,11 +4,12 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpReverski : ConstManaOperator {
override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
return spellListOf(args.getChecked<List<SpellDatum<*>>>(0).asReversed()) // okay kotlin kinda pogged for this
return spellListOf(args.getChecked<SpellList>(0).toList().asReversed()) // okay kotlin kinda pogged for this
}
}

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
import net.minecraft.util.Mth
import kotlin.math.max
@ -13,7 +14,7 @@ import kotlin.math.roundToInt
object OpSlice : ConstManaOperator {
override val argc = 3
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0)
val list = args.getChecked<SpellList>(0).toList()
val index1 = Mth.clamp(args.getChecked<Double>(1).roundToInt(), 0, list.size)
val index2 = Mth.clamp(args.getChecked<Double>(2).roundToInt(), 0, list.size)

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.lists
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpSplat : ConstManaOperator {
@ -10,5 +11,5 @@ object OpSplat : ConstManaOperator {
get() = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> =
args.getChecked<List<SpellDatum<*>>>(0).toMutableList()
args.getChecked<SpellList>(0).toMutableList()
}

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.common.casting.operators.math.MathOpUtils
import kotlin.math.roundToInt
@ -16,7 +17,7 @@ object OpAnd : ConstManaOperator {
if (firstParam.right().isPresent) {
val list1 = firstParam.right().get()
val list2 = args.getChecked<List<SpellDatum<*>>>(1)
val list2 = args.getChecked<SpellList>(1)
return spellListOf(list1.filter { it in list2 })
}

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.common.casting.operators.math.MathOpUtils
import kotlin.math.roundToInt
@ -16,7 +17,7 @@ object OpOr : ConstManaOperator {
if (firstParam.right().isPresent) {
val list1 = firstParam.right().get()
val list2 = args.getChecked<List<SpellDatum<*>>>(1)
val list2 = args.getChecked<SpellList>(1)
return spellListOf(list1 + list2.filter { it !in list1 })
}

View file

@ -4,13 +4,14 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
object OpToSet : ConstManaOperator {
override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val payload = args.getChecked<List<SpellDatum<*>>>(0)
val payload = args.getChecked<SpellList>(0)
return spellListOf(payload.toSet().toList())
}
}

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.common.casting.operators.math.MathOpUtils
import kotlin.math.roundToInt
@ -16,7 +17,7 @@ object OpXor : ConstManaOperator {
if (firstParam.right().isPresent) {
val list1 = firstParam.right().get()
val list2 = args.getChecked<List<SpellDatum<*>>>(1)
val list2 = args.getChecked<SpellList>(1)
return spellListOf(list1.filter { it !in list2 } + list2.filter { it !in list1 })
}

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
@ -21,7 +22,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val entity = args.getChecked<ItemEntity>(0)
val patterns = args.getChecked<List<SpellDatum<*>>>(1)
val patterns = args.getChecked<SpellList>(1)
val (handStack, hand) = ctx.getHeldItemToOperateOn {
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it)