Slice and splice delegates, listenables, syncheddelegates

This commit is contained in:
DBotThePony 2024-02-08 19:59:14 +07:00
parent 5c26b1087a
commit 3c797b9131
Signed by: DBot
GPG Key ID: DCC23B5715498507
60 changed files with 1787 additions and 3431 deletions

View File

@ -4,7 +4,7 @@ kotlin.code.style=official
specifyKotlinAsDependency=false
projectGroup=ru.dbotthepony.kommons
projectVersion=1.7.9
projectVersion=2.0.0
guavaDepVersion=33.0.0
gsonDepVersion=2.8.9

View File

@ -10,7 +10,7 @@ import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kommons.core.Either
import ru.dbotthepony.kommons.util.Either
import java.lang.reflect.ParameterizedType
object EitherTypeAdapter : TypeAdapterFactory {

View File

@ -7,7 +7,7 @@ import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kommons.core.KOptional
import ru.dbotthepony.kommons.util.KOptional
import java.lang.reflect.ParameterizedType
@Suppress("DEPRECATION")

View File

@ -1,5 +1,8 @@
package ru.dbotthepony.kommons.io
import ru.dbotthepony.kommons.util.DelegateGetter
import ru.dbotthepony.kommons.util.DelegateSetter
import ru.dbotthepony.kommons.util.ListenableDelegate
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kommons.vector.Vector2f
import ru.dbotthepony.kommons.vector.Vector2i
@ -37,14 +40,26 @@ fun InputStream.readVector4i() = read4(::Vector4i) { it.readInt() }
fun InputStream.readVector4d() = read4(::Vector4d) { it.readDouble() }
fun InputStream.readVector4f() = read4(::Vector4f) { it.readFloat() }
val Vector2iCodec = StreamCodec(DataInputStream::readVector2i, DataOutputStream::writeStruct2i)
val Vector2dCodec = StreamCodec(DataInputStream::readVector2d, DataOutputStream::writeStruct2d)
val Vector2fCodec = StreamCodec(DataInputStream::readVector2f, DataOutputStream::writeStruct2f)
val Vector2iCodec = StreamCodec.Impl(DataInputStream::readVector2i, DataOutputStream::writeStruct2i)
val Vector2dCodec = StreamCodec.Impl(DataInputStream::readVector2d, DataOutputStream::writeStruct2d)
val Vector2fCodec = StreamCodec.Impl(DataInputStream::readVector2f, DataOutputStream::writeStruct2f)
val Vector3iCodec = StreamCodec(DataInputStream::readVector3i, DataOutputStream::writeStruct3i)
val Vector3dCodec = StreamCodec(DataInputStream::readVector3d, DataOutputStream::writeStruct3d)
val Vector3fCodec = StreamCodec(DataInputStream::readVector3f, DataOutputStream::writeStruct3f)
val Vector3iCodec = StreamCodec.Impl(DataInputStream::readVector3i, DataOutputStream::writeStruct3i)
val Vector3dCodec = StreamCodec.Impl(DataInputStream::readVector3d, DataOutputStream::writeStruct3d)
val Vector3fCodec = StreamCodec.Impl(DataInputStream::readVector3f, DataOutputStream::writeStruct3f)
val Vector4iCodec = StreamCodec(DataInputStream::readVector4i, DataOutputStream::writeStruct4i)
val Vector4dCodec = StreamCodec(DataInputStream::readVector4d, DataOutputStream::writeStruct4d)
val Vector4fCodec = StreamCodec(DataInputStream::readVector4f, DataOutputStream::writeStruct4f)
val Vector4iCodec = StreamCodec.Impl(DataInputStream::readVector4i, DataOutputStream::writeStruct4i)
val Vector4dCodec = StreamCodec.Impl(DataInputStream::readVector4d, DataOutputStream::writeStruct4d)
val Vector4fCodec = StreamCodec.Impl(DataInputStream::readVector4f, DataOutputStream::writeStruct4f)
fun SynchedDelegates.vec2i(value: Vector2i, getter: DelegateGetter<Vector2i> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector2i> = DelegateSetter.passthrough()): ListenableDelegate<Vector2i> = RegularValue(value, Vector2iCodec, getter, setter)
fun SynchedDelegates.vec2d(value: Vector2d, getter: DelegateGetter<Vector2d> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector2d> = DelegateSetter.passthrough()): ListenableDelegate<Vector2d> = RegularValue(value, Vector2dCodec, getter, setter)
fun SynchedDelegates.vec2f(value: Vector2f, getter: DelegateGetter<Vector2f> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector2f> = DelegateSetter.passthrough()): ListenableDelegate<Vector2f> = RegularValue(value, Vector2fCodec, getter, setter)
fun SynchedDelegates.vec3i(value: Vector3i, getter: DelegateGetter<Vector3i> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector3i> = DelegateSetter.passthrough()): ListenableDelegate<Vector3i> = RegularValue(value, Vector3iCodec, getter, setter)
fun SynchedDelegates.vec3d(value: Vector3d, getter: DelegateGetter<Vector3d> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector3d> = DelegateSetter.passthrough()): ListenableDelegate<Vector3d> = RegularValue(value, Vector3dCodec, getter, setter)
fun SynchedDelegates.vec3f(value: Vector3f, getter: DelegateGetter<Vector3f> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector3f> = DelegateSetter.passthrough()): ListenableDelegate<Vector3f> = RegularValue(value, Vector3fCodec, getter, setter)
fun SynchedDelegates.vec4i(value: Vector4i, getter: DelegateGetter<Vector4i> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector4i> = DelegateSetter.passthrough()): ListenableDelegate<Vector4i> = RegularValue(value, Vector4iCodec, getter, setter)
fun SynchedDelegates.vec4d(value: Vector4d, getter: DelegateGetter<Vector4d> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector4d> = DelegateSetter.passthrough()): ListenableDelegate<Vector4d> = RegularValue(value, Vector4dCodec, getter, setter)
fun SynchedDelegates.vec4f(value: Vector4f, getter: DelegateGetter<Vector4f> = DelegateGetter.passthrough(), setter: DelegateSetter<Vector4f> = DelegateSetter.passthrough()): ListenableDelegate<Vector4f> = RegularValue(value, Vector4fCodec, getter, setter)

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.kommons.matrix
import ru.dbotthepony.kommons.arrays.Double2DArray
import ru.dbotthepony.kommons.arrays.mulMatrixComponents
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.vector.Vector2d
import java.nio.ByteBuffer
import java.nio.DoubleBuffer

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.kommons.matrix
import ru.dbotthepony.kommons.arrays.Float2DArray
import ru.dbotthepony.kommons.arrays.mulMatrixComponents
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.vector.Vector2f
import java.nio.ByteBuffer
import java.nio.FloatBuffer

View File

@ -2,8 +2,8 @@ package ru.dbotthepony.kommons.matrix
import ru.dbotthepony.kommons.arrays.Double2DArray
import ru.dbotthepony.kommons.arrays.mulMatrixComponents
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kommons.vector.Vector3d
import java.nio.ByteBuffer

View File

@ -2,8 +2,8 @@ package ru.dbotthepony.kommons.matrix
import ru.dbotthepony.kommons.arrays.Float2DArray
import ru.dbotthepony.kommons.arrays.mulMatrixComponents
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.vector.Vector2f
import ru.dbotthepony.kommons.vector.Vector3f
import java.nio.ByteBuffer

View File

@ -2,9 +2,9 @@ package ru.dbotthepony.kommons.matrix
import ru.dbotthepony.kommons.arrays.Double2DArray
import ru.dbotthepony.kommons.arrays.mulMatrixComponents
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct4d
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct4d
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kommons.vector.Vector3d
import ru.dbotthepony.kommons.vector.Vector4d

View File

@ -2,9 +2,9 @@ package ru.dbotthepony.kommons.matrix
import ru.dbotthepony.kommons.arrays.Float2DArray
import ru.dbotthepony.kommons.arrays.mulMatrixComponents
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct4f
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct4f
import ru.dbotthepony.kommons.vector.Vector2f
import ru.dbotthepony.kommons.vector.Vector3f
import ru.dbotthepony.kommons.vector.Vector4f

View File

@ -3,7 +3,6 @@
package ru.dbotthepony.kommons.util
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.math.intersectRectangles
import ru.dbotthepony.kommons.math.rectangleContainsRectangle
import ru.dbotthepony.kommons.vector.Vector2d

View File

@ -1,6 +1,5 @@
package ru.dbotthepony.kommons.util
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.math.intersectRectangles
import ru.dbotthepony.kommons.math.rectangleContainsRectangle
import ru.dbotthepony.kommons.vector.Vector2i

View File

@ -1,8 +1,8 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.matrix.Matrix2d
import ru.dbotthepony.kommons.matrix.Matrix3d
import ru.dbotthepony.kommons.matrix.Matrix4d

View File

@ -1,8 +1,8 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.matrix.Matrix2f
import ru.dbotthepony.kommons.matrix.Matrix3f
import ru.dbotthepony.kommons.matrix.Matrix4f

View File

@ -1,8 +1,8 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import kotlin.math.sqrt
data class Vector2i(

View File

@ -1,11 +1,11 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.matrix.Matrix3d
import ru.dbotthepony.kommons.matrix.Matrix4d
import ru.dbotthepony.kommons.matrix.Matrix4dStack

View File

@ -1,11 +1,11 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.matrix.Matrix3f
import ru.dbotthepony.kommons.matrix.Matrix4f
import ru.dbotthepony.kommons.matrix.Matrix4fStack

View File

@ -1,11 +1,11 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import kotlin.math.sqrt
data class Vector3i(

View File

@ -1,15 +1,14 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.vector.Vector4f
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.core.IStruct4d
import ru.dbotthepony.kommons.core.IStruct4f
import ru.dbotthepony.kommons.core.IStruct4i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.util.IStruct4d
import ru.dbotthepony.kommons.util.IStruct4f
import ru.dbotthepony.kommons.util.IStruct4i
import ru.dbotthepony.kommons.matrix.Matrix4d
import ru.dbotthepony.kommons.matrix.Matrix4dStack
import kotlin.math.absoluteValue

View File

@ -1,14 +1,14 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.core.IStruct4d
import ru.dbotthepony.kommons.core.IStruct4f
import ru.dbotthepony.kommons.core.IStruct4i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.util.IStruct4d
import ru.dbotthepony.kommons.util.IStruct4f
import ru.dbotthepony.kommons.util.IStruct4i
import ru.dbotthepony.kommons.matrix.Matrix4f
import ru.dbotthepony.kommons.matrix.Matrix4fStack
import kotlin.math.absoluteValue

View File

@ -1,15 +1,14 @@
package ru.dbotthepony.kommons.vector
import ru.dbotthepony.kommons.vector.Vector4f
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.core.IStruct4d
import ru.dbotthepony.kommons.core.IStruct4f
import ru.dbotthepony.kommons.core.IStruct4i
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.util.IStruct4d
import ru.dbotthepony.kommons.util.IStruct4f
import ru.dbotthepony.kommons.util.IStruct4i
import kotlin.math.sqrt
data class Vector4i(

View File

@ -1,6 +1,6 @@
package ru.dbotthepony.kommons.collect
import ru.dbotthepony.kommons.core.KOptional
import ru.dbotthepony.kommons.util.KOptional
import java.lang.ref.Reference
import java.util.*
import java.util.concurrent.CompletableFuture

View File

@ -1,149 +0,0 @@
package ru.dbotthepony.kommons.core
import ru.dbotthepony.kommons.event.ISubscriptable
import java.util.function.Consumer
import java.util.function.Supplier
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty
inline var <V> GetterSetter<V>.value: V
get() = get()
set(value) { accept(value) }
interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V> {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
accept(value)
}
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return get()
}
operator fun invoke(): V {
return get()
}
operator fun invoke(value: V) {
accept(value)
}
fun asGetterOnly(): GetterSetter<V> {
val self = this
return object : GetterSetter<V> {
override fun get(): V {
return self.get()
}
override fun accept(t: V) {
}
}
}
fun watch(watch: (old: V, new: V) -> Unit): GetterSetter<V> {
val self = this
return object : GetterSetter<V> by self {
override fun accept(t: V) {
val old = get()
self.accept(t)
watch.invoke(old, t)
}
}
}
companion object {
fun <V> of(getter: Supplier<V>, setter: Consumer<V>): GetterSetter<V> {
return object : GetterSetter<V> {
override fun get(): V {
return getter.get()
}
override fun accept(t: V) {
setter.accept(t)
}
}
}
fun <V> of(getter: () -> V, setter: (V) -> Unit): GetterSetter<V> {
return object : GetterSetter<V> {
override fun get(): V {
return getter.invoke()
}
override fun accept(t: V) {
setter.invoke(t)
}
}
}
fun <V> of(property: KMutableProperty0<V>): GetterSetter<V> {
return object : GetterSetter<V> {
override fun get(): V {
return property.get()
}
override fun accept(t: V) {
property.set(t)
}
}
}
fun <V> box(value: V): SentientGetterSetter<V> {
return object : SentientGetterSetter<V> {
private val subs = ISubscriptable.Impl<V>()
override fun addListener(listener: Consumer<V>): ISubscriptable.L {
return subs.addListener(listener)
}
private var value = value
override fun get(): V {
return value
}
override fun accept(t: V) {
this.value = t
subs.accept(t)
}
}
}
}
}
interface SentientGetterSetter<V> : GetterSetter<V>, ISubscriptable<V> {
override fun watch(watch: (old: V, new: V) -> Unit): SentientGetterSetter<V> {
val self = this
return object : SentientGetterSetter<V> by self {
override fun accept(t: V) {
val old = get()
self.accept(t)
watch.invoke(old, t)
}
}
}
}
operator fun <T> Supplier<T>.getValue(thisRef: Any?, property: KProperty<*>): T {
return get()
}
operator fun <T> Consumer<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
accept(value)
}
fun <V> KMutableProperty0<V>.asGetterSetter(watch: ((old: V, new: V) -> Unit)? = null): GetterSetter<V> {
return GetterSetter.of(this).let {
if (watch != null) {
it.watch(watch)
} else {
it
}
}
}
fun <V> KMutableProperty0<V>.asGetterOnly() = GetterSetter.of(Supplier { this.get() }, Consumer { /* do nothing */ })

View File

@ -1,43 +0,0 @@
package ru.dbotthepony.kommons.event
import it.unimi.dsi.fastutil.booleans.BooleanConsumer
import java.util.function.Consumer
interface IBooleanSubscriptable : ISubscriptable<Boolean> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Boolean>): ISubscriptable.L {
return addListener(listener::accept)
}
fun addListener(listener: BooleanConsumer): ISubscriptable.L
class Impl : IBooleanSubscriptable, Consumer<Boolean>, BooleanConsumer {
private inner class L(val callback: BooleanConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: BooleanConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Boolean) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -1,43 +0,0 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
import java.util.function.DoubleConsumer
interface IDoubleSubcriptable : ISubscriptable<Double> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Double>): ISubscriptable.L {
return addListener(DoubleConsumer { listener.accept(it) })
}
fun addListener(listener: DoubleConsumer): ISubscriptable.L
class Impl : IDoubleSubcriptable, Consumer<Double>, DoubleConsumer {
private inner class L(val callback: DoubleConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: DoubleConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Double) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -1,43 +0,0 @@
package ru.dbotthepony.kommons.event
import it.unimi.dsi.fastutil.floats.FloatConsumer
import java.util.function.Consumer
interface IFloatSubcriptable : ISubscriptable<Float> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Float>): ISubscriptable.L {
return addListener(listener::accept)
}
fun addListener(listener: FloatConsumer): ISubscriptable.L
class Impl : IFloatSubcriptable, Consumer<Float>, FloatConsumer {
private inner class L(val callback: FloatConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: FloatConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Float) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -1,43 +0,0 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
import java.util.function.IntConsumer
interface IIntSubcriptable : ISubscriptable<Int> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Int>): ISubscriptable.L {
return addListener(IntConsumer { listener.accept(it) })
}
fun addListener(listener: IntConsumer): ISubscriptable.L
class Impl : IIntSubcriptable, Consumer<Int>, IntConsumer {
private inner class L(val callback: IntConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: IntConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Int) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -1,43 +0,0 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
import java.util.function.LongConsumer
interface ILongSubcriptable : ISubscriptable<Long> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Long>): ISubscriptable.L {
return addListener(LongConsumer { listener.accept(it) })
}
fun addListener(listener: LongConsumer): ISubscriptable.L
class Impl : ILongSubcriptable, Consumer<Long>, LongConsumer {
private inner class L(val callback: LongConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: LongConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Long) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -1,60 +0,0 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
interface ISubscriptable<V> {
/**
* Listener token, allows to remove listener from subscriber list
*/
fun interface L {
/**
* Removes this listener
*/
fun remove()
}
fun addListener(listener: Consumer<V>): L
class Impl<V> : ISubscriptable<V>, Consumer<V> {
private inner class L(val callback: Consumer<V>) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: Consumer<V>): ISubscriptable.L {
return L(listener)
}
override fun accept(t: V) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
companion object : ISubscriptable<Nothing>, L {
@Suppress("unchecked_cast")
fun <T> empty(): ISubscriptable<T> {
return this as ISubscriptable<T>
}
override fun remove() {}
override fun addListener(listener: Consumer<Nothing>): L {
return this
}
}
}

View File

@ -1,41 +0,0 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
interface IUnitSubscriptable : ISubscriptable<Unit> {
fun addListener(listener: Runnable): ISubscriptable.L
override fun addListener(listener: Consumer<Unit>): ISubscriptable.L {
return addListener(Runnable { listener.accept(Unit) })
}
class Impl : IUnitSubscriptable, Runnable {
private inner class L(val callback: Runnable) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = ArrayList<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: Runnable): ISubscriptable.L {
return L(listener)
}
override fun run() {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.run() }
}
}
}

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kommons.networking
package ru.dbotthepony.kommons.io
enum class ChangesetAction {
CLEAR, ADD, REMOVE

View File

@ -1,34 +0,0 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStreamCodec<E>, val collectionFactory: (Int) -> C) :
IStreamCodec<C> {
override fun read(stream: DataInputStream): C {
val size = stream.readVarInt()
if (size <= 0) {
return collectionFactory.invoke(0)
}
val collection = collectionFactory.invoke(size)
for (i in 0 until size) {
collection.add(elementCodec.read(stream))
}
return collection
}
override fun write(stream: DataOutputStream, value: C) {
stream.writeVarInt(value.size)
value.forEach { elementCodec.write(stream, it) }
}
override fun copy(value: C): C {
val new = collectionFactory.invoke(value.size)
value.forEach { new.add(elementCodec.copy(it)) }
return new
}
}

View File

@ -20,4 +20,4 @@ fun OutputStream.writeDecimal(value: Decimal) {
write(bytes)
}
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
val DecimalValueCodec = StreamCodec.Impl(DataInputStream::readDecimal, DataOutputStream::writeDecimal)

View File

@ -1,48 +0,0 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>) : IStreamCodec<V> {
val clazz = searchClass(clazz)
val values: List<V> = listOf(*this.clazz.enumConstants!!)
val valuesMap = values.associateBy { it.name }
override fun read(stream: DataInputStream): V {
val id = stream.readVarInt()
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
}
override fun write(stream: DataOutputStream, value: V) {
stream.writeVarInt(value.ordinal)
}
override fun copy(value: V): V {
return value
}
override fun compare(a: V, b: V): Boolean {
return a === b
}
companion object {
/**
* FIXME: enums with abstract methods which get compiled to subclasses, whose DO NOT expose "parent's" enum constants array
*
* is there an already existing solution?
*/
fun <V : Enum<V>> searchClass(clazz: Class<out V>): Class<out V> {
var search: Class<*> = clazz
while (search.enumConstants == null && search.superclass != null) {
search = search.superclass
}
if (search.enumConstants == null) {
throw ClassCastException("$clazz does not represent an enum or enum subclass")
}
return search as Class<out V>
}
}
}

View File

@ -1,28 +0,0 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
/**
* Represents value which can be encoded onto or decoded from stream.
*
* Also provides [copy] and [compare] methods
*/
interface IStreamCodec<V> {
fun read(stream: DataInputStream): V
fun write(stream: DataOutputStream, value: V)
/**
* if value is immutable, return it right away
*/
fun copy(value: V): V
/**
* Optional equality check override. Utilized to determine whenever e.g. network value is different from new value
*
* By default uses [Any.equals]
*/
fun compare(a: V, b: V): Boolean {
return a == b
}
}

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kommons.networking
package ru.dbotthepony.kommons.io
data class MapChangeset<out K, out V>(
val action: ChangesetAction,

View File

@ -1,23 +1,23 @@
package ru.dbotthepony.kommons.io
import ru.dbotthepony.kommons.core.IStruct2b
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct2l
import ru.dbotthepony.kommons.core.IStruct2s
import ru.dbotthepony.kommons.core.IStruct3b
import ru.dbotthepony.kommons.core.IStruct3d
import ru.dbotthepony.kommons.core.IStruct3f
import ru.dbotthepony.kommons.core.IStruct3i
import ru.dbotthepony.kommons.core.IStruct3l
import ru.dbotthepony.kommons.core.IStruct3s
import ru.dbotthepony.kommons.core.IStruct4b
import ru.dbotthepony.kommons.core.IStruct4d
import ru.dbotthepony.kommons.core.IStruct4f
import ru.dbotthepony.kommons.core.IStruct4i
import ru.dbotthepony.kommons.core.IStruct4l
import ru.dbotthepony.kommons.core.IStruct4s
import ru.dbotthepony.kommons.util.IStruct2b
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct2l
import ru.dbotthepony.kommons.util.IStruct2s
import ru.dbotthepony.kommons.util.IStruct3b
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.util.IStruct3l
import ru.dbotthepony.kommons.util.IStruct3s
import ru.dbotthepony.kommons.util.IStruct4b
import ru.dbotthepony.kommons.util.IStruct4d
import ru.dbotthepony.kommons.util.IStruct4f
import ru.dbotthepony.kommons.util.IStruct4i
import ru.dbotthepony.kommons.util.IStruct4l
import ru.dbotthepony.kommons.util.IStruct4s
import java.io.DataOutput
import java.io.OutputStream
import java.io.RandomAccessFile

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kommons.networking
package ru.dbotthepony.kommons.io
data class SetChangeset<out V>(
val action: ChangesetAction,

View File

@ -0,0 +1,175 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.*
import kotlin.reflect.KClass
/**
* Represents value which can be encoded onto or decoded from stream.
*
* Also provides [copy] and [compare] methods
*/
interface StreamCodec<V> {
fun read(stream: DataInputStream): V
fun write(stream: DataOutputStream, value: V)
/**
* defensive copy
*/
fun copy(value: V): V
/**
* Optional equality check override. Utilized to determine whenever e.g. network value is different from new value
*
* By default uses [Any.equals]
*/
fun compare(a: V, b: V): Boolean {
return a == b
}
class Impl<V>(
private val reader: (stream: DataInputStream) -> V,
private val writer: (stream: DataOutputStream, value: V) -> Unit,
private val copier: ((value: V) -> V) = { it },
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : StreamCodec<V> {
constructor(
reader: (stream: DataInputStream) -> V,
payloadSize: Long,
writer: (stream: DataOutputStream, value: V) -> Unit,
copier: ((value: V) -> V) = { it },
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : this({ stream -> reader.invoke(stream) }, writer, copier, comparator)
val nullable = object : StreamCodec<V?> {
override fun read(stream: DataInputStream): V? {
return if (stream.read() == 0) null else reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V?) {
if (value === null) stream.write(0) else {
stream.write(1)
writer.invoke(stream, value)
}
}
override fun copy(value: V?): V? {
return if (value === null) null else copier.invoke(value)
}
override fun compare(a: V?, b: V?): Boolean {
if (a === null && b === null) return true
if (a === null || b === null) return false
return comparator.invoke(a, b)
}
}
override fun read(stream: DataInputStream): V {
return reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V) {
writer.invoke(stream, value)
}
override fun copy(value: V): V {
return copier.invoke(value)
}
override fun compare(a: V, b: V): Boolean {
return comparator.invoke(a, b)
}
}
class Collection<E, C : MutableCollection<E>>(val elementCodec: StreamCodec<E>, val collectionFactory: (Int) -> C) : StreamCodec<C> {
override fun read(stream: DataInputStream): C {
val size = stream.readVarInt()
if (size <= 0) {
return collectionFactory.invoke(0)
}
val collection = collectionFactory.invoke(size)
for (i in 0 until size) {
collection.add(elementCodec.read(stream))
}
return collection
}
override fun write(stream: DataOutputStream, value: C) {
stream.writeVarInt(value.size)
value.forEach { elementCodec.write(stream, it) }
}
override fun copy(value: C): C {
val new = collectionFactory.invoke(value.size)
value.forEach { new.add(elementCodec.copy(it)) }
return new
}
}
class Enum<V : kotlin.Enum<V>>(clazz: Class<out V>) : StreamCodec<V> {
val clazz = searchClass(clazz)
val values: List<V> = listOf(*this.clazz.enumConstants!!)
val valuesMap = values.associateBy { it.name }
override fun read(stream: DataInputStream): V {
val id = stream.readVarInt()
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
}
override fun write(stream: DataOutputStream, value: V) {
stream.writeVarInt(value.ordinal)
}
override fun copy(value: V): V {
return value
}
override fun compare(a: V, b: V): Boolean {
return a === b
}
companion object {
/**
* FIXME: enums with abstract methods which get compiled to subclasses, whose DO NOT expose "parent's" enum constants array
*
* is there an already existing solution?
*/
fun <V : kotlin.Enum<V>> searchClass(clazz: Class<out V>): Class<out V> {
var search: Class<*> = clazz
while (search.enumConstants == null && search.superclass != null) {
search = search.superclass
}
if (search.enumConstants == null) {
throw ClassCastException("$clazz does not represent an enum or enum subclass")
}
return search as Class<out V>
}
}
}
}
val NullValueCodec = StreamCodec.Impl({ _ -> null }, { _, _ -> })
val BooleanValueCodec = StreamCodec.Impl(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean)
val ByteValueCodec = StreamCodec.Impl(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) })
val ShortValueCodec = StreamCodec.Impl(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) })
val CharValueCodec = StreamCodec.Impl(DataInputStream::readChar, 2L, { s, v -> s.writeShort(v.code) })
val IntValueCodec = StreamCodec.Impl(DataInputStream::readInt, 4L, DataOutputStream::writeInt)
val LongValueCodec = StreamCodec.Impl(DataInputStream::readLong, 8L, DataOutputStream::writeLong)
val FloatValueCodec = StreamCodec.Impl(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat)
val DoubleValueCodec = StreamCodec.Impl(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble)
val BigDecimalValueCodec = StreamCodec.Impl(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
val UUIDValueCodec = StreamCodec.Impl({ s -> UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
val VarIntValueCodec = StreamCodec.Impl(DataInputStream::readSignedVarInt, DataOutputStream::writeSignedVarInt)
val VarLongValueCodec = StreamCodec.Impl(DataInputStream::readSignedVarLong, DataOutputStream::writeSignedVarLong)
val BinaryStringCodec = StreamCodec.Impl(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
fun <E : Enum<E>> Class<E>.codec() = StreamCodec.Enum(this)
fun <E : Enum<E>> KClass<E>.codec() = StreamCodec.Enum(this.java)

View File

@ -1,77 +0,0 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.*
import kotlin.reflect.KClass
class StreamCodec<V>(
private val reader: (stream: DataInputStream) -> V,
private val writer: (stream: DataOutputStream, value: V) -> Unit,
private val copier: ((value: V) -> V) = { it },
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : IStreamCodec<V> {
constructor(
reader: (stream: DataInputStream) -> V,
payloadSize: Long,
writer: (stream: DataOutputStream, value: V) -> Unit,
copier: ((value: V) -> V) = { it },
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : this({ stream -> reader.invoke(stream) }, writer, copier, comparator)
val nullable = object : IStreamCodec<V?> {
override fun read(stream: DataInputStream): V? {
return if (stream.read() == 0) null else reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V?) {
if (value === null) stream.write(0) else {
stream.write(1)
writer.invoke(stream, value)
}
}
override fun copy(value: V?): V? {
return if (value === null) null else copier.invoke(value)
}
override fun compare(a: V?, b: V?): Boolean {
if (a === null && b === null) return true
if (a === null || b === null) return false
return comparator.invoke(a, b)
}
}
override fun read(stream: DataInputStream): V {
return reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V) {
writer.invoke(stream, value)
}
override fun copy(value: V): V {
return copier.invoke(value)
}
override fun compare(a: V, b: V): Boolean {
return comparator.invoke(a, b)
}
}
val NullValueCodec = StreamCodec({ _ -> null }, { _, _ -> })
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean) { a, b -> a == b }
val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) }) { a, b -> a == b }
val ShortValueCodec = StreamCodec(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) }) { a, b -> a == b }
val IntValueCodec = StreamCodec(DataInputStream::readInt, 4L, DataOutputStream::writeInt) { a, b -> a == b }
val LongValueCodec = StreamCodec(DataInputStream::readLong, 8L, DataOutputStream::writeLong) { a, b -> a == b }
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat) { a, b -> a == b }
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble) { a, b -> a == b }
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
val UUIDValueCodec = StreamCodec({ s -> UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
val VarIntValueCodec = StreamCodec(DataInputStream::readSignedVarInt, DataOutputStream::writeSignedVarInt) { a, b -> a == b }
val VarLongValueCodec = StreamCodec(DataInputStream::readSignedVarLong, DataOutputStream::writeSignedVarLong) { a, b -> a == b }
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
fun <E : Enum<E>> Class<E>.codec() = EnumValueCodec(this)
fun <E : Enum<E>> KClass<E>.codec() = EnumValueCodec(this.java)

View File

@ -0,0 +1,945 @@
@file:Suppress("DeprecatedCallableAddReplaceWith")
package ru.dbotthepony.kommons.io
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import ru.dbotthepony.kommons.collect.ProxiedMap
import ru.dbotthepony.kommons.collect.forValidRefs
import ru.dbotthepony.kommons.util.Observer
import ru.dbotthepony.kommons.util.ListenableDelegate
import ru.dbotthepony.kommons.util.DelegateGetter
import ru.dbotthepony.kommons.util.DelegateSetter
import ru.dbotthepony.kommons.util.Listenable
import java.io.ByteArrayOutputStream
import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.InputStream
import java.lang.ref.WeakReference
import java.util.*
import java.util.function.Consumer
import java.util.function.Supplier
/**
* Universal, one-to-many value synchronizer, allowing to synchronize values from server to client
* anywhere, where input/output streams are supported
*/
@Suppress("unused", "BlockingMethodInNonBlockingContext")
class SynchedDelegates(private val callback: Runnable, private val alwaysCallCallback: Boolean) {
constructor() : this(Runnable {}, false)
constructor(callback: Runnable) : this(callback, false)
private var freeSlots = 0
// почему не удалять поля напрямую?
// чтоб не возникло проблем в состоянии гонки
// формируем пакет -> удаляем поле по обе стороны -> клиент принимает пакет -> клиент считывает неверные данные
// конечно, всё равно всё сломается если было удалено поле, которое находится в пакете
// но если поля нет в пакете, то всё окей
private val fields = ArrayList<AbstractValue?>(0)
private val observers = ArrayList<Observer>(0)
private var nextFieldID = 0
val hasObservers: Boolean get() = observers.isNotEmpty()
var isEmpty: Boolean = true
private set
val isNotEmpty: Boolean get() = !isEmpty
var isDirty: Boolean = false
private set(value) {
if (value != field) {
field = value
if (value && !alwaysCallCallback) {
callback.run()
}
}
if (alwaysCallCallback && value) {
callback.run()
}
}
fun markClean() {
isDirty = false
}
private var endpointsMaxCapacity = 1
private val endpoints = ArrayList<WeakReference<Endpoint>>(1)
val defaultEndpoint = Endpoint()
private var lastEndpointCleanup = System.nanoTime()
private fun notifyEndpoints(dirtyField: AbstractValue) {
isDirty = true
forEachEndpoint {
it.addDirty(dirtyField)
}
}
private inline fun forEachEndpoint(execute: (Endpoint) -> Unit) {
synchronized(endpoints) {
endpoints.forValidRefs { execute.invoke(it) }
if (endpoints.size < endpointsMaxCapacity / 2) {
endpoints.trimToSize()
endpointsMaxCapacity = endpoints.size
}
}
}
inner class Endpoint {
init {
synchronized(endpoints) {
endpoints.add(WeakReference(this))
endpointsMaxCapacity = endpointsMaxCapacity.coerceAtLeast(endpoints.size)
if (System.nanoTime() - lastEndpointCleanup <= 60) {
lastEndpointCleanup = System.nanoTime()
val iterator = endpoints.listIterator()
for (value in iterator) {
if (value.get() == null) {
iterator.remove()
}
}
if (endpoints.size < endpointsMaxCapacity / 2) {
endpoints.trimToSize()
endpointsMaxCapacity = endpoints.size
}
}
}
}
private val dirty = ReferenceArraySet<AbstractValue>(4)
// use LinkedList because it is ensured memory is freed on LinkedList#clear
private val mapBacklogs = Reference2ObjectOpenHashMap<Map<*, *>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
private val setBacklogs = Reference2ObjectOpenHashMap<Set<*>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
var unused: Boolean = false
private set
fun markUnused() {
require(this === defaultEndpoint) { "This is not a default endpoint" }
if (unused) return
unused = true
mapBacklogs.clear()
dirty.clear()
val iterator = endpoints.listIterator()
for (value in iterator) {
if (value.get() === this) {
iterator.remove()
}
}
}
init {
markDirty()
}
fun markDirty() {
for (field in fields) {
field?.markDirty(this)
}
}
internal fun addDirty(field: AbstractValue) {
if (unused) {
return
}
dirty.add(field)
}
internal fun removeDirty(field: AbstractValue) {
dirty.remove(field)
}
internal fun <K, V> getMapBacklog(map: Map<K, V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> {
if (unused) {
return LinkedList()
}
return mapBacklogs.computeIfAbsent(map, Reference2ObjectFunction {
LinkedList()
})
}
internal fun <K, V> removeMapBacklog(map: Map<K, V>) {
mapBacklogs.remove(map)
}
internal fun <V> getSetBacklog(set: Set<V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> {
if (unused) {
return LinkedList()
}
return setBacklogs.computeIfAbsent(set, Reference2ObjectFunction {
LinkedList()
})
}
internal fun <V> removeSetBacklog(set: Set<V>) {
setBacklogs.remove(set)
}
fun collectNetworkPayload(): ByteArrayOutputStream? {
if (unused || dirty.isEmpty()) {
return null
}
val stream = ByteArrayOutputStream()
val dataStream = DataOutputStream(stream)
for (field in dirty) {
stream.writeVarInt(field.id)
field.write(dataStream, this)
}
dirty.clear()
stream.write(0)
return stream
}
}
private val boundEndpoints = WeakHashMap<Any, Endpoint>()
fun computeEndpointFor(obj: Any): Endpoint {
return boundEndpoints.computeIfAbsent(obj) { Endpoint() }
}
fun removeEndpointFor(obj: Any): Endpoint? {
return boundEndpoints.remove(obj)
}
fun endpointFor(obj: Any): Endpoint? {
return boundEndpoints[obj]
}
abstract inner class AbstractValue : Observer {
val id: Int
init {
if (freeSlots > 0) {
var found = -1
for (i in fields.indices) {
if (fields[i] == null) {
fields[i] = this
found = i + 1
freeSlots--
break
}
}
if (found == -1) {
throw RuntimeException("freeSlots = $freeSlots but no null entries in field list!")
} else {
id = found
}
} else {
fields.add(this)
id = fields.size
isEmpty = false
}
}
var isRemoved = false
private set
protected var isDirty = false
protected var isRemote = false
open fun remove() {
if (isRemoved)
return
isRemoved = true
freeSlots++
fields[id - 1] = null
observers.remove(this)
isEmpty = fields.all { it == null }
while (fields[fields.size - 1] == null) {
fields.removeAt(fields.size - 1)
freeSlots--
}
forEachEndpoint {
it.removeDirty(this)
}
}
open fun markDirty(endpoint: Endpoint) {
check(!isRemoved) { "Field was removed" }
endpoint.addDirty(this)
}
open fun markDirty() {
check(!isRemoved) { "Field was removed" }
notifyEndpoints(this)
isDirty = true
}
abstract fun write(stream: DataOutputStream, endpoint: Endpoint)
abstract fun read(stream: DataInputStream)
}
inner class RegularValue<T>(
value: T,
private val codec: StreamCodec<T>,
getter: DelegateGetter<T> = DelegateGetter.passthrough(),
setter: DelegateSetter<T> = DelegateSetter.passthrough()
) : AbstractValue(), ListenableDelegate<T> by ListenableDelegate.maskSmart(value, getter, setter) {
init {
addListener(Runnable {
if (!isDirty && !isRemote) {
notifyEndpoints(this)
isDirty = true
}
})
}
override fun observe(): Boolean {
return false
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) {
codec.write(stream, get())
isDirty = false
}
override fun read(stream: DataInputStream) {
isRemote = true
accept(codec.read(stream))
isDirty = false
}
}
inner class ObservedValue<T>(
value: T,
private val codec: StreamCodec<T>,
getter: DelegateGetter<T> = DelegateGetter.passthrough(),
setter: DelegateSetter<T> = DelegateSetter.passthrough()
) : AbstractValue(), ListenableDelegate<T> by ListenableDelegate.maskSmart(value, getter, setter) {
private var observed = codec.copy(value)
init {
observers.add(this)
addListener(Runnable {
if (!isDirty && !isRemote) {
notifyEndpoints(this)
isDirty = true
}
})
}
override fun observe(): Boolean {
if (!isRemote) {
val get = get()
if (!codec.compare(get, observed)) {
observed = codec.copy(get)
isDirty = true
}
}
return isDirty
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) {
codec.write(stream, get())
isDirty = false
}
override fun read(stream: DataInputStream) {
isRemote = true
accept(codec.read(stream))
isDirty = false
}
}
inner class ComputedValue<T>(getter: Supplier<T>, private val codec: StreamCodec<T>) : AbstractValue(), ListenableDelegate<T> {
private val shadow = ListenableDelegate.SmartShadow(getter, codec::compare, codec::copy)
override fun get(): T {
return shadow.get()
}
override fun accept(t: T) {
shadow.accept(t)
}
override fun addListener(listener: Consumer<T>): Listenable.L {
return shadow.addListener(listener)
}
override fun observe(): Boolean {
return shadow.observe()
}
init {
shadow.addListener(Runnable {
if (!isDirty && !isRemote) {
notifyEndpoints(this)
isDirty = true
}
})
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) {
codec.write(stream, shadow.get())
isDirty = false
}
override fun read(stream: DataInputStream) {
isRemote = true
shadow.accept(codec.read(stream))
isDirty = false
}
}
@JvmName("vbyte") fun byte(value: Byte = 0, getter: DelegateGetter<Byte> = DelegateGetter.passthrough(), setter: DelegateSetter<Byte> = DelegateSetter.passthrough()): ListenableDelegate<Byte> = RegularValue(value, ByteValueCodec, getter, setter)
@JvmName("vshort") fun short(value: Short = 0, getter: DelegateGetter<Short> = DelegateGetter.passthrough(), setter: DelegateSetter<Short> = DelegateSetter.passthrough()): ListenableDelegate<Short> = RegularValue(value, ShortValueCodec, getter, setter)
@JvmName("vchar") fun char(value: Char = 0.toChar(), getter: DelegateGetter<Char> = DelegateGetter.passthrough(), setter: DelegateSetter<Char> = DelegateSetter.passthrough()): ListenableDelegate<Char> = RegularValue(value, CharValueCodec, getter, setter)
@JvmName("vint") fun int(value: Int = 0, getter: DelegateGetter<Int> = DelegateGetter.passthrough(), setter: DelegateSetter<Int> = DelegateSetter.passthrough()): ListenableDelegate<Int> = RegularValue(value, IntValueCodec, getter, setter)
@JvmName("vlong") fun long(value: Long = 0L, getter: DelegateGetter<Long> = DelegateGetter.passthrough(), setter: DelegateSetter<Long> = DelegateSetter.passthrough()): ListenableDelegate<Long> = RegularValue(value, LongValueCodec, getter, setter)
@JvmName("vfloat") fun float(value: Float = 0f, getter: DelegateGetter<Float> = DelegateGetter.passthrough(), setter: DelegateSetter<Float> = DelegateSetter.passthrough()): ListenableDelegate<Float> = RegularValue(value, FloatValueCodec, getter, setter)
@JvmName("vdouble") fun double(value: Double = 0.0, getter: DelegateGetter<Double> = DelegateGetter.passthrough(), setter: DelegateSetter<Double> = DelegateSetter.passthrough()): ListenableDelegate<Double> = RegularValue(value, DoubleValueCodec, getter, setter)
@JvmName("vboolean") fun boolean(value: Boolean = false, getter: DelegateGetter<Boolean> = DelegateGetter.passthrough(), setter: DelegateSetter<Boolean> = DelegateSetter.passthrough()): ListenableDelegate<Boolean> = RegularValue(value, BooleanValueCodec, getter, setter)
fun string(value: String, getter: DelegateGetter<String> = DelegateGetter.passthrough(), setter: DelegateSetter<String> = DelegateSetter.passthrough()): ListenableDelegate<String> = RegularValue(value, BinaryStringCodec, getter, setter)
fun uuid(value: UUID, getter: DelegateGetter<UUID> = DelegateGetter.passthrough(), setter: DelegateSetter<UUID> = DelegateSetter.passthrough()): ListenableDelegate<UUID> = RegularValue(value, UUIDValueCodec, getter, setter)
inner class Set<E>(
private val codec: StreamCodec<E>,
private val backingSet: MutableSet<E>,
private val callback: ((changes: Collection<SetChangeset<E>>) -> Unit)? = null,
) : AbstractValue() {
private fun pushBacklog(element: E, action: (DataOutputStream) -> Unit) {
check(!isRemote) { "Field marked as remote" }
val pair = element to action
forEachEndpoint {
val list = it.getSetBacklog(this)
val iterator = list.listIterator()
for (value in iterator) {
if (value.first == element) {
iterator.remove()
}
}
list.addLast(pair)
}
}
override fun observe(): Boolean {
return false
}
override fun remove() {
if (!isRemoved) {
forEachEndpoint { it.removeSetBacklog(this) }
}
super.remove()
}
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
if (isRemote || endpoints.isEmpty())
return
isDirty = true
val endpoints = LinkedList<MutableList<Pair<Any?, (DataOutputStream) -> Unit>>>()
forEachEndpoint {
endpoints.add(it.getSetBacklog(this))
it.addDirty(this)
}
endpoints.forEach {
it.clear()
it.add(null to ClearBacklogEntry)
}
for (value in backingSet) {
val valueCopy = codec.copy(value)
val pair: Pair<Any?, (DataOutputStream) -> Unit> = valueCopy to { it.write(ChangesetAction.ADD.ordinal + 1); codec.write(it, valueCopy) }
endpoints.forEach {
it.add(pair)
}
}
}
override fun markDirty(endpoint: Endpoint) {
super.markDirty(endpoint)
endpoint.getSetBacklog(this).let {
it.clear()
it.add(null to ClearBacklogEntry)
for (value in backingSet) {
val valueCopy = codec.copy(value)
it.add(valueCopy to { it.write(ChangesetAction.ADD.ordinal + 1); codec.write(it, valueCopy) })
}
}
}
val value: MutableSet<E> = object : MutableSet<E> {
override fun add(element: E): Boolean {
if (backingSet.add(element)) {
if (!isRemote) {
markDirty()
val copy = codec.copy(element)
pushBacklog(element) {
it.write(ChangesetAction.ADD.ordinal + 1)
codec.write(it, copy)
}
}
return true
}
return false
}
override fun addAll(elements: Collection<E>): Boolean {
var any = false
elements.forEach { any = add(it) || any }
return any
}
override fun clear() {
if (backingSet.isNotEmpty()) {
backingSet.clear()
if (!isRemote) {
markDirty()
forEachEndpoint {
it.getSetBacklog(this@Set).let {
it.clear()
it.add(null to ClearBacklogEntry)
}
}
}
}
}
override fun iterator(): MutableIterator<E> {
return object : MutableIterator<E> {
private val parent = backingSet.iterator()
private var lastElement: Any? = Mark
override fun hasNext(): Boolean {
return parent.hasNext()
}
override fun next(): E {
return parent.next().also { lastElement = it }
}
override fun remove() {
parent.remove()
val lastElement = lastElement
if (lastElement !== Mark) {
this.lastElement = Mark
if (!isRemote) {
markDirty()
@Suppress("unchecked_cast")
pushBacklog(lastElement as E) {
it.write(ChangesetAction.REMOVE.ordinal + 1)
codec.write(it, lastElement as E)
}
}
}
}
}
}
override fun remove(element: E): Boolean {
if (backingSet.remove(element)) {
if (!isRemote) {
markDirty()
val copy = codec.copy(element)
pushBacklog(element) {
it.write(ChangesetAction.REMOVE.ordinal + 1)
codec.write(it, copy)
}
}
return true
}
return false
}
override fun removeAll(elements: Collection<E>): Boolean {
var any = false
elements.forEach { any = remove(it) || any }
return any
}
override fun retainAll(elements: Collection<E>): Boolean {
var any = false
val iterator = iterator()
for (value in iterator) {
if (value !in elements) {
any = true
iterator.remove()
}
}
return any
}
override val size: Int
get() = backingSet.size
override fun contains(element: E): Boolean {
return element in backingSet
}
override fun containsAll(elements: Collection<E>): Boolean {
return backingSet.containsAll(elements)
}
override fun isEmpty(): Boolean {
return backingSet.isEmpty()
}
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) {
val list = endpoint.getSetBacklog(this)
for (value in list) {
value.second.invoke(stream)
}
stream.write(0)
list.clear()
isDirty = false
}
override fun read(stream: DataInputStream) {
if (!isRemote) {
isRemote = true
forEachEndpoint { it.removeSetBacklog(this) }
}
isDirty = false
var action = stream.read()
val changeset = LinkedList<SetChangeset<E>>()
while (action != 0) {
if ((action - 1) !in ChangesetActionList.indices) {
throw IllegalArgumentException("Unknown changeset action with index ${action - 1}")
}
when (ChangesetActionList[action - 1]) {
ChangesetAction.CLEAR -> {
changeset.add(SetChangeset(ChangesetAction.CLEAR, null))
backingSet.clear()
}
ChangesetAction.ADD -> {
val read = codec.read(stream)
changeset.add(SetChangeset(ChangesetAction.ADD, read))
backingSet.add(read)
}
ChangesetAction.REMOVE -> {
val read = codec.read(stream)
changeset.add(SetChangeset(ChangesetAction.REMOVE, read))
backingSet.remove(read)
}
}
action = stream.read()
}
callback?.invoke(changeset)
}
}
inner class Map<K, V>(
private val keyCodec: StreamCodec<K>,
private val valueCodec: StreamCodec<V>,
private val backingMap: MutableMap<K, V>,
private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
) : AbstractValue() {
private var sentAllValues = false
private fun pushBacklog(key: Any?, value: (DataOutputStream) -> Unit) {
val pair = key to value
forEachEndpoint {
val list = it.getMapBacklog(this)
val iterator = list.listIterator()
for (e in iterator) {
if (e.first == key) {
iterator.remove()
}
}
list.addLast(pair)
}
}
override fun observe(): Boolean {
return false
}
override fun markDirty() {
check(!isRemoved) { "Field was removed" }
if (isRemote || endpoints.isEmpty())
return
isDirty = true
val backlogs = LinkedList<LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
forEachEndpoint {
it.addDirty(this)
val value = it.getMapBacklog(this)
backlogs.add(value)
value.clear()
value.add(null to ClearBacklogEntry)
}
for ((key, value) in backingMap) {
val valueCopy = valueCodec.copy(value)
val action = key to { it: DataOutputStream ->
it.write(ChangesetAction.ADD.ordinal + 1)
keyCodec.write(it, key)
valueCodec.write(it, valueCopy)
}
for (backlog in backlogs) {
backlog.add(action)
}
}
}
override fun markDirty(endpoint: Endpoint) {
check(!isRemoved) { "Field was removed" }
if (isRemote)
return
val backlog = endpoint.getMapBacklog(this)
backlog.clear()
backlog.add(null to ClearBacklogEntry)
for ((key, value) in backingMap) {
val valueCopy = valueCodec.copy(value)
backlog.add(key to {
it.write(ChangesetAction.ADD.ordinal + 1)
keyCodec.write(it, key)
valueCodec.write(it, valueCopy)
})
}
}
private fun lmarkDirty() {
if (!isDirty) {
notifyEndpoints(this@Map)
isDirty = true
}
}
val value: MutableMap<K, V> = object : ProxiedMap<K, V>(backingMap) {
override fun onClear() {
if (isRemote || endpoints.isEmpty())
return
forEachEndpoint { endpoint ->
endpoint.getMapBacklog(this@Map).let {
it.clear()
it.add(null to ClearBacklogEntry)
}
}
lmarkDirty()
this@SynchedDelegates.isDirty = true
}
override fun onValueAdded(key: K, value: V) {
if (isRemote || endpoints.isEmpty())
return
val keyCopy = keyCodec.copy(key)
val valueCopy = valueCodec.copy(value)
pushBacklog(key) {
it.write(ChangesetAction.ADD.ordinal + 1)
keyCodec.write(it, keyCopy)
valueCodec.write(it, valueCopy)
}
lmarkDirty()
}
override fun onValueRemoved(key: K, value: V) {
if (isRemote || endpoints.isEmpty())
return
val keyCopy = keyCodec.copy(key)
pushBacklog(key) {
it.write(ChangesetAction.REMOVE.ordinal + 1)
keyCodec.write(it, keyCopy)
}
lmarkDirty()
}
}
override fun write(stream: DataOutputStream, endpoint: Endpoint) {
sentAllValues = false
isDirty = false
val iterator = endpoint.getMapBacklog(this).listIterator()
for (entry in iterator) {
entry.second.invoke(stream)
iterator.remove()
}
stream.write(0)
}
override fun read(stream: DataInputStream) {
if (!isRemote) {
isRemote = true
forEachEndpoint { it.removeMapBacklog(this) }
}
isDirty = false
val changeset = LinkedList<MapChangeset<K, V>>()
var readAction = stream.read() - 1
while (readAction != -1) {
if (readAction >= ChangesetActionList.size) {
throw IndexOutOfBoundsException("Unknown map action with ID $readAction")
}
when (ChangesetActionList[readAction]) {
ChangesetAction.CLEAR -> {
backingMap.clear()
changeset.add(ClearMapChangeset)
}
ChangesetAction.ADD -> {
val key = keyCodec.read(stream)
val value = valueCodec.read(stream)
backingMap[key] = value
changeset.add(MapChangeset(ChangesetAction.ADD, key, value))
}
ChangesetAction.REMOVE -> {
val key = keyCodec.read(stream)
backingMap.remove(key)
changeset.add(MapChangeset(ChangesetAction.REMOVE, key, null))
}
}
readAction = stream.read() - 1
}
if (changeset.size != 0) {
callback?.invoke(changeset)
}
}
}
/**
* marks all fields dirty, invalidates mappings for each endpoint
*/
fun invalidate() {
for (field in fields) {
field?.markDirty()
}
}
/**
* Observe changes of all fields with backing computation lambda
*/
fun observe(): Boolean {
var changes = false
if (observers.isNotEmpty()) {
for (field in observers) {
changes = field.observe() || changes
}
}
return changes
}
/**
* [defaultEndpoint]#collectNetworkPayload
*/
fun collectNetworkPayload(): ByteArrayOutputStream? {
check(!defaultEndpoint.unused) { "Default endpoint is not used" }
observe()
val values = defaultEndpoint.collectNetworkPayload()
markClean()
return values
}
fun read(stream: InputStream): Int {
var fieldId = stream.readVarInt()
var i = 0
val dataStream = DataInputStream(stream)
while (fieldId != 0) {
val field = fields.getOrNull(fieldId - 1) ?: throw IllegalArgumentException("Unknown field ID ${fieldId - 1}")
field.read(dataStream)
fieldId = stream.readVarInt()
i++
}
return i
}
private object Mark
companion object {
private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(ChangesetAction.CLEAR.ordinal + 1) }
private val ChangesetActionList = ChangesetAction.values()
private val ClearMapChangeset = MapChangeset(ChangesetAction.CLEAR, null, null)
}
}

View File

@ -3,10 +3,10 @@
package ru.dbotthepony.kommons.math
import ru.dbotthepony.kommons.core.IStruct2d
import ru.dbotthepony.kommons.core.IStruct2f
import ru.dbotthepony.kommons.core.IStruct2i
import ru.dbotthepony.kommons.core.IStruct2l
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct2l
private inline fun span(x0: Float, x1: Float): Float {
return x1 - x0

View File

@ -1,6 +1,6 @@
package ru.dbotthepony.kommons.math
import ru.dbotthepony.kommons.core.IStruct4f
import ru.dbotthepony.kommons.util.IStruct4f
import kotlin.math.roundToInt
private fun hex(value: Int): String {

View File

@ -1,41 +0,0 @@
package ru.dbotthepony.kommons.networking
interface FieldAccess<V> {
fun read(): V
fun write(value: V)
}
interface FloatFieldAccess : FieldAccess<Float> {
override fun write(value: Float)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readFloat()"))
override fun read() = readFloat()
fun readFloat(): Float
}
interface DoubleFieldAccess : FieldAccess<Double> {
override fun write(value: Double)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readDouble()"))
override fun read() = readDouble()
fun readDouble(): Double
}
interface IntFieldAccess : FieldAccess<Int> {
override fun write(value: Int)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readInt()"))
override fun read() = readInt()
fun readInt(): Int
}
interface LongFieldAccess : FieldAccess<Long> {
override fun write(value: Long)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readLong()"))
override fun read() = readLong()
fun readLong(): Long
}
interface BooleanFieldAccess : FieldAccess<Boolean> {
override fun write(value: Boolean)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readBoolean()"))
override fun read() = readBoolean()
fun readBoolean(): Boolean
}

View File

@ -1,50 +0,0 @@
package ru.dbotthepony.kommons.networking
fun interface FieldGetter<V> {
fun invoke(field: FieldAccess<V>): V
}
fun interface FloatFieldGetter : FieldGetter<Float> {
fun invoke(field: FloatFieldAccess): Float
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Float>): Float {
return invoke(field as FloatFieldAccess)
}
}
fun interface DoubleFieldGetter : FieldGetter<Double> {
fun invoke(field: DoubleFieldAccess): Double
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Double>): Double {
return invoke(field as DoubleFieldAccess)
}
}
fun interface IntFieldGetter : FieldGetter<Int> {
fun invoke(field: IntFieldAccess): Int
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Int>): Int {
return invoke(field as IntFieldAccess)
}
}
fun interface LongFieldGetter : FieldGetter<Long> {
fun invoke(field: LongFieldAccess): Long
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Long>): Long {
return invoke(field as LongFieldAccess)
}
}
fun interface BooleanFieldGetter : FieldGetter<Boolean> {
fun invoke(field: BooleanFieldAccess): Boolean
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Boolean>): Boolean {
return invoke(field as BooleanFieldAccess)
}
}

View File

@ -1,50 +0,0 @@
package ru.dbotthepony.kommons.networking
fun interface FieldSetter<V> {
fun invoke(value: V, access: FieldAccess<V>, setByRemote: Boolean)
}
fun interface FloatFieldSetter : FieldSetter<Float> {
fun invoke(value: Float, access: FloatFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Float, access: FieldAccess<Float>, setByRemote: Boolean) {
invoke(value, access as FloatFieldAccess, setByRemote)
}
}
fun interface DoubleFieldSetter : FieldSetter<Double> {
fun invoke(value: Double, access: DoubleFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Double, access: FieldAccess<Double>, setByRemote: Boolean) {
invoke(value, access as DoubleFieldAccess, setByRemote)
}
}
fun interface IntFieldSetter : FieldSetter<Int> {
fun invoke(value: Int, access: IntFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Int, access: FieldAccess<Int>, setByRemote: Boolean) {
invoke(value, access as IntFieldAccess, setByRemote)
}
}
fun interface LongFieldSetter : FieldSetter<Long> {
fun invoke(value: Long, access: LongFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Long, access: FieldAccess<Long>, setByRemote: Boolean) {
invoke(value, access as LongFieldAccess, setByRemote)
}
}
fun interface BooleanFieldSetter : FieldSetter<Boolean> {
fun invoke(value: Boolean, access: BooleanFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Boolean, access: FieldAccess<Boolean>, setByRemote: Boolean) {
invoke(value, access as BooleanFieldAccess, setByRemote)
}
}

View File

@ -1,173 +0,0 @@
package ru.dbotthepony.kommons.networking
import ru.dbotthepony.kommons.event.IBooleanSubscriptable
import ru.dbotthepony.kommons.event.IDoubleSubcriptable
import ru.dbotthepony.kommons.event.IFloatSubcriptable
import ru.dbotthepony.kommons.event.IIntSubcriptable
import ru.dbotthepony.kommons.event.ILongSubcriptable
import ru.dbotthepony.kommons.event.ISubscriptable
import ru.dbotthepony.kommons.util.FloatSupplier
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.function.BooleanSupplier
import java.util.function.DoubleSupplier
import java.util.function.IntSupplier
import java.util.function.LongSupplier
import java.util.function.Supplier
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
sealed interface IField<V> : ReadOnlyProperty<Any?, V>, Supplier<V>, () -> V, ISubscriptable<V> {
fun observe(): Boolean
fun markDirty()
fun markDirty(endpoint: FieldSynchronizer.Endpoint)
val value: V
val isRemoved: Boolean
fun remove()
fun write(stream: DataOutputStream, endpoint: FieldSynchronizer.Endpoint)
fun read(stream: DataInputStream)
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return this.value
}
override fun get(): V {
return value
}
override fun invoke(): V {
return value
}
}
interface IFloatProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Float
}
sealed interface IFloatField : IField<Float>, FloatSupplier, IFloatSubcriptable {
val float: Float
val property: IFloatProperty
override val value: Float
get() = float
@Deprecated("Use type specific Supplier interface")
override fun get(): Float {
return float
}
override fun getAsFloat(): Float {
return float
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
return float
}
}
interface IDoubleProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Double
}
sealed interface IDoubleField : IField<Double>, DoubleSupplier, IDoubleSubcriptable {
val double: Double
val property: IDoubleProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Double {
return double
}
override val value: Double
get() = double
override fun getAsDouble(): Double {
return double
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
return double
}
}
interface IIntProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int
}
sealed interface IIntField : IField<Int>, IntSupplier, IIntSubcriptable {
val int: Int
val property: IIntProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Int {
return int
}
override val value: Int
get() = int
override fun getAsInt(): Int {
return int
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return int
}
}
interface ILongProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Long
}
sealed interface ILongField : IField<Long>, LongSupplier, ILongSubcriptable {
val long: Long
val property: ILongProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Long {
return long
}
override val value: Long
get() = long
override fun getAsLong(): Long {
return long
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
return long
}
}
interface IBooleanProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean
}
sealed interface IBooleanField : IField<Boolean>, BooleanSupplier, IBooleanSubscriptable {
val boolean: Boolean
val property: IBooleanProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Boolean {
return boolean
}
override val value: Boolean
get() = boolean
override fun getAsBoolean(): Boolean {
return boolean
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return boolean
}
}

View File

@ -1,165 +0,0 @@
package ru.dbotthepony.kommons.networking
import it.unimi.dsi.fastutil.booleans.BooleanConsumer
import it.unimi.dsi.fastutil.floats.FloatConsumer
import ru.dbotthepony.kommons.core.SentientGetterSetter
import java.util.function.DoubleConsumer
import java.util.function.IntConsumer
import java.util.function.LongConsumer
import kotlin.reflect.KProperty
sealed interface IMutableField<V> : IField<V>, SentientGetterSetter<V> {
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return this.value
}
override var value: V
override fun accept(t: V) {
value = t
}
override fun invoke(): V {
return this.value
}
}
interface IMutableFloatProperty : IFloatProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Float)
}
sealed interface IMutableFloatField : IMutableField<Float>, IFloatField, FloatConsumer {
override var float: Float
override val property: IMutableFloatProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.float"))
override var value: Float
get() = float
set(value) { float = value }
override fun accept(t: Float) {
float = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
return float
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Float) {
float = value
}
}
interface IMutableDoubleProperty : IDoubleProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Double)
}
sealed interface IMutableDoubleField : IMutableField<Double>, IDoubleField, DoubleConsumer {
override var double: Double
override val property: IMutableDoubleProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.double"))
override var value: Double
get() = double
set(value) { double = value }
override fun accept(t: Double) {
double = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
return double
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Double) {
double = value
}
}
interface IMutableIntProperty : IIntProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int)
}
sealed interface IMutableIntField : IMutableField<Int>, IIntField, IntConsumer {
override var int: Int
override val property: IMutableIntProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.int"))
override var value: Int
get() = int
set(value) { int = value }
override fun accept(t: Int) {
int = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return int
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
int = value
}
}
interface IMutableLongProperty : ILongProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Long)
}
sealed interface IMutableLongField : IMutableField<Long>, ILongField, LongConsumer {
override var long: Long
override val property: IMutableLongProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.long"))
override var value: Long
get() = long
set(value) { long = value }
override fun accept(t: Long) {
long = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
return long
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Long) {
long = value
}
}
interface IMutableBooleanProperty : IBooleanProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean)
}
sealed interface IMutableBooleanField : IMutableField<Boolean>, IBooleanField, BooleanConsumer {
override var boolean: Boolean
override val property: IMutableBooleanProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.boolean"))
override var value: Boolean
get() = boolean
set(value) { boolean = value }
override fun accept(t: Boolean) {
boolean = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return boolean
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
boolean = value
}
}

View File

@ -0,0 +1,64 @@
@file:Suppress("UsePropertyAccessSyntax")
package ru.dbotthepony.kommons.util
import java.util.function.Consumer
import java.util.function.Supplier
import kotlin.reflect.KProperty
/**
* [Supplier] and [Consumer] combined in single interface
*/
interface Delegate<V> : Supplier<V>, Consumer<V> {
class UnboundBox<V> : Delegate<V> {
private var value: Any? = Companion
override fun get(): V {
val get = value
if (get === Companion) throw UninitializedPropertyAccessException()
return get as V
}
override fun accept(t: V) {
value = t
}
private companion object
}
class Box<V>(private var value: V) : Delegate<V> {
override fun get(): V {
return value
}
override fun accept(t: V) {
value = t
}
}
class SmartBox<V>(value: V, private val getter: DelegateGetter<V>, private val setter: DelegateSetter<V>) : Delegate<V> {
private val value = Box(value)
override fun get(): V {
return getter(value)
}
override fun accept(t: V) {
setter(value, t)
}
}
class Of<V>(getter: Supplier<V>, setter: Consumer<V>) : Delegate<V>, Supplier<V> by getter, Consumer<V> by setter
}
operator fun <V> Supplier<V>.getValue(ref: Any?, property: KProperty<*>): V {
return get()
}
operator fun <V> Consumer<V>.setValue(ref: Any?, property: KProperty<*>, value: V) {
accept(value)
}
var <V> Delegate<V>.value: V
get() = get()
set(value) { accept(value) }

View File

@ -0,0 +1,17 @@
package ru.dbotthepony.kommons.util
fun interface DelegateGetter<V> {
operator fun invoke(field: Delegate<V>): V
private object PASSTHROUGH : DelegateGetter<Any?> {
override fun invoke(field: Delegate<Any?>): Any? {
return field.get()
}
}
companion object {
fun <V> passthrough(): DelegateGetter<V> {
return PASSTHROUGH as DelegateGetter<V>
}
}
}

View File

@ -0,0 +1,17 @@
package ru.dbotthepony.kommons.util
fun interface DelegateSetter<V> {
operator fun invoke(field: Delegate<V>, value: V)
private object PASSTHROUGH : DelegateSetter<Any?> {
override fun invoke(field: Delegate<Any?>, value: Any?) {
field.accept(value)
}
}
companion object {
fun <V> passthrough(): DelegateSetter<V> {
return PASSTHROUGH as DelegateSetter<V>
}
}
}

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kommons.core
package ru.dbotthepony.kommons.util
/**
* Implements a value container which contain either [L] or [R] value

View File

@ -1,12 +0,0 @@
package ru.dbotthepony.kommons.util
import java.util.function.Supplier
fun interface FloatSupplier : Supplier<Float> {
fun getAsFloat(): Float
@Deprecated("Use type-specific method", replaceWith = ReplaceWith("this.getAsFloat()"))
override fun get(): Float {
return getAsFloat()
}
}

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kommons.core
package ru.dbotthepony.kommons.util
import java.util.function.Supplier

View File

@ -0,0 +1,100 @@
package ru.dbotthepony.kommons.util
import java.util.concurrent.CopyOnWriteArrayList
import java.util.function.Consumer
interface Listenable<V> {
/**
* Listener token, allows to remove listener from subscriber list
*/
fun interface L {
/**
* Removes this listener
*/
fun remove()
}
fun addListener(listener: Runnable): L {
return addListener(Consumer { listener.run() })
}
fun addListener(listener: Consumer<V>): L
/**
* Adding and removing listeners is thread-safe.
*/
class Impl<V> : Listenable<V>, Consumer<V> {
private inner class L(val callback: Consumer<V>) : Listenable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
subscribers.remove(this)
}
}
}
private val subscribers = CopyOnWriteArrayList<L>()
override fun addListener(listener: Consumer<V>): Listenable.L {
return L(listener)
}
override fun accept(t: V) {
subscribers.forEach { it.callback.accept(t) }
}
}
class Void : Listenable<Unit>, Runnable {
private inner class L(val callback: Runnable) : Listenable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
subscribers.remove(this)
}
}
}
private val subscribers = CopyOnWriteArrayList<L>()
override fun addListener(listener: Runnable): Listenable.L {
return L(listener)
}
override fun addListener(listener: Consumer<Unit>): Listenable.L {
return L(Runnable { listener.accept(Unit) })
}
override fun run() {
subscribers.forEach { it.callback.run() }
}
}
companion object : Listenable<Nothing>, L {
@Suppress("unchecked_cast")
fun <T> empty(): Listenable<T> {
return this as Listenable<T>
}
override fun remove() {}
override fun addListener(listener: Consumer<Nothing>): L {
return this
}
override fun addListener(listener: Runnable): L {
return this
}
}
}

View File

@ -0,0 +1,177 @@
package ru.dbotthepony.kommons.util
import java.util.concurrent.locks.ReentrantLock
import java.util.function.Consumer
import java.util.function.Supplier
import kotlin.concurrent.withLock
interface ListenableDelegate<V> : Delegate<V>, Listenable<V> {
class UnboundBox<V> : ListenableDelegate<V> {
private var value: Any? = Companion
private val listeners = Listenable.Impl<V>()
override fun addListener(listener: Consumer<V>): Listenable.L {
return listeners.addListener(listener)
}
override fun get(): V {
val get = value
if (get === Companion) throw UninitializedPropertyAccessException()
return get as V
}
override fun accept(t: V) {
value = t
}
private companion object
}
class Box<V>(private var value: V) : ListenableDelegate<V> {
private val listeners = Listenable.Impl<V>()
override fun addListener(listener: Consumer<V>): Listenable.L {
return listeners.addListener(listener)
}
override fun get(): V {
return value
}
override fun accept(t: V) {
if (value != t) {
value = t
listeners.accept(t)
}
}
}
class SmartBox<V>(value: V, private val getter: DelegateGetter<V>, private val setter: DelegateSetter<V>) : ListenableDelegate<V> {
private val value = Box(value)
override fun addListener(listener: Consumer<V>): Listenable.L {
return value.addListener(listener)
}
override fun get(): V {
return getter(value)
}
override fun accept(t: V) {
setter(value, t)
}
}
abstract class AbstractShadow<V>(private val parent: Supplier<V>) : ListenableDelegate<V>, ValueObserver<V> {
@Volatile
private var shadow: Any? = Companion
@Volatile
private var observed: Any? = Companion
private val listeners = Listenable.Impl<V>()
private val lock = ReentrantLock()
protected abstract fun compare(a: V, b: V): Boolean
protected abstract fun copy(value: V): V
override fun get(): V {
if (shadow !== Companion) {
return shadow as V
}
return parent.get()
}
override fun accept(t: V) {
val shadow = shadow
this.shadow = t
if (shadow != t) {
listeners.accept(t)
}
}
override fun addListener(listener: Consumer<V>): Listenable.L {
return listeners.addListener(listener)
}
override fun observe(): Boolean {
if (shadow !== Companion)
return false
val get = parent.get()
if (observed === Companion || !compare(observed as V, get)) {
lock.withLock {
if (shadow !== Companion)
return false
if (observed === Companion || !compare(observed as V, get)) {
observed = copy(get)
listeners.accept(get)
return true
}
}
}
return false
}
override fun getAndObserve(): Pair<V, Boolean> {
if (shadow !== Companion)
return (shadow as V) to false
val get = parent.get()
if (observed === Companion || !compare(observed as V, get)) {
lock.withLock {
if (shadow !== Companion)
return (shadow as V) to false
if (observed === Companion || !compare(observed as V, get)) {
observed = copy(get)
listeners.accept(get)
return get to true
}
}
}
return get to false
}
private companion object
}
class Shadow<V>(parent: Supplier<V>) : AbstractShadow<V>(parent) {
override fun compare(a: V, b: V): Boolean {
return a == b
}
override fun copy(value: V): V {
return value
}
}
class SmartShadow<V>(parent: Supplier<V>, private val comparator: (V, V) -> Boolean, private val copy: (V) -> V) : AbstractShadow<V>(parent) {
override fun compare(a: V, b: V): Boolean {
return comparator(a, b)
}
override fun copy(value: V): V {
return copy.invoke(value)
}
}
companion object {
/**
* Returns smart box if [getter] or [setter] is not passthrough
*/
@JvmStatic
fun <V> maskSmart(value: V, getter: DelegateGetter<V>, setter: DelegateSetter<V>): ListenableDelegate<V> {
if (getter === DelegateGetter.passthrough<V>() && setter === DelegateSetter.passthrough<V>()) {
return Box(value)
} else {
return SmartBox(value, getter, setter)
}
}
}
}

View File

@ -0,0 +1,11 @@
package ru.dbotthepony.kommons.util
/**
* Observes upstream value for changes when [observe] is called
*/
interface Observer {
/**
* Returns true if value changed since last observation.
*/
fun observe(): Boolean
}

View File

@ -1,7 +1,7 @@
@file:Suppress("unused")
package ru.dbotthepony.kommons.core
package ru.dbotthepony.kommons.util
interface IStruct2f {
operator fun component1(): Float

View File

@ -0,0 +1,157 @@
package ru.dbotthepony.kommons.util
import java.util.concurrent.locks.ReentrantLock
import java.util.function.Consumer
import java.util.function.Supplier
import kotlin.concurrent.withLock
interface ValueObserver<V> : Listenable<V>, Supplier<V>, Observer {
fun getAndObserve(): Pair<V, Boolean>
/**
* Notifies listeners when value returned by [provider] changes.
*
* Observation happen on [get] call, or on [observe]/[getAndObserve].
*
* This implementation is not synchronized, calls to [get]/[observe]/[getAndObserve] from multiple threads
* will result in undefined behavior;
* For thread-safe implementation, use [SynchronizedObserved].
*/
class Impl<V>(private val provider: Supplier<V>) : ValueObserver<V> {
private val subs = Listenable.Impl<V>()
private var observed: Any? = Companion
override fun addListener(listener: Consumer<V>): Listenable.L {
return subs.addListener(listener)
}
/**
* Returns last observed value or observes it if it were never observed before
*/
fun getObserved(): V {
if (observed === Companion) {
return get()
}
return observed as V
}
override fun get(): V {
val get = provider.get()
if (get != observed) {
observed = get
subs.accept(get)
}
return get
}
override fun observe(): Boolean {
val get = provider.get()
if (get != observed) {
observed = get
subs.accept(get)
return true
}
return false
}
/**
* Returns pair representing value and if value changed since last observation.
*/
override fun getAndObserve(): Pair<V, Boolean> {
val get = provider.get()
if (get != observed) {
observed = get
subs.accept(get)
return get to true
}
return get to false
}
private companion object
}
/**
* Notifies listeners when value returned by [provider] changes.
*
* Observation happen on [get] call, or on [observe]/[getAndObserve].
*/
class SynchronizedImpl<V>(private val provider: Supplier<V>) : ValueObserver<V> {
private val subs = Listenable.Impl<V>()
private val lock = ReentrantLock() // reentrant lock to avoid deadlock when doing observe -> listeners triggered -> listeners call observe
private var observed: Any? = Companion
override fun addListener(listener: Consumer<V>): Listenable.L {
return subs.addListener(listener)
}
/**
* Returns last observed value or observes it if it were never observed before
*/
fun getObserved(): V {
if (observed === Companion) {
return get()
}
return observed as V
}
override fun get(): V {
val get = provider.get()
if (get != observed) {
lock.withLock {
if (get != observed) {
observed = get
subs.accept(get)
}
}
}
return get
}
override fun observe(): Boolean {
val get = provider.get()
if (get != observed) {
lock.withLock {
if (get != observed) {
observed = get
subs.accept(get)
return true
}
}
}
return false
}
/**
* Returns pair representing value and if value changed since last observation.
*/
override fun getAndObserve(): Pair<V, Boolean> {
val get = provider.get()
if (get != observed) {
lock.withLock {
if (get != observed) {
observed = get
subs.accept(get)
return get to true
}
}
}
return get to false
}
private companion object
}
}