Do some code cleaning in field synchronizer

This commit is contained in:
DBotThePony 2023-07-09 15:48:04 +07:00
parent 2095120abd
commit 5d8b770b94
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -48,7 +48,7 @@ import kotlin.reflect.KProperty0
* Universal, one-to-many value synchronizer, allowing to synchronize values from server to client * Universal, one-to-many value synchronizer, allowing to synchronize values from server to client
* anywhere, where input/output streams are supported * anywhere, where input/output streams are supported
*/ */
@Suppress("unused") @Suppress("unused", "BlockingMethodInNonBlockingContext")
class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCallback: Boolean) { class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCallback: Boolean) {
constructor() : this(Runnable {}, false) constructor() : this(Runnable {}, false)
constructor(callback: Runnable) : this(callback, false) constructor(callback: Runnable) : this(callback, false)
@ -485,6 +485,8 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
final override var isRemoved = false final override var isRemoved = false
private set private set
protected var isDirty = false
override fun remove() { override fun remove() {
if (isRemoved) if (isRemoved)
return return
@ -508,6 +510,12 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
endpoint.addDirtyField(this) endpoint.addDirtyField(this)
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this@AbstractField)
isDirty = true
}
} }
/** /**
@ -528,8 +536,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
} }
} }
private var isDirty = false
private val access = object : FieldAccess<V> { private val access = object : FieldAccess<V> {
override fun read(): V { override fun read(): V {
return field return field
@ -582,12 +588,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
this.field = value this.field = value
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this@Field)
isDirty = true
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) { override fun write(stream: DataOutputStream, endpoint: Endpoint) {
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
codec.write(stream, field) codec.write(stream, field)
@ -609,19 +609,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
} }
} }
abstract inner class PrimitiveField<V : Any>() : AbstractField<V>() { abstract inner class PrimitiveField<V : Any> : AbstractField<V>() {
protected var isDirty = false
override fun observe(): Boolean { override fun observe(): Boolean {
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
return isDirty return isDirty
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
} }
/** /**
@ -1022,7 +1014,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
) : AbstractField<V>(), IField<V> { ) : AbstractField<V>(), IField<V> {
private var remote: V? = null private var remote: V? = null
private var clientValue: V? = null private var clientValue: V? = null
private var isDirty = false
init { init {
observers.add(this) observers.add(this)
@ -1042,12 +1033,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return isDirty return isDirty
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
override val value: V override val value: V
get() = clientValue ?: getter.invoke() get() = clientValue ?: getter.invoke()
@ -1075,7 +1060,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private var isRemoteSet = false private var isRemoteSet = false
private var clientValue: Float = 0f private var clientValue: Float = 0f
private var isClientValue = false private var isClientValue = false
private var isDirty = false
override val property = object : IFloatProperty { override val property = object : IFloatProperty {
override fun getValue(thisRef: Any?, property: KProperty<*>): Float { override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
@ -1133,7 +1117,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property")) @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Float { override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
return super<IFloatField>.getValue(thisRef, property) return float
} }
} }
@ -1147,7 +1131,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private var isRemoteSet = false private var isRemoteSet = false
private var clientValue: Double = 0.0 private var clientValue: Double = 0.0
private var isClientValue = false private var isClientValue = false
private var isDirty = false
override val property = object : IDoubleProperty { override val property = object : IDoubleProperty {
override fun getValue(thisRef: Any?, property: KProperty<*>): Double { override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
@ -1174,12 +1157,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return isDirty return isDirty
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
override val double: Double override val double: Double
get() { get() {
if (isClientValue) { if (isClientValue) {
@ -1205,7 +1182,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property")) @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Double { override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
return super<IDoubleField>.getValue(thisRef, property) return double
} }
} }
@ -1219,7 +1196,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private var isRemoteSet = false private var isRemoteSet = false
protected var clientValue: Int = 0 protected var clientValue: Int = 0
protected var isClientValue = false protected var isClientValue = false
protected var isDirty = false
final override val property = object : IIntProperty { final override val property = object : IIntProperty {
override fun getValue(thisRef: Any?, property: KProperty<*>): Int { override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
@ -1246,12 +1222,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return isDirty return isDirty
} }
final override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
final override val int: Int final override val int: Int
get() { get() {
if (isClientValue) { if (isClientValue) {
@ -1263,7 +1233,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property")) @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Int { override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return super<IIntField>.getValue(thisRef, property) return int
} }
} }
@ -1319,7 +1289,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private var isRemoteSet = false private var isRemoteSet = false
protected var clientValue: Long = 0L protected var clientValue: Long = 0L
protected var isClientValue = false protected var isClientValue = false
protected var isDirty = false
final override val property = object : ILongProperty { final override val property = object : ILongProperty {
override fun getValue(thisRef: Any?, property: KProperty<*>): Long { override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
@ -1346,12 +1315,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return isDirty return isDirty
} }
final override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
final override val long: Long final override val long: Long
get() { get() {
if (isClientValue) { if (isClientValue) {
@ -1363,7 +1326,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property")) @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Long { override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
return super<ILongField>.getValue(thisRef, property) return long
} }
} }
@ -1419,7 +1382,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private var isRemoteSet = false private var isRemoteSet = false
private var clientValue: Boolean = false private var clientValue: Boolean = false
private var isClientValue = false private var isClientValue = false
private var isDirty = false
override val property = object : IBooleanProperty { override val property = object : IBooleanProperty {
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
@ -1446,12 +1408,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return isDirty return isDirty
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
override val boolean: Boolean override val boolean: Boolean
get() { get() {
if (isClientValue) { if (isClientValue) {
@ -1477,7 +1433,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property")) @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return super<IBooleanField>.getValue(thisRef, property) return boolean
} }
} }
@ -1508,8 +1464,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
remote = codec.copy(value) remote = codec.copy(value)
} }
private var isDirty = false
init { init {
observers.add(this) observers.add(this)
} }
@ -1528,12 +1482,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return isDirty return isDirty
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) { override fun write(stream: DataOutputStream, endpoint: Endpoint) {
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
codec.write(stream, value) codec.write(stream, value)
@ -1552,7 +1500,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private val callback: ((changes: Collection<SetChangeset<E>>) -> Unit)? = null, private val callback: ((changes: Collection<SetChangeset<E>>) -> Unit)? = null,
) : AbstractField<MutableSet<E>>() { ) : AbstractField<MutableSet<E>>() {
private var isRemote = false private var isRemote = false
private var isDirty = false
private fun pushBacklog(element: E, action: (DataOutputStream) -> Unit) { private fun pushBacklog(element: E, action: (DataOutputStream) -> Unit) {
check(!isRemote) { "Field marked as remote" } check(!isRemote) { "Field marked as remote" }
@ -1585,12 +1532,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
super.remove() super.remove()
} }
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
override fun markDirty(endpoint: Endpoint) { override fun markDirty(endpoint: Endpoint) {
super.markDirty(endpoint) super.markDirty(endpoint)
@ -1610,9 +1551,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
if (!isRemote) { if (!isRemote) {
markDirty() markDirty()
val copy = codec.copy(element)
pushBacklog(element) { pushBacklog(element) {
it.write(ChangesetAction.ADD.ordinal + 1) it.write(ChangesetAction.ADD.ordinal + 1)
codec.write(it, element) codec.write(it, copy)
} }
} }
@ -1668,6 +1611,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
if (!isRemote) { if (!isRemote) {
markDirty() markDirty()
@Suppress("unchecked_cast")
pushBacklog(lastElement as E) { pushBacklog(lastElement as E) {
it.write(ChangesetAction.REMOVE.ordinal + 1) it.write(ChangesetAction.REMOVE.ordinal + 1)
codec.write(it, lastElement as E) codec.write(it, lastElement as E)
@ -1683,9 +1627,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
if (!isRemote) { if (!isRemote) {
markDirty() markDirty()
val copy = codec.copy(element)
pushBacklog(element) { pushBacklog(element) {
it.write(ChangesetAction.REMOVE.ordinal + 1) it.write(ChangesetAction.REMOVE.ordinal + 1)
codec.write(it, element) codec.write(it, copy)
} }
} }
@ -1790,19 +1736,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private val keyCodec: IStreamCodec<K>, private val keyCodec: IStreamCodec<K>,
private val valueCodec: IStreamCodec<V>, private val valueCodec: IStreamCodec<V>,
private val backingMap: MutableMap<K, V>, private val backingMap: MutableMap<K, V>,
private val observingBackingMap: MutableMap<K, V>? = null,
private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null, private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
) : AbstractField<MutableMap<K, V>>(), IField<MutableMap<K, V>> { ) : AbstractField<MutableMap<K, V>>(), IField<MutableMap<K, V>> {
private var isDirty = false
private var sentAllValues = false private var sentAllValues = false
private var isRemote = false private var isRemote = false
init {
if (observingBackingMap != null) {
observers.add(this)
}
}
private fun pushBacklog(key: Any?, value: (DataOutputStream) -> Unit) { private fun pushBacklog(key: Any?, value: (DataOutputStream) -> Unit) {
val pair = key to value val pair = key to value
@ -1820,62 +1758,15 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
} }
} }
private fun clearBacklog() {
forEachEndpoint {
it.getMapBacklog(this).clear()
}
}
override fun observe(): Boolean { override fun observe(): Boolean {
check(!isRemoved) { "Field was removed" }
if (isRemote) {
return false return false
} }
val observingBackingMap = observingBackingMap
if (observingBackingMap != null) {
for ((key, value) in backingMap) {
val remoteValue = observingBackingMap[key] ?: throw ConcurrentModificationException("Backing map of $this was modified externally, or $value missed a modification")
if (!valueCodec.compare(value, remoteValue)) {
val valueCopy = valueCodec.copy(value)
pushBacklog(key) {
it.write(ChangesetAction.ADD.ordinal + 1)
keyCodec.write(it, key)
valueCodec.write(it, valueCopy)
}
observingBackingMap[key] = valueCopy
if (!isDirty) {
notifyEndpoints(this)
isDirty = true
}
}
}
}
return isDirty
}
override fun markDirty() { override fun markDirty() {
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
if (isRemote) { if (isRemote || endpoints.isEmpty())
return return
}
if (endpoints.isEmpty()) {
val observingBackingMap = observingBackingMap ?: return
for ((key, value) in backingMap)
observingBackingMap[key] = valueCodec.copy(value)
return
}
isDirty = true isDirty = true
val backlogs = LinkedList<LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>() val backlogs = LinkedList<LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
@ -1900,17 +1791,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
for (backlog in backlogs) { for (backlog in backlogs) {
backlog.add(key to action) backlog.add(key to action)
} }
observingBackingMap?.put(key, valueCopy)
} }
} }
override fun markDirty(endpoint: Endpoint) { override fun markDirty(endpoint: Endpoint) {
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
if (isRemote) { if (isRemote)
return return
}
val backlog = endpoint.getMapBacklog(this) val backlog = endpoint.getMapBacklog(this)
@ -1928,69 +1816,49 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
} }
} }
private fun lmarkDirty() {
if (!isDirty) {
notifyEndpoints(this@Map)
isDirty = true
}
}
override val value: MutableMap<K, V> = object : ProxiedMap<K, V>(backingMap) { override val value: MutableMap<K, V> = object : ProxiedMap<K, V>(backingMap) {
override fun onClear() { override fun onClear() {
if (isRemote) { if (isRemote || endpoints.isEmpty())
return return
}
if (endpoints.isEmpty()) {
return
}
observingBackingMap?.clear()
forEachEndpoint { endpoint -> forEachEndpoint { endpoint ->
endpoint.getMapBacklog(this@Map).also { endpoint.getMapBacklog(this@Map).let {
it.clear() it.clear()
it.add(null to ClearBacklogEntry) it.add(null to ClearBacklogEntry)
} }
} }
if (!isDirty) { lmarkDirty()
notifyEndpoints(this@Map)
isDirty = true
}
hasChanges = true hasChanges = true
} }
override fun onValueAdded(key: K, value: V) { override fun onValueAdded(key: K, value: V) {
if (isRemote) { if (isRemote || endpoints.isEmpty())
return return
}
if (endpoints.isEmpty()) {
return
}
val keyCopy = keyCodec.copy(key)
val valueCopy = valueCodec.copy(value) val valueCopy = valueCodec.copy(value)
pushBacklog(key) { pushBacklog(key) {
@Suppress("BlockingMethodInNonBlockingContext") // false positive @Suppress("BlockingMethodInNonBlockingContext") // false positive
it.write(ChangesetAction.ADD.ordinal + 1) it.write(ChangesetAction.ADD.ordinal + 1)
keyCodec.write(it, key) keyCodec.write(it, keyCopy)
valueCodec.write(it, valueCopy) valueCodec.write(it, valueCopy)
} }
observingBackingMap?.put(key, valueCopy) lmarkDirty()
if (!isDirty) {
notifyEndpoints(this@Map)
isDirty = true
}
hasChanges = true
} }
override fun onValueRemoved(key: K, value: V) { override fun onValueRemoved(key: K, value: V) {
if (isRemote) { if (isRemote || endpoints.isEmpty())
return return
}
if (endpoints.isEmpty()) {
return
}
val keyCopy = keyCodec.copy(key) val keyCopy = keyCodec.copy(key)
@ -2000,14 +1868,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
keyCodec.write(it, keyCopy) keyCodec.write(it, keyCopy)
} }
observingBackingMap?.remove(key) lmarkDirty()
if (!isDirty) {
notifyEndpoints(this@Map)
isDirty = true
}
hasChanges = true
} }
} }
@ -2029,7 +1890,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
if (!isRemote) { if (!isRemote) {
isRemote = true isRemote = true
forEachEndpoint { it.removeMapBacklog(this) } forEachEndpoint { it.removeMapBacklog(this) }
observingBackingMap?.clear()
} }
isDirty = false isDirty = false