From cbea8873e965d62a10666ce98b7f39618bdc8c6a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 2 Sep 2022 12:54:02 +0700 Subject: [PATCH] Extract observed map from saved counting map --- .../ru/dbotthepony/mc/otm/core/ObservedMap.kt | 315 +++++++++++++++++ .../mc/otm/saveddata/SavedCountingMap.kt | 334 ++---------------- 2 files changed, 347 insertions(+), 302 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/ObservedMap.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ObservedMap.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ObservedMap.kt new file mode 100644 index 000000000..9276a08d9 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ObservedMap.kt @@ -0,0 +1,315 @@ +package ru.dbotthepony.mc.otm.core + +abstract class ObservedMap(protected val backingMap: MutableMap = HashMap()) : MutableMap { + protected abstract fun onClear() + protected abstract fun onValueAdded(key: K, value: V) + protected abstract fun onValueRemoved(key: K, value: V) + + final override val size: Int + get() = backingMap.size + + final override fun containsKey(key: K): Boolean { + return backingMap.containsKey(key) + } + + final override fun containsValue(value: V): Boolean { + return backingMap.containsValue(value) + } + + final override fun get(key: K): V? { + return backingMap[key] + } + + final override fun isEmpty(): Boolean { + return backingMap.isEmpty() + } + + final override val entries: MutableSet> by lazy { + object : MutableSet> { + override fun add(element: MutableMap.MutableEntry): Boolean { + this@ObservedMap[element.key] = element.value + return true + } + + override fun addAll(elements: Collection>): Boolean { + for (value in elements) { + add(value) + } + + return true + } + + override fun clear() { + this@ObservedMap.clear() + } + + private val setParent = this@ObservedMap.backingMap.entries + + override fun iterator(): MutableIterator> { + return object : MutableIterator> { + private val parent = setParent.iterator() + private var last: MutableMap.MutableEntry? = null + + override fun hasNext(): Boolean { + return parent.hasNext() + } + + override fun next(): MutableMap.MutableEntry { + return parent.next().also { last = it } + } + + override fun remove() { + val last = last ?: throw IllegalStateException("Never called next()") + parent.remove() + onValueRemoved(last.key, last.value) + } + } + } + + override fun remove(element: MutableMap.MutableEntry): Boolean { + if (setParent.remove(element)) { + onValueRemoved(element.key, element.value) + return true + } + + return false + } + + override fun removeAll(elements: Collection>): Boolean { + var any = false + + for (element in elements) { + any = remove(element) || any + } + + return any + } + + override fun retainAll(elements: Collection>): Boolean { + val iterator = this.iterator() + var any = false + + for (value in iterator) { + if (value !in elements) { + iterator.remove() + any = true + } + } + + return any + } + + override val size: Int + get() = setParent.size + + override fun contains(element: MutableMap.MutableEntry): Boolean { + return setParent.contains(element) + } + + override fun containsAll(elements: Collection>): Boolean { + return setParent.containsAll(elements) + } + + override fun isEmpty(): Boolean { + return setParent.isEmpty() + } + } + } + + final override val keys: MutableSet by lazy { + object : MutableSet { + val parent = this@ObservedMap.backingMap.keys + + override fun add(element: K): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun clear() { + this@ObservedMap.clear() + } + + override fun iterator(): MutableIterator { + return object : MutableIterator { + private val parentIterator = parent.iterator() + private var last: K? = null + + override fun hasNext(): Boolean { + return parentIterator.hasNext() + } + + override fun next(): K { + return parentIterator.next().also { last = it } + } + + override fun remove() { + val last = last ?: throw IllegalStateException("Never called next()") + val value = this@ObservedMap[last] ?: throw ConcurrentModificationException() + parentIterator.remove() + onValueRemoved(last, value) + } + } + } + + override fun remove(element: K): Boolean { + return this@ObservedMap.remove(element) != null + } + + override fun removeAll(elements: Collection): Boolean { + var changes = false + + for (element in elements) { + changes = remove(element) || changes + } + + return changes + } + + override fun retainAll(elements: Collection): Boolean { + val iterator = this.iterator() + var any = false + + for (element in iterator) { + if (element !in elements) { + iterator.remove() + any = true + } + } + + return any + } + + override val size: Int + get() = parent.size + + override fun contains(element: K): Boolean { + return parent.contains(element) + } + + override fun containsAll(elements: Collection): Boolean { + return parent.containsAll(elements) + } + + override fun isEmpty(): Boolean { + return parent.isEmpty() + } + } + } + + final override val values: MutableCollection by lazy { + object : MutableCollection { + private val parent = this@ObservedMap.backingMap.values + + override val size: Int + get() = parent.size + + override fun contains(element: V): Boolean { + return parent.contains(element) + } + + override fun containsAll(elements: Collection): Boolean { + return parent.containsAll(elements) + } + + override fun isEmpty(): Boolean { + return parent.isEmpty() + } + + override fun add(element: V): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun clear() { + this@ObservedMap.clear() + } + + override fun iterator(): MutableIterator { + return object : MutableIterator { + private val parentIterator = parent.iterator() + + override fun hasNext(): Boolean { + return parentIterator.hasNext() + } + + override fun next(): V { + return parentIterator.next() + } + + override fun remove() { + parentIterator.remove() + } + } + } + + override fun remove(element: V): Boolean { + val indexOf = this@ObservedMap.backingMap.firstNotNullOfOrNull { if (it.value == element) it.key else null } ?: return false + this@ObservedMap.remove(indexOf) + return true + } + + override fun removeAll(elements: Collection): Boolean { + var changes = false + + for (element in elements) { + changes = remove(element) || changes + } + + return changes + } + + override fun retainAll(elements: Collection): Boolean { + val iterator = this.iterator() + var changes = false + + for (element in iterator) { + if (element !in elements) { + iterator.remove() + changes = true + } + } + + return changes + } + } + } + + override fun clear() { + onClear() + return backingMap.clear() + } + + override fun put(key: K, value: V): V? { + val existing = backingMap.put(key, value) + + if (existing == value) { + return existing + } + + onValueAdded(key, value) + return existing + } + + final override fun putAll(from: Map) { + for ((k, v) in from) { + this[k] = v + } + } + + override fun remove(key: K): V? { + val removed = backingMap.remove(key) + + if (removed != null) { + onValueRemoved(key, removed) + } + + return removed + } +} + diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/saveddata/SavedCountingMap.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/saveddata/SavedCountingMap.kt index 59fb89ec3..8dd1ab17f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/saveddata/SavedCountingMap.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/saveddata/SavedCountingMap.kt @@ -8,8 +8,9 @@ import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag import net.minecraft.world.level.saveddata.SavedData import org.apache.logging.log4j.LogManager -import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.core.ObservedMap import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.registry.WriteOnce class SavedMapDelegate(val parent: SavedCountingMap>?, val index: Int, value: V) { constructor(value: V) : this(null, -1, value) @@ -37,11 +38,38 @@ class SavedMapDelegate(val parent: SavedCountingMap>?, va } } -class SavedCountingMap( +private class ObservedCountingMap : ObservedMap(Int2ObjectAVLTreeMap()) { + var parent: SavedCountingMap by WriteOnce() + + override fun onClear() { + parent.isDirty = true + } + + override fun onValueAdded(key: Int, value: T) { + parent.isDirty = true + } + + override fun onValueRemoved(key: Int, value: T) { + parent.isDirty = true + } +} + +class SavedCountingMap private constructor( val serializer: (map: SavedCountingMap, value: T, index: Int) -> Tag, val deserializer: (map: SavedCountingMap, nbt: Tag, index: Int) -> T, - val factory: (map: SavedCountingMap, index: Int) -> T -) : SavedData(), MutableMap { + val factory: (map: SavedCountingMap, index: Int) -> T, + private val map: ObservedCountingMap +) : SavedData(), MutableMap by map { + constructor( + serializer: (map: SavedCountingMap, value: T, index: Int) -> Tag, + deserializer: (map: SavedCountingMap, nbt: Tag, index: Int) -> T, + factory: (map: SavedCountingMap, index: Int) -> T, + ) : this(serializer, deserializer, factory, ObservedCountingMap()) + + init { + map.parent = this + } + var nextIndex = 0 private set @@ -56,304 +84,6 @@ class SavedCountingMap( return computeIfAbsent(nextIndex++) } - private val map = Int2ObjectAVLTreeMap() - - override val size: Int - get() = map.size - - override fun containsKey(key: Int): Boolean { - return map.containsKey(key) - } - - override fun containsValue(value: T): Boolean { - return map.containsValue(value) - } - - override fun get(key: Int): T? { - return map[key] - } - - override fun isEmpty(): Boolean { - return map.isEmpty() - } - - override val entries: MutableSet> by lazy { - object : MutableSet> { - override fun add(element: MutableMap.MutableEntry): Boolean { - this@SavedCountingMap[element.key] = element.value - return true - } - - override fun addAll(elements: Collection>): Boolean { - for (value in elements) { - add(value) - } - - return true - } - - override fun clear() { - this@SavedCountingMap.clear() - } - - private val setParent = this@SavedCountingMap.map.int2ObjectEntrySet() - - override fun iterator(): MutableIterator> { - return object : MutableIterator> { - private val parent = setParent.iterator() - - override fun hasNext(): Boolean { - return parent.hasNext() - } - - override fun next(): MutableMap.MutableEntry { - return parent.next() - } - - override fun remove() { - parent.remove() - isDirty = true - } - } - } - - override fun remove(element: MutableMap.MutableEntry): Boolean { - if (setParent.remove(element)) { - isDirty = true - return true - } - - return false - } - - override fun removeAll(elements: Collection>): Boolean { - if (setParent.removeAll(elements)) { - isDirty = true - return true - } - - return false - } - - override fun retainAll(elements: Collection>): Boolean { - if (setParent.retainAll(elements)) { - isDirty = true - return true - } - - return false - } - - override val size: Int - get() = setParent.size - - override fun contains(element: MutableMap.MutableEntry): Boolean { - return setParent.contains(element) - } - - override fun containsAll(elements: Collection>): Boolean { - return setParent.containsAll(elements) - } - - override fun isEmpty(): Boolean { - return setParent.isEmpty() - } - } - } - - override val keys: MutableSet by lazy { - object : MutableSet { - val parent = this@SavedCountingMap.map.keys - - override fun add(element: Int): Boolean { - throw UnsupportedOperationException() - } - - override fun addAll(elements: Collection): Boolean { - throw UnsupportedOperationException() - } - - override fun clear() { - this@SavedCountingMap.clear() - } - - override fun iterator(): MutableIterator { - return object : MutableIterator { - private val parentIterator = parent.iterator() - - override fun hasNext(): Boolean { - return parentIterator.hasNext() - } - - override fun next(): Int { - return parentIterator.nextInt() - } - - override fun remove() { - parentIterator.remove() - isDirty = true - } - } - } - - override fun remove(element: Int): Boolean { - return this@SavedCountingMap.remove(element) != null - } - - override fun removeAll(elements: Collection): Boolean { - var changes = false - - for (element in elements) { - changes = remove(element) || changes - } - - return changes - } - - override fun retainAll(elements: Collection): Boolean { - val iterator = this.iterator() - var changes = false - - for (element in iterator) { - if (element !in elements) { - iterator.remove() - changes = true - } - } - - return changes - } - - override val size: Int - get() = parent.size - - override fun contains(element: Int): Boolean { - return parent.contains(element) - } - - override fun containsAll(elements: Collection): Boolean { - return parent.containsAll(elements) - } - - override fun isEmpty(): Boolean { - return parent.isEmpty() - } - } - } - - override val values: MutableCollection by lazy { - object : MutableCollection { - private val parent = this@SavedCountingMap.map.values - - override val size: Int - get() = parent.size - - override fun contains(element: T): Boolean { - return parent.contains(element) - } - - override fun containsAll(elements: Collection): Boolean { - return parent.containsAll(elements) - } - - override fun isEmpty(): Boolean { - return parent.isEmpty() - } - - override fun add(element: T): Boolean { - throw UnsupportedOperationException() - } - - override fun addAll(elements: Collection): Boolean { - throw UnsupportedOperationException() - } - - override fun clear() { - this@SavedCountingMap.clear() - } - - override fun iterator(): MutableIterator { - return object : MutableIterator { - private val parentIterator = parent.iterator() - - override fun hasNext(): Boolean { - return parentIterator.hasNext() - } - - override fun next(): T { - return parentIterator.next() - } - - override fun remove() { - parentIterator.remove() - isDirty = true - } - } - } - - override fun remove(element: T): Boolean { - val indexOf = this@SavedCountingMap.map.firstNotNullOfOrNull { if (it.value == element) it.key else null } ?: return false - this@SavedCountingMap.remove(indexOf) - return true - } - - override fun removeAll(elements: Collection): Boolean { - var changes = false - - for (element in elements) { - changes = remove(element) || changes - } - - return changes - } - - override fun retainAll(elements: Collection): Boolean { - val iterator = this.iterator() - var changes = false - - for (element in iterator) { - if (element !in elements) { - iterator.remove() - changes = true - } - } - - return changes - } - } - } - - override fun clear() { - isDirty = true - return map.clear() - } - - override fun put(key: Int, value: T): T? { - val existing = map.put(key, value) - - if (existing == value) { - return existing - } - - isDirty = true - return existing - } - - override fun putAll(from: Map) { - isDirty = true - return map.putAll(from) - } - - override fun remove(key: Int): T? { - val removed = map.remove(key) - - if (removed != null) { - isDirty = true - } - - return removed - } - override fun save(output: CompoundTag): CompoundTag { output["map"] = ListTag().also { for ((key, value) in this.map) {