diff --git a/AsyncSocket/build.gradle b/AsyncSocket/build.gradle index c6107f7..90e629e 100644 --- a/AsyncSocket/build.gradle +++ b/AsyncSocket/build.gradle @@ -1,7 +1,9 @@ dependencies { compile project(":") + compile project(":log") // kotlin 协程 compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9' + compile project(":log") testRuntime group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-debug', version: '1.3.9' } \ No newline at end of file diff --git a/AsyncSocket/src/main/kotlin/cn/tursom/niothread/loophandler/MultithreadingBossLoopHandler.kt b/AsyncSocket/src/main/kotlin/cn/tursom/niothread/loophandler/MultithreadingBossLoopHandler.kt index 9cfa714..666ab3c 100644 --- a/AsyncSocket/src/main/kotlin/cn/tursom/niothread/loophandler/MultithreadingBossLoopHandler.kt +++ b/AsyncSocket/src/main/kotlin/cn/tursom/niothread/loophandler/MultithreadingBossLoopHandler.kt @@ -1,10 +1,9 @@ package cn.tursom.niothread.loophandler -import cn.tursom.core.randomInt -import cn.tursom.niothread.NioThread +import cn.tursom.core.Utils import cn.tursom.niothread.NioProtocol +import cn.tursom.niothread.NioThread import java.nio.channels.SelectionKey -import java.nio.channels.ServerSocketChannel class MultithreadingBossLoopHandler( protocol: NioProtocol, @@ -14,7 +13,7 @@ class MultithreadingBossLoopHandler( val workerThread: NioThread = if (workerThread.isEmpty()) { nioThread } else { - workerThread[randomInt(0, workerThread.size - 1)] + workerThread[Utils.random.nextInt(0, workerThread.size - 1)] } handle(nioThread, key, workerThread) } diff --git a/AsyncSocket/src/test/kotlin/cn/tursom/datagram/server/test.kt b/AsyncSocket/src/test/kotlin/cn/tursom/datagram/server/test.kt index a3a73cb..7a1fa83 100644 --- a/AsyncSocket/src/test/kotlin/cn/tursom/datagram/server/test.kt +++ b/AsyncSocket/src/test/kotlin/cn/tursom/datagram/server/test.kt @@ -1,17 +1,19 @@ package cn.tursom.datagram.server import cn.tursom.channel.BufferedAsyncChannel -import cn.tursom.core.log import cn.tursom.core.pool.DirectMemoryPool import cn.tursom.datagram.AsyncDatagramClient +import cn.tursom.log.impl.Slf4jImpl import cn.tursom.socket.NioClient import cn.tursom.socket.server.BuffedNioServer import kotlinx.coroutines.runBlocking +val logger = Slf4jImpl.getLogger() + val echoHandler: suspend BufferedAsyncChannel.() -> Unit = { while (true) { val buffer = read() - log("$this recv from client $remoteAddress: ${buffer.toString(buffer.readable)}") + logger.debug("$this recv from client $remoteAddress: ${buffer.toString(buffer.readable)}") Throwable().printStackTrace() write(buffer) } @@ -52,7 +54,7 @@ fun main() { client.write(line) client.read(3000) } - log("recv from server: ${read.getString()}") + logger.debug("recv from server: ${read.getString()}") read.close() } catch (e: Exception) { Exception(e).printStackTrace() diff --git a/build.gradle b/build.gradle index a846c3e..a3d5487 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = '1.4.0' + ext.kotlinVersion = '1.4.31' repositories { mavenLocal() @@ -28,14 +28,18 @@ allprojects { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" + api "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" + api "com.google.code.gson:gson:2.8.2" testImplementation group: 'junit', name: 'junit', version: '4.12' } compileKotlin { kotlinOptions.jvmTarget = "1.8" + kotlinOptions.useIR = true } compileTestKotlin { kotlinOptions.jvmTarget = "1.8" + kotlinOptions.useIR = true } //打包源代码 @@ -66,4 +70,11 @@ allprojects { } } } + sourceSets { + all { + languageSettings { + useExperimentalAnnotation('-Xopt-in=kotlin.RequiresOptIn') + } + } + } } diff --git a/log/src/main/kotlin/cn/tursom/log/LogUtils.kt b/log/src/main/kotlin/cn/tursom/log/LogUtils.kt index 23c3f8d..68b86da 100644 --- a/log/src/main/kotlin/cn/tursom/log/LogUtils.kt +++ b/log/src/main/kotlin/cn/tursom/log/LogUtils.kt @@ -1,5 +1,8 @@ package cn.tursom.log +import org.slf4j.Logger +import org.slf4j.event.Level + inline fun lazyLog(crossinline toString: () -> String) = object { override fun toString(): String = toString() } @@ -26,4 +29,46 @@ inline fun lazyPrettyMap(map: Map) = if (map.isNotEmpty() lazyPrettyMap(map.iterator()) } else { "{}" +} + +fun Logger.isEnabled(level: Level) = when (level) { + Level.ERROR -> isErrorEnabled + Level.WARN -> isWarnEnabled + Level.INFO -> isInfoEnabled + Level.DEBUG -> isDebugEnabled + Level.TRACE -> isTraceEnabled +} + +fun Logger.log(level: Level, msg: String, args: Array<*>) = when (level) { + Level.ERROR -> error(msg, *args) + Level.WARN -> warn(msg, *args) + Level.INFO -> info(msg, *args) + Level.DEBUG -> debug(msg, *args) + Level.TRACE -> trace(msg, *args) +} + +@JvmName("friendlyLog") +fun Logger.log(level: Level, msg: String, vararg args: Any?) = when (level) { + Level.ERROR -> error(msg, *args) + Level.WARN -> warn(msg, *args) + Level.INFO -> info(msg, *args) + Level.DEBUG -> debug(msg, *args) + Level.TRACE -> trace(msg, *args) +} + +fun Logger.logCaller() = logCaller(Level.DEBUG) + +fun Logger.logCaller(level: Level) { + if (isEnabled(level)) { + val e = Throwable() + val stackTraceElement = e.stackTrace[1] + log( + level, + "calling {}.{}({}:{})", + stackTraceElement.className, + stackTraceElement.methodName, + stackTraceElement.fileName, + stackTraceElement.lineNumber + ) + } } \ No newline at end of file diff --git a/log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt b/log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt index b043505..f35ce1a 100644 --- a/log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt +++ b/log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt @@ -3,21 +3,60 @@ package cn.tursom.log.impl import cn.tursom.log.Slf4j import org.slf4j.Logger import org.slf4j.LoggerFactory +import sun.reflect.Reflection import kotlin.reflect.KClass import kotlin.reflect.jvm.jvmName -open class Slf4jImpl(name: String? = null) : Slf4j { - constructor(clazz: Class<*>?) : this(clazz?.name) - constructor(clazz: KClass<*>?) : this(clazz?.jvmName?.let { - if (clazz.isCompanion) it.dropLast(10) else it +open class Slf4jImpl( + override val log: Logger, +) : Slf4j, Logger by log { + constructor(name: String? = null) : this(LoggerFactory.getLogger(name ?: loggerName)) + constructor(target: Class<*>?) : this(target?.canonicalName) + constructor(target: Any?) : this(target?.let { it::class }) + constructor(target: KClass<*>?) : this(target?.let { clazz -> + clazz.jvmName.let { + if (clazz.isCompanion) { + it.dropLast(10) + } else { + it + } + } }) - override val log: Logger = LoggerFactory.getLogger(name ?: if (this.javaClass != Slf4jImpl::class.java) { - val clazz = this.javaClass.kotlin - clazz.jvmName.let { - if (clazz.isCompanion) it.dropLast(10) else it + @Suppress("MemberVisibilityCanBePrivate", "NOTHING_TO_INLINE") + companion object { + private val thisClassName = listOf(this::class.java.name.dropLast(10), this::class.java.name) + private val loggerName: String + get() = getCallerClassName() ?: throw UnsupportedOperationException() + + private fun getCallerClassName(): String? { + var clazz: Class<*>? + var callStackDepth = 1 + do { + @Suppress("DEPRECATION") + clazz = Reflection.getCallerClass(callStackDepth++) + if (clazz?.name !in thisClassName) { + break + } + } while (clazz != null) + return clazz?.name } - } else { - throw NotImplementedError("") - }) + + inline fun getLogger(name: String): Logger = LoggerFactory.getLogger(name) + + fun getLogger(): Logger = LoggerFactory.getLogger(loggerName) + + inline fun getLogger(target: Any): Logger = getLogger(if (target::class != Slf4jImpl::class) { + val kClass = target::class + kClass.jvmName.let { + if (kClass.isCompanion) { + it.dropLast(10) + } else { + it + } + } + } else { + throw NotImplementedError("there is no default logger name") + }) + } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 534344f..c17cacc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -14,5 +14,7 @@ include 'database:redis' include 'utils:ws-client' include 'utils:mail' include 'utils:csv' +include 'utils:delegation' +include 'utils:observer' include 'utils:TrafficForward' include 'utils:performance-test' \ No newline at end of file diff --git a/socket/build.gradle b/socket/build.gradle index 0a402a7..d9595f5 100644 --- a/socket/build.gradle +++ b/socket/build.gradle @@ -1,3 +1,4 @@ dependencies { compile project(":") + compile project(":log") } \ No newline at end of file diff --git a/socket/src/main/kotlin/cn/tursom/socket/server/NioServer.kt b/socket/src/main/kotlin/cn/tursom/socket/server/NioServer.kt index 6012d54..bb858eb 100644 --- a/socket/src/main/kotlin/cn/tursom/socket/server/NioServer.kt +++ b/socket/src/main/kotlin/cn/tursom/socket/server/NioServer.kt @@ -1,7 +1,5 @@ package cn.tursom.socket.server -import cn.tursom.core.log -import cn.tursom.core.logE import cn.tursom.socket.INioProtocol import cn.tursom.socket.niothread.INioThread import cn.tursom.socket.niothread.WorkerLoopNioThread diff --git a/socket/src/main/kotlin/cn/tursom/socket/server/ThreadPoolSocketServer.kt b/socket/src/main/kotlin/cn/tursom/socket/server/ThreadPoolSocketServer.kt index 352c957..be1f9d1 100644 --- a/socket/src/main/kotlin/cn/tursom/socket/server/ThreadPoolSocketServer.kt +++ b/socket/src/main/kotlin/cn/tursom/socket/server/ThreadPoolSocketServer.kt @@ -1,6 +1,6 @@ package cn.tursom.socket.server -import cn.tursom.core.getTAG +import cn.tursom.log.impl.Slf4jImpl import cn.tursom.socket.BaseSocket import java.io.IOException import java.net.ServerSocket @@ -41,22 +41,22 @@ class ThreadPoolSocketServer * @param timeUnit timeout的单位,默认毫秒 * @param handler 对套接字处理的业务逻辑 */( - override val port: Int, - threads: Int = 1, - queueSize: Int = 1, - keepAliveTime: Long = 60_000L, - timeUnit: TimeUnit = TimeUnit.MILLISECONDS, - override val handler: BaseSocket.() -> Unit + override val port: Int, + threads: Int = 1, + queueSize: Int = 1, + keepAliveTime: Long = 60_000L, + timeUnit: TimeUnit = TimeUnit.MILLISECONDS, + override val handler: BaseSocket.() -> Unit ) : ISimpleSocketServer { constructor( - port: Int, - handler: BaseSocket.() -> Unit + port: Int, + handler: BaseSocket.() -> Unit ) : this(port, 1, 1, 60_000L, TimeUnit.MILLISECONDS, handler) var socket = Socket() private val pool: ThreadPoolExecutor = - ThreadPoolExecutor(threads, threads, keepAliveTime, timeUnit, LinkedBlockingQueue(queueSize)) + ThreadPoolExecutor(threads, threads, keepAliveTime, timeUnit, LinkedBlockingQueue(queueSize)) private var serverSocket: ServerSocket = ServerSocket(port) /** @@ -70,7 +70,7 @@ class ThreadPoolSocketServer while (!serverSocket.isClosed) { try { socket = serverSocket.accept() - println("$TAG: run(): get connect: $socket") + debug("run(): get connect: {}", socket) pool.execute { socket.use { BaseSocket(it).handler() @@ -128,8 +128,7 @@ class ThreadPoolSocketServer closeServer() } - companion object { - val TAG = getTAG(this::class.java) + companion object : Slf4jImpl() { /** * 线程池满时返回给客户端的信息 */ diff --git a/src/main/kotlin/cn/tursom/core/EnumTypeAdapterFactory.kt b/src/main/kotlin/cn/tursom/core/EnumTypeAdapterFactory.kt new file mode 100644 index 0000000..45d81ad --- /dev/null +++ b/src/main/kotlin/cn/tursom/core/EnumTypeAdapterFactory.kt @@ -0,0 +1,79 @@ +package cn.tursom.core + +import com.google.gson.Gson +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.annotations.SerializedName +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonToken +import com.google.gson.stream.JsonWriter + +object EnumTypeAdapterFactory : TypeAdapterFactory { + @Retention(AnnotationRetention.RUNTIME) + @Target(AnnotationTarget.FIELD) + annotation class EnumValue + + override fun create(gson: Gson, type: TypeToken): TypeAdapter? { + if (!type.rawType.isEnum) { + return null + } + + val valueOf = type.rawType.getDeclaredMethod("valueOf", String::class.java) + + val enumValueMap = type.rawType.enumConstants.asList().associateWith { + val enum: T = it.cast() + enum.javaClass.getField(it.toString()).getAnnotation(SerializedName::class.java)?.let { serializedName -> + return@associateWith serializedName.value + } + + val field = enum.javaClass.declaredFields.firstOrNull { it2 -> + it2.getAnnotation(EnumValue::class.java) != null + } + if (field != null) { + field.isAccessible = true + val value: Any = field.get(enum) + value + } else { + enum + } + } + + return object : TypeAdapter() { + override fun write(out: JsonWriter, value: T?) { + if (value == null) { + out.nullValue() + } else { + when (val enumValue = enumValueMap[value]) { + null -> out.nullValue() + is Boolean -> out.value(enumValue) + is Char -> out.value(enumValue.toString()) + is Byte -> out.value(enumValue) + is Short -> out.value(enumValue) + is Int -> out.value(enumValue) + is Long -> out.value(enumValue) + is Float -> out.value(enumValue) + is Double -> out.value(enumValue) + is Enum<*> -> out.value(enumValue.toString()) + else -> out.jsonValue(Utils.gson.toJson(enumValue)) + } + } + } + + override fun read(reader: JsonReader): T? { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull() + return null + } else { + val source = reader.nextString() + enumValueMap.forEach { (value, type) -> + if (type.toString() == source) { + return value.cast() + } + } + return valueOf(null, source).cast() + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/GsonDataTypeAdaptor.kt b/src/main/kotlin/cn/tursom/core/GsonDataTypeAdaptor.kt new file mode 100644 index 0000000..1bd6a83 --- /dev/null +++ b/src/main/kotlin/cn/tursom/core/GsonDataTypeAdaptor.kt @@ -0,0 +1,81 @@ +package cn.tursom.core + +import com.google.gson.Gson +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.internal.LinkedTreeMap +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonToken +import com.google.gson.stream.JsonWriter + +class GsonDataTypeAdaptor internal constructor(private val gson: Gson) : TypeAdapter?>() { + override fun write(out: JsonWriter, value: Map?) { + if (value == null) { + out.nullValue() + return + } + out.beginObject() + value.forEach { (t, u) -> + out.name(t) + System.err.println(u) + gson.getAdapter(Any::class.java).write(out, u) + } + out.endObject() + } + + override fun read(`in`: JsonReader): Map = readInternal(`in`).cast() + + private fun readInternal(`in`: JsonReader): Any? { + return when (`in`.peek()) { + JsonToken.BEGIN_ARRAY -> { + val list: MutableList = ArrayList() + `in`.beginArray() + while (`in`.hasNext()) { + list.add(readInternal(`in`)) + } + `in`.endArray() + list + } + JsonToken.BEGIN_OBJECT -> { + val map: MutableMap = LinkedTreeMap() + `in`.beginObject() + while (`in`.hasNext()) { + map[`in`.nextName()] = readInternal(`in`) + } + `in`.endObject() + map + } + JsonToken.STRING -> `in`.nextString() + JsonToken.NUMBER -> { + //将其作为一个字符串读取出来 + val numberStr: String = `in`.nextString() + //返回的numberStr不会为null + if (numberStr.contains(".") || numberStr.contains("e") + || numberStr.contains("E") + ) { + numberStr.toDouble() + } else numberStr.toLong() + } + JsonToken.BOOLEAN -> `in`.nextBoolean() + JsonToken.NULL -> { + `in`.nextNull() + null + } + else -> throw IllegalStateException() + } + } + + companion object { + val FACTORY: TypeAdapterFactory = object : TypeAdapterFactory { + override fun create(gson: Gson, type: TypeToken): TypeAdapter? { + return if (type.rawType == Map::class.java) { + GsonDataTypeAdaptor(gson).cast() + } else { + null + } + } + } + } +} + diff --git a/src/main/kotlin/cn/tursom/core/Parser.kt b/src/main/kotlin/cn/tursom/core/Parser.kt index e2777e4..6a9669b 100644 --- a/src/main/kotlin/cn/tursom/core/Parser.kt +++ b/src/main/kotlin/cn/tursom/core/Parser.kt @@ -1,5 +1,6 @@ package cn.tursom.core +import cn.tursom.core.Unsafe.unsafe import java.lang.reflect.Array import java.lang.reflect.Field import java.lang.reflect.Modifier diff --git a/src/main/kotlin/cn/tursom/core/Tools.kt b/src/main/kotlin/cn/tursom/core/Tools.kt index 51821c2..ae78510 100644 --- a/src/main/kotlin/cn/tursom/core/Tools.kt +++ b/src/main/kotlin/cn/tursom/core/Tools.kt @@ -2,229 +2,229 @@ package cn.tursom.core -import sun.misc.Unsafe -import java.io.ByteArrayInputStream +import cn.tursom.core.datastruct.ReversedList +import cn.tursom.core.datastruct.StepList +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import sun.reflect.Reflection import java.io.ByteArrayOutputStream +import java.io.ObjectOutputStream +import java.io.Serializable import java.lang.reflect.Field import java.lang.reflect.Method -import java.lang.reflect.ParameterizedType -import java.lang.reflect.Type +import java.lang.reflect.Proxy import java.net.URLDecoder import java.net.URLEncoder import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.util.* import java.util.concurrent.Executor -import java.util.jar.JarFile -import java.util.zip.Deflater -import java.util.zip.GZIPInputStream -import java.util.zip.GZIPOutputStream -import java.util.zip.Inflater import kotlin.collections.ArrayList +import kotlin.collections.HashSet +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine import kotlin.experimental.and +import kotlin.jvm.internal.PropertyReference +import kotlin.random.Random +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.companionObjectInstance +import kotlin.reflect.full.memberProperties +import kotlin.reflect.full.superclasses +object Utils { + const val dollar = '$' + val random = Random(System.currentTimeMillis()) -inline fun Array.excludeNull(): List { - val list = ArrayList() - forEach { if (it != null) list.add(it) } - return list -} - -fun printNonDaemonThread() { - val currentGroup = Thread.currentThread().threadGroup - val noThreads = currentGroup.activeCount() - val lstThreads = arrayOfNulls(noThreads) - currentGroup.enumerate(lstThreads) - lstThreads.excludeNull().forEach { t -> - if (!t.isDaemon) { - log(t.name) - } + @Suppress("unused", "SpellCheckingInspection") + val gson: Gson by lazy { + GsonBuilder() + .registerTypeAdapterFactory(GsonDataTypeAdaptor.FACTORY) + .registerTypeAdapterFactory(EnumTypeAdapterFactory) + .create() } - println() -} -fun log(log: String) = println("${ThreadLocalSimpleDateFormat.standard.format(System.currentTimeMillis())}: $log") -fun logE(log: String) = - System.err.println("${ThreadLocalSimpleDateFormat.standard.format(System.currentTimeMillis())}: $log") - -val String.urlDecode: String get() = URLDecoder.decode(this, "utf-8") -val String.urlEncode: String get() = URLEncoder.encode(this, "utf-8") - -inline fun usingTime(action: () -> T): Long { - val t1 = System.currentTimeMillis() - action() - val t2 = System.currentTimeMillis() - return t2 - t1 -} - -inline fun usingNanoTime(action: () -> T): Long { - val t1 = System.nanoTime() - action() - val t2 = System.nanoTime() - return t2 - t1 -} - -inline fun Collection.toString(action: (T) -> Any): String { - val iterator = iterator() - if (!iterator.hasNext()) return "[]" - val sb = StringBuilder("[${action(iterator.next())}") - iterator.forEach { - sb.append(", ") - sb.append(action(it)) + @Suppress("unused", "SpellCheckingInspection") + val prettyGson: Gson by lazy { + GsonBuilder() + .registerTypeAdapterFactory(GsonDataTypeAdaptor.FACTORY) + .registerTypeAdapterFactory(EnumTypeAdapterFactory) + .setPrettyPrinting() + .create() + } + + internal val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray() + internal val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray() + val md5 by lazy { MessageDigest.getInstance("MD5")!! } + val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! } + val sha by lazy { MessageDigest.getInstance("SHA")!! } + val sha1 by lazy { MessageDigest.getInstance("SHA-1")!! } + val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! } + val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! } + + internal val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray() + + val receiverField: Field by lazy { + kotlin.jvm.internal.CallableReference::class.java.getDeclaredField("receiver").apply { isAccessible = true } + } + val ownerField: Field by lazy { + kotlin.jvm.internal.CallableReference::class.java.getDeclaredField("owner").apply { isAccessible = true } } - sb.append("]") - return sb.toString() } -val unsafe by lazy { - val field = Unsafe::class.java.getDeclaredField("theUnsafe") - field.isAccessible = true - field.get(null) as Unsafe +fun String.hexStringToByteArray(): ByteArray { + val len = length + val data = ByteArray(len / 2) + var i = 0 + while (i < len) { + data[i / 2] = (Character.digit(this[i], 16) shl 4 or Character.digit(this[i + 1], 16)).toByte() + i += 2 + } + return data } -@Suppress("UNCHECKED_CAST") -fun Class.unsafeInstance() = unsafe.allocateInstance(this) as T -val Class<*>.actualTypeArguments: Array - get() = (genericSuperclass as ParameterizedType).actualTypeArguments +fun ByteArray.toHexString(upper: Boolean = true): String = if (upper) toUpperHexString() else toLowerHexString() + +fun ByteArray.toUpperHexString(): String { + val hexChars = CharArray(size * 2) + for (i in indices) { + val b = this[i] + hexChars[i shl 1] = Utils.UPPER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F] + hexChars[(i shl 1) + 1] = Utils.UPPER_HEX_ARRAY[(b and 0x0F).toInt()] + } + return String(hexChars) +} + +fun ByteArray.toLowerHexString(): String { + val hexChars = CharArray(size * 2) + for (i in indices) { + val b = this[i] + hexChars[i shl 1] = Utils.LOWER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F] + hexChars[(i shl 1) + 1] = Utils.LOWER_HEX_ARRAY[(b and 0x0F).toInt()] + } + return String(hexChars) +} + + +inline fun Iterable.toSetNotNull(transform: (T) -> R?): Set { + return HashSet().apply { this@toSetNotNull.forEach { add(transform(it) ?: return@forEach) } } +} + + +@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") +inline fun Any?.cast() = this as T + +@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") +inline fun Any?.castOrNull() = if (this is T) this else null + +inline fun T?.checkNull(ifNull: () -> Exception): T { + if (this == null) { + throw ifNull() + } else { + return this + } +} + +fun String.emptyToNull() = if (isEmpty()) null else this + +inline fun getClazz() = T::class.java fun Class<*>.isInheritanceFrom(parent: Class<*>) = parent.isAssignableFrom(this) -fun getClassName(jarPath: String): List { - val myClassName = ArrayList() - for (entry in JarFile(jarPath).entries()) { - val entryName = entry.name - if (entryName.endsWith(".class")) { - myClassName.add(entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."))) - } - } - return myClassName +operator fun (() -> T).unaryPlus() = object : () -> T { + override operator fun invoke() = this@unaryPlus() + override fun toString(): String = this@unaryPlus().toString() } -fun List.binarySearch(comparison: (T) -> Int): T? { - val index = binarySearch(0, size, comparison) - return if (index < 0) null - else get(index) +fun String.toLowerCase(vararg indexes: Int): String { + val charArray = toCharArray() + indexes.forEach { index -> + charArray[index] = charArray[index].toLowerCase() + } + return String(charArray) } -val cpuNumber = Runtime.getRuntime().availableProcessors() - -fun String.simplifyPath(): String { - if (isEmpty()) { - return "." +fun String.toUpperCase(vararg indexes: Int): String { + val charArray = toCharArray() + indexes.forEach { index -> + charArray[index] = charArray[index].toUpperCase() } - val pathList = split(java.io.File.separator).dropLastWhile { it.isEmpty() } - val list = LinkedList() - for (path in pathList) { - if (path.isEmpty() || "." == path) { - continue - } - if (".." == path) { - list.pollLast() - continue - } - list.addLast(path) - } - var result = "" - while (list.size > 0) { - result += java.io.File.separator + list.pollFirst()!! - } - return if (result.isNotEmpty()) result else "." + return String(charArray) } -//获取md5加密对象 -val md5 by lazy { MessageDigest.getInstance("MD5")!! } +fun String.toLowerCase(indexes: IntRange): String { + val charArray = toCharArray() + indexes.forEach { index -> + charArray[index] = charArray[index].toLowerCase() + } + return String(charArray) +} + +fun String.toUpperCase(indexes: IntRange): String { + val charArray = toCharArray() + indexes.forEach { index -> + charArray[index] = charArray[index].toUpperCase() + } + return String(charArray) +} fun ByteArray.md5(): ByteArray { - //加密,返回字节数组 - return md5.digest(this) + return Utils.md5.digest(this) } fun String.md5(): String = toByteArray().md5().toHexString() -//获取md5加密对象 -val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! } - fun ByteArray.sha256(): ByteArray { - //加密,返回字节数组 - return sha256.digest(this) + return Utils.sha256.digest(this) } fun String.sha256(): String = toByteArray().sha256().toHexString() -//获取sha加密对象 -val sha by lazy { MessageDigest.getInstance("SHA")!! } -fun ByteArray.sha(): ByteArray = sha.digest(this) +fun ByteArray.sha(): ByteArray = Utils.sha.digest(this) fun String.sha(): String = toByteArray().sha().toHexString() -//获取sha1加密对象 -val sha1 by lazy { MessageDigest.getInstance("SHA-1")!! } -fun ByteArray.sha1(): ByteArray = sha1.digest(this) +fun ByteArray.sha1(): ByteArray = Utils.sha1.digest(this) fun String.sha1(): String = toByteArray().sha1().toHexString() -//获取sha384加密对象 -val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! } -fun ByteArray.sha384(): ByteArray = sha384.digest(this) +fun ByteArray.sha384(): ByteArray = Utils.sha384.digest(this) fun String.sha384(): String = toByteArray().sha384().toHexString() -//获取 sha-512 加密对象 -val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! } - -fun ByteArray.sha512(): ByteArray = sha512.digest(this) +fun ByteArray.sha512(): ByteArray = Utils.sha512.digest(this) fun String.sha512(): String = toByteArray().sha512().toHexString() - -fun ByteArray.toHexString(upper: Boolean = true): String = if (upper) toUpperHexString() else toLowerHexString() - -private val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray() -fun ByteArray.toUpperHexString(): String { - val hexChars = CharArray(size * 2) - for (i in indices) { - val b = this[i] - hexChars[i shl 1] = UPPER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F] - hexChars[(i shl 1) + 1] = UPPER_HEX_ARRAY[(b and 0x0F).toInt()] - } - return String(hexChars) -} - -private val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray() -fun ByteArray.toLowerHexString(): String { - val hexChars = CharArray(size * 2) - for (i in indices) { - val b = this[i] - hexChars[i shl 1] = LOWER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F] - hexChars[(i shl 1) + 1] = LOWER_HEX_ARRAY[(b and 0x0F).toInt()] - } - return String(hexChars) -} - fun String.fromHexString(): ByteArray { val source = toLowerCase() val data = ByteArray(length / 2) for (i in 0 until length / 2) { - data[i] = ((LOWER_HEX_ARRAY.indexOf(source[i * 2]) shl 4) + LOWER_HEX_ARRAY.indexOf(source[i * 2 + 1])).toByte() + data[i] = + ((Utils.UPPER_HEX_ARRAY.indexOf(source[i * 2]) shl 4) + Utils.UPPER_HEX_ARRAY.indexOf(source[i * 2 + 1])).toByte() } return data } fun ByteArray.toUTF8String() = String(this, Charsets.UTF_8) -fun String.base64(): String = this.toByteArray().base64().toUTF8String() +fun String.base64() = this.toByteArray().base64().toUTF8String() fun ByteArray.base64(): ByteArray = Base64.getEncoder().encode(this) fun String.base64Url(): String = this.toByteArray().base64Url().toUTF8String() fun ByteArray.base64Url(): ByteArray = Base64.getUrlEncoder().encode(this) fun String.base64Mime(): String = this.toByteArray().base64Mime().toUTF8String() fun ByteArray.base64Mime(): ByteArray = Base64.getMimeEncoder().encode(this) -fun String.base64decode(): String = Base64.getDecoder().decode(this).toUTF8String() +fun String.base64decode() = Base64.getDecoder().decode(this).toUTF8String() fun ByteArray.base64decode(): ByteArray = Base64.getDecoder().decode(this) fun String.base64UrlDecode(): String = Base64.getUrlDecoder().decode(this).toUTF8String() fun ByteArray.base64UrlDecode(): ByteArray = Base64.getUrlDecoder().decode(this) @@ -234,163 +234,56 @@ fun ByteArray.base64MimeDecode(): ByteArray = Base64.getMimeDecoder().decode(thi fun String.digest(type: String) = toByteArray().digest(type)?.toHexString() fun ByteArray.digest(type: String) = try { - //获取加密对象 val instance = MessageDigest.getInstance(type) - //加密,返回字节数组 instance.digest(this) } catch (e: NoSuchAlgorithmException) { e.printStackTrace() null } -val random = Random() -fun randomInt() = random.nextInt() -fun randomInt(min: Int, max: Int): Int = - if (min > max) randomInt(max, min) else (random.nextInt() and Int.MAX_VALUE) % (max - min + 1) + min - -fun randomLong() = random.nextLong() -fun randomLong(min: Long, max: Long) = (random.nextLong() and Long.MAX_VALUE) % (max - min + 1) + min -fun randomBoolean() = random.nextBoolean() -fun randomFloat() = random.nextFloat() -fun randomDouble() = random.nextDouble() -fun randomGaussian() = random.nextGaussian() -fun randomBytes(bytes: ByteArray) = random.nextBytes(bytes) - -fun getTAG(cls: Class<*>): String { - return cls.name.split(".").last().dropLast(10) -} - -operator fun (() -> T).unaryPlus() = object : () -> T { - override fun invoke(): T = this@unaryPlus() - override fun toString() = this@unaryPlus().toString() -} - -operator fun Executor.invoke(action: () -> Unit) { - execute(action) -} - -operator fun Executor.invoke(action: Runnable) = this(action::run) - -inline fun Field.getAnnotation(): T? = getAnnotation(T::class.java) - -inline fun Class<*>.getAnnotation(): T? = getAnnotation(T::class.java) - -fun process(size: Int, vararg actions: () -> Unit) { - actions.forEachIndexed { index, function -> - if (actions.size - index <= size) function() - } -} - -fun process(value: T, vararg actions: Pair Unit>) { - var checked = false - actions.forEach { (v, function) -> - if (checked || value == v) { - checked = true - function() - } - } -} - -fun T.println(): T { - println(this) - return this -} - -@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") -inline fun Any?.cast(): T = this as T - -inline fun loop(`continue`: () -> Boolean = { true }, action: () -> Unit) { - while (`continue`()) action() -} - -inline fun getClazz() = T::class.java - -@Suppress("NOTHING_TO_INLINE") -inline fun > lambda(lambda: T) = lambda - -fun ByteArray.gz(): ByteArray { - val os = ByteArrayOutputStream() - GZIPOutputStream(os).use { - it.write(this) - } - return os.toByteArray() -} - -fun ByteArray.ungz(): ByteArray { - return GZIPInputStream(ByteArrayInputStream(this)).readBytes() -} - -fun ByteArray.undeflate(): ByteArray { - val infl = Inflater() - infl.setInput(this) - val bos = ByteArrayOutputStream() - val outByte = ByteArray(1024) - bos.use { - while (!infl.finished()) { - // 解压缩并将解压缩后的内容输出到字节输出流bos中 - val len = infl.inflate(outByte) - if (len == 0) { - break - } - bos.write(outByte, 0, len) - } - infl.end() - } - return bos.toByteArray() -} - - -fun ByteArray.deflate(): ByteArray { - val defl = Deflater() - defl.setInput(this) - defl.finish() - val bos = ByteArrayOutputStream() - val outputByte = ByteArray(1024) - bos.use { - while (!defl.finished()) { - // 压缩并将压缩后的内容输出到字节输出流bos中 - val len = defl.deflate(outputByte) - bos.write(outputByte, 0, len) - } - defl.end() - } - return bos.toByteArray() -} - -//fun ByteArray.deflate(): ByteArray { -// val os = ByteArrayOutputStream() -// DeflaterOutputStream(os).use { -// it.write(this) -// } -// return os.toByteArray() -//} -// -//fun ByteArray.undeflate(): ByteArray { -// return DeflaterInputStream(ByteArrayInputStream(this)).readBytes() -//} - -inline fun Any.assert(action: T.() -> Unit): Boolean { - return if (this is T) { - action() +fun A.changeAnnotationValue(field: KProperty1, value: V): Boolean { + return try { + val h = Proxy.getInvocationHandler(this) + val memberValuesField = h.javaClass.getDeclaredField("memberValues") + memberValuesField.isAccessible = true + val memberValues = memberValuesField[h].cast>() + memberValues[field.name] = value true - } else { + } catch (e: Exception) { false } } -val Class<*>.allFields: List - get() { - var clazz = this - val list = ArrayList() - while (clazz != Any::class.java) { - list.addAll(clazz.declaredFields) - clazz = clazz.superclass +/** + * 向数据库提交一项任务并获取返回值 + */ +suspend fun Executor.runWith(action: () -> T): T = suspendCoroutine { cont -> + execute { + try { + cont.resume(action()) + } catch (e: Exception) { + cont.resumeWithException(e) } - list.addAll(clazz.declaredFields) - return list } +} -fun Class<*>.forAllFields(action: (Field) -> Unit) { +inline fun Gson.fromJson(json: String): T = fromJson(json, T::class.java) + +inline fun usingTime(action: () -> Unit): Long { + val t1 = System.currentTimeMillis() + action() + val t2 = System.currentTimeMillis() + return t2 - t1 +} + +inline fun usingNanoTime(action: () -> Unit): Long { + val t1 = System.nanoTime() + action() + val t2 = System.nanoTime() + return t2 - t1 +} + +inline fun Class<*>.forAllFields(action: (Field) -> Unit) { var clazz = this while (clazz != Any::class.java) { clazz.declaredFields.forEach(action) @@ -399,14 +292,21 @@ fun Class<*>.forAllFields(action: (Field) -> Unit) { clazz.declaredFields.forEach(action) } -fun Iterable.firstNotNull(selector: (T) -> R): R? { - forEach { - return selector(it) ?: return@forEach +val Class<*>.allFields: List + get() { + val fieldList = ArrayList() + forAllFields(fieldList::add) + return fieldList + } + +fun Class<*>.getFieldForAll(name: String): Field? { + forAllFields { + if (it.name == name) return it } return null } -fun Class<*>.forAllMethods(action: (Method) -> Unit) { +inline fun Class<*>.forAllMethods(action: (Method) -> Unit) { var clazz = this while (clazz != Any::class.java) { clazz.declaredMethods.forEach(action) @@ -415,14 +315,51 @@ fun Class<*>.forAllMethods(action: (Method) -> Unit) { clazz.declaredMethods.forEach(action) } -private val BASE62_DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray() +fun Class<*>.getMethodForAll(name: String, vararg parameterTypes: Class<*>?): Method? { + forAllMethods { + if (it.name == name && parameterTypes.contentEquals(it.parameterTypes)) return it + } + return null +} + +val Class<*>.allMethods: List + get() { + val fieldList = ArrayList() + forAllMethods(fieldList::add) + return fieldList + } + +/** + * 获取一个 KProperty<*> 对应的对象 + */ +val KProperty<*>.receiver: Any? + get() = if (this is PropertyReference) { + boundReceiver + } else try { + Utils.receiverField.get(this) + } catch (e: Exception) { + null + } ?: javaClass.getFieldForAll("receiver")?.let { + it.isAccessible = true + it.get(this) + } + +val KProperty<*>.owner: Class<*>? + get() = try { + Utils.ownerField.get(this)?.cast>() + } catch (e: Exception) { + null + } ?: javaClass.getFieldForAll("owner")?.let { + it.isAccessible = true + it.get(this)?.castOrNull() + } tailrec fun Long.base62(sBuilder: StringBuilder = StringBuilder()): String { return if (this == 0L) { sBuilder.reverse().toString() } else { val remainder = (this % 62).toInt() - sBuilder.append(BASE62_DIGITS[remainder]) + sBuilder.append(Utils.DIGITS[remainder]) (this / 62).base62(sBuilder) } } @@ -430,10 +367,208 @@ tailrec fun Long.base62(sBuilder: StringBuilder = StringBuilder()): String { fun String.base62Decode(): Long { var sum: Long = 0 val len = length - var base = 62L + var base = 1L for (i in 0 until len) { - sum += BASE62_DIGITS.indexOf(this[len - i - 1]) * base + sum += Utils.DIGITS.indexOf(this[len - i - 1]) * base base *= 62 } return sum } + +fun Any.toJson(): String = Utils.gson.toJson(this) +fun Any.toPrettyJson(): String = Utils.prettyGson.toJson(this) + +inline fun String.fromJson(): T = Utils.gson.fromJson(this, T::class.java) + +fun Any.serialize(): ByteArray { + val outputStream = ByteArrayOutputStream() + ObjectOutputStream(outputStream).writeObject(this) + return outputStream.toByteArray() +} + +operator fun List.get(startIndex: Int = 0, endIndex: Int = size, step: Int = 1): List { + if (step <= 0) throw IllegalArgumentException("step($step) is negative or zero") + val fromIndex = when { + startIndex < 0 -> size + startIndex + startIndex >= size -> size + else -> startIndex + } + val toIndex = when { + endIndex < 0 -> size + endIndex + 1 + endIndex >= size -> size + else -> endIndex + } + var targetList = if (fromIndex > toIndex) ReversedList(subList(toIndex, fromIndex)) else subList(fromIndex, toIndex) + if (step != 1) targetList = targetList step step + return targetList +} + +operator fun List.get(intProgression: IntProgression): List { + val first = intProgression.first + val last = intProgression.last + val step = intProgression.step + return when { + step == 0 -> get(first, last + if (last < 0) 0 else 1, 1) + step < 0 -> get(first + if (last > 0 && first >= 0) 1 else 0, last, -step) + else -> get(first, last + if (last < 0) 0 else 1, step) + } +} + +infix fun List.step(step: Int): List = StepList(this, step) + +inline infix fun String.ifEmpty(ifEmpty: () -> String) = if (isNotEmpty()) this else ifEmpty() +inline infix fun String.ifBlank(ifBlank: () -> String) = if (isNotBlank()) this else ifBlank() + +@JvmName("ifEmptyNullable") +inline fun String.ifEmpty(ifEmpty: () -> String?) = if (isNotEmpty()) this else ifEmpty() + +@JvmName("ifBlankNullable") +inline fun String.ifBlank(ifBlank: () -> String?) = if (isNotBlank()) this else ifBlank() + +/** + * 使用 condition 做条件判断,如果返回 true 则使用 then 生成结果,否则范湖自身 + */ +inline fun T.ifThen(condition: T.() -> Boolean, then: () -> T) = if (condition()) then() else this + +@JvmName("ifThenNullable") +inline fun T.ifThen(condition: T.() -> Boolean, then: () -> T?) = if (condition()) then() else this + +inline fun Any.wait(action: () -> T) = synchronized(this) { + val t = action() + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + (this as Object).wait() + t +} + +inline fun Any.notify(action: () -> T) = synchronized(this) { + val t = action() + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + (this as Object).notify() + t +} + +inline fun Any.notifyAll(action: () -> T) = synchronized(this) { + val t = action() + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + (this as Object).notifyAll() + t +} + +inline val KClass<*>.companionObjectInstanceOrNull: Any? + get() = try { + companionObjectInstance + } catch (e: Exception) { + null + } + +inline val Map.notNullKey get() = cast>() +inline val Map.notNullValue get() = cast>() +inline val Map.notNullEntry get() = cast>() + +inline val Map.filterNullKey get() = filter { it.key != null }.notNullKey +inline val Map.filterNullValue get() = filter { it.value != null }.notNullValue + +val KClass.allMemberProperties: List> + get() { + val propertiesList = memberProperties.toMutableList() + var superClass = superclasses.firstOrNull { + !it.java.isInterface + } + while (superClass != null) { + propertiesList.addAll(superClass.memberProperties.cast()) + superClass = superClass.superclasses.firstOrNull { + !it.java.isInterface + } + } + return propertiesList + } + +fun String.toStartWith(prefix: String) = if (startsWith(prefix)) this else prefix + this +fun String.toStartWith(prefix: Char) = if (startsWith(prefix)) this else prefix + this + + +fun mongoLegal(value: Any?) = when { + value == null -> true + value is Number -> true + value is Boolean -> true + value is Char -> true + value is String -> true + value is Serializable -> true + value.javaClass.kotlin.isData -> true + value.javaClass.name.endsWith("DTO") -> true + value.javaClass.name.endsWith("VO") -> true + else -> false +} + +fun getCallerClass(thisClassName: List): Class<*>? { + var clazz: Class<*>? + var callStackDepth = 1 + do { + clazz = getCallerClass(callStackDepth++) + if (clazz?.name !in thisClassName) { + break + } + } while (clazz != null) + return clazz +} + +fun getCallerClassName(thisClassName: List): String? { + return getCallerClass(thisClassName)?.name +} + +fun getCallerClass(callStackDepth: Int): Class<*>? { + @Suppress("DEPRECATION") + return Reflection.getCallerClass(callStackDepth) +} + +fun getCallerClassName(callStackDepth: Int): String? { + return getCallerClass(callStackDepth)?.name +} + +@OptIn(ExperimentalContracts::class) +fun CharSequence?.isNotNullOrEmpty(): Boolean { + contract { + returns(true) implies (this@isNotNullOrEmpty != null) + } + + return this != null && this.isNotEmpty() +} + +@OptIn(ExperimentalContracts::class) +fun Collection<*>?.isNotNullOrEmpty(): Boolean { + contract { + returns(true) implies (this@isNotNullOrEmpty != null) + } + + return this != null && this.isNotEmpty() +} + +//@OptIn(ExperimentalContracts::class) +//fun main() { +// val s: String? = "" +// if (s.isNotNullAndEmpty()) { +// println(s.length) +// } +//} + + +inline fun Any?.assert(ifMatch: T.() -> Unit) = if (this is T) { + ifMatch() + true +} else { + false +} + +val cpuNumber get() = Runtime.getRuntime().availableProcessors() + +@Suppress("NOTHING_TO_INLINE") +inline fun > lambda(lambda: T) = lambda + +val String.urlDecode: String get() = URLDecoder.decode(this, "utf-8") +val String.urlEncode: String get() = URLEncoder.encode(this, "utf-8") + +fun List.binarySearch(comparison: (T) -> Int): T? { + val index = binarySearch(0, size, comparison) + return if (index < 0) null + else get(index) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/datastruct/AbstractListIterator.kt b/src/main/kotlin/cn/tursom/core/datastruct/AbstractListIterator.kt new file mode 100644 index 0000000..a09d74d --- /dev/null +++ b/src/main/kotlin/cn/tursom/core/datastruct/AbstractListIterator.kt @@ -0,0 +1,14 @@ +package cn.tursom.core.datastruct + +open class AbstractListIterator( + val list: List, + private var index: Int = 0 +) : ListIterator { + override fun hasNext(): Boolean = list.size > index + override fun next(): E = list[index++] + override fun nextIndex(): Int = index + override fun hasPrevious(): Boolean = index > 0 + override fun previous(): E = list[--index] + + override fun previousIndex(): Int = index - 1 +} \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/datastruct/ReversedList.kt b/src/main/kotlin/cn/tursom/core/datastruct/ReversedList.kt new file mode 100644 index 0000000..d9705a6 --- /dev/null +++ b/src/main/kotlin/cn/tursom/core/datastruct/ReversedList.kt @@ -0,0 +1,48 @@ +package cn.tursom.core.datastruct + +class ReversedList( + val list: List +) : List by list { + override fun get(index: Int): E = list[size - index - 1] + + override fun indexOf(element: E): Int { + val lastIndexOf = list.lastIndexOf(element) + return if (lastIndexOf >= 0) size - lastIndexOf else -1 + } + + override fun lastIndexOf(element: E): Int { + val indexOf = list.indexOf(element) + return if (indexOf >= 0) size - indexOf else -1 + } + + override fun iterator(): Iterator = listIterator() + override fun listIterator(): ListIterator = listIterator(0) + + override fun listIterator(index: Int): ListIterator = ReverseListIterator(list.listIterator(size - index)) + + override fun subList(fromIndex: Int, toIndex: Int): List { + return ReversedList(list.subList(size - toIndex, size - fromIndex)) + } + + override fun toString(): String { + val iterator = iterator() + return buildString { + append('[') + iterator.forEach { + append(it) + if (iterator.hasNext()) append(", ") + } + append(']') + } + } + + private class ReverseListIterator(val listIterator: ListIterator) : ListIterator { + override fun hasNext(): Boolean = listIterator.hasPrevious() + override fun next(): E = listIterator.previous() + override fun nextIndex(): Int = listIterator.previousIndex() + override fun hasPrevious(): Boolean = listIterator.hasNext() + override fun previous(): E = listIterator.next() + override fun previousIndex(): Int = listIterator.nextIndex() + } +} + diff --git a/src/main/kotlin/cn/tursom/core/datastruct/StepList.kt b/src/main/kotlin/cn/tursom/core/datastruct/StepList.kt new file mode 100644 index 0000000..0362758 --- /dev/null +++ b/src/main/kotlin/cn/tursom/core/datastruct/StepList.kt @@ -0,0 +1,49 @@ +package cn.tursom.core.datastruct + +class StepList( + val list: List, + val step: Int = 1, +) : List by list { + init { + if (step <= 0) throw IllegalArgumentException("step is negative or zero") + } + + override val size: Int + get() = when { + step == 1 -> list.size + list.isEmpty() -> 0 + else -> list.size / step + if (list.size % step == 0) 0 else 1 + } + + override fun get(index: Int): E = list[index * step] + + override fun indexOf(element: E): Int { + val indexOf = list.indexOf(element) + return if (indexOf >= 0) indexOf * step else -1 + } + + override fun lastIndexOf(element: E): Int { + val indexOf = list.lastIndexOf(element) + return if (indexOf >= 0) indexOf * step else -1 + } + + override fun iterator(): Iterator = listIterator() + override fun listIterator(): ListIterator = listIterator(0) + override fun listIterator(index: Int): ListIterator = + if (step == 1) list.listIterator(index) else AbstractListIterator(this, index) + + override fun subList(fromIndex: Int, toIndex: Int): List = + StepList(list.subList(fromIndex * step, toIndex * step), step) + + override fun toString(): String { + val iterator = iterator() + return buildString { + append('[') + iterator.forEach { + append(it) + if (iterator.hasNext()) append(", ") + } + append(']') + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/encrypt/EncryptPool.kt b/src/main/kotlin/cn/tursom/core/encrypt/EncryptPool.kt index 561b644..d166e58 100644 --- a/src/main/kotlin/cn/tursom/core/encrypt/EncryptPool.kt +++ b/src/main/kotlin/cn/tursom/core/encrypt/EncryptPool.kt @@ -1,8 +1,8 @@ package cn.tursom.core.encrypt +import cn.tursom.core.Utils import cn.tursom.core.datastruct.concurrent.BlockingArrayList import cn.tursom.core.pool.Pool -import cn.tursom.core.randomInt open class EncryptPool( initSize: Int = 0, @@ -20,5 +20,5 @@ open class EncryptPool( return aesPool.add(cache) } - override fun get(): T = aesPool[randomInt(0, aesPool.size - 1)] + override fun get(): T = aesPool[Utils.random.nextInt(0, aesPool.size - 1)] } \ No newline at end of file diff --git a/utils/delegation/build.gradle b/utils/delegation/build.gradle new file mode 100644 index 0000000..9e4c218 --- /dev/null +++ b/utils/delegation/build.gradle @@ -0,0 +1,4 @@ +dependencies { + compile project(":") + api "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" +} diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegateProvider.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegateProvider.kt new file mode 100644 index 0000000..aebbc6c --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegateProvider.kt @@ -0,0 +1,9 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +interface DecoratorDelegateProvider : + DelegateProvider>, + DecoratorDelegatedField { + override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): DelegatedField = delegatedField +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegatedField.kt new file mode 100644 index 0000000..e007cae --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegatedField.kt @@ -0,0 +1,5 @@ +package cn.tursom.delegation + +interface DecoratorDelegatedField { + val delegatedField: DelegatedField +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegateProvider.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegateProvider.kt new file mode 100644 index 0000000..d0c44ea --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegateProvider.kt @@ -0,0 +1,11 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +interface DecoratorMutableDelegateProvider : + DelegateProvider>, + //DecoratorProvideDelegate, + DecoratorMutableDelegatedField { + override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): MutableDelegatedField = + mutableDelegatedField +} diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegatedField.kt new file mode 100644 index 0000000..0bb2f9f --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegatedField.kt @@ -0,0 +1,6 @@ +package cn.tursom.delegation + +interface DecoratorMutableDelegatedField : DecoratorDelegatedField { + val mutableDelegatedField: MutableDelegatedField + override val delegatedField: DelegatedField get() = mutableDelegatedField +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegateProvider.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegateProvider.kt new file mode 100644 index 0000000..d737a49 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegateProvider.kt @@ -0,0 +1,7 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +interface DelegateProvider { + operator fun provideDelegate(thisRef: T, prop: KProperty<*>): R +} diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegatedField.kt new file mode 100644 index 0000000..c59cf69 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegatedField.kt @@ -0,0 +1,44 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +/** + * 这是用来规范kotlin委托属性的一个接口,你可以用这个接口来针对属性进行硬编码级别的动态代理 + * 比如如果你需要监控属性的变化,可以使用 FieldChangeListener.listened 来定义属性 + * 如果你还需要对这个属性进行加锁,你就可以在后方加一个 .locked 即可 + * 如果还需要用指定的锁,在后面再加一个 (lock) 就玩成了 + * 使用例: + * class XXXImpl: XXX, FieldChangeListener by FieldChangeListenerImpl() { + * val lock = ReentrantLock() + * val field by listened(0).locker(lock) + * } + */ +interface DelegatedField { + /** + * 用来获取值,不会发生附加调用 + */ + fun getValue(): V + operator fun getValue(thisRef: T, property: KProperty<*>): V = getValue() + + operator fun get(key: DelegatedFieldAttachmentKey): K? = + if (this is DecoratorDelegatedField<*, *>) { + delegatedField[key] + } else { + null + } + + operator fun set(key: DelegatedFieldAttachmentKey, value: V): Boolean = + if (this is DecoratorDelegatedField<*, *>) { + delegatedField.set(key, value) + } else { + false + } + + fun removeAttachment(key: DelegatedFieldAttachmentKey): Boolean = + if (this is DecoratorDelegatedField<*, *>) { + delegatedField.removeAttachment(key) + } else { + false + } +} + diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegatedFieldAttachmentKey.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegatedFieldAttachmentKey.kt new file mode 100644 index 0000000..1f26256 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/DelegatedFieldAttachmentKey.kt @@ -0,0 +1,3 @@ +package cn.tursom.delegation + +interface DelegatedFieldAttachmentKey \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/ExecutorMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/ExecutorMutableDelegatedField.kt new file mode 100644 index 0000000..d1f2366 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/ExecutorMutableDelegatedField.kt @@ -0,0 +1,20 @@ +package cn.tursom.delegation + +import java.util.concurrent.Executor +import kotlin.reflect.KProperty + +class ExecutorMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, + private val executor: Executor, +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { + executor.execute { + mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + } + } + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + valueOnSet(thisRef, property, value, getValue()) + mutableDelegatedField.setValue(value) + } +} diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/FilterDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/FilterDelegatedField.kt new file mode 100644 index 0000000..4a82cc6 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/FilterDelegatedField.kt @@ -0,0 +1,33 @@ +package cn.tursom.delegation + +import cn.tursom.core.cast +import kotlin.reflect.KProperty + +class FilterDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, + private val filter: T.(old: V, new: V) -> Boolean, +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + companion object Key : DelegatedFieldAttachmentKey + + private var filterResult = false + + override fun get(key: DelegatedFieldAttachmentKey): K? { + return if (key == Key) filterResult.cast() else super.get(key) + } + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + filterResult = thisRef.filter(getValue(), value) + if (!filterResult) { + return + } + mutableDelegatedField.setValue(thisRef, property, value) + } + + override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { + filterResult = thisRef.filter(getValue(), value) + if (!filterResult) { + return + } + mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + } +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/GetterDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/GetterDelegatedField.kt new file mode 100644 index 0000000..86b205d --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/GetterDelegatedField.kt @@ -0,0 +1,10 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +class GetterDelegatedField( + override val delegatedField: DelegatedField, + private val getter: DelegatedField.(thisRef: T, property: KProperty<*>) -> V, +) : DelegatedField by delegatedField, DecoratorDelegatedField { + override fun getValue(thisRef: T, property: KProperty<*>): V = delegatedField.getter(thisRef, property) +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/GetterMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/GetterMutableDelegatedField.kt new file mode 100644 index 0000000..b8a9f0a --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/GetterMutableDelegatedField.kt @@ -0,0 +1,10 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +class GetterMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, + private val getter: MutableDelegatedField.(thisRef: T, property: KProperty<*>) -> V, +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + override fun getValue(thisRef: T, property: KProperty<*>): V = mutableDelegatedField.getter(thisRef, property) +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/KPropertyDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/KPropertyDelegatedField.kt new file mode 100644 index 0000000..2ab2d7b --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/KPropertyDelegatedField.kt @@ -0,0 +1,9 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty0 + +class KPropertyDelegatedField( + val delegation: KProperty0, +) : DelegatedField { + override fun getValue(): V = delegation.get() +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/KPropertyMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/KPropertyMutableDelegatedField.kt new file mode 100644 index 0000000..168d5ca --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/KPropertyMutableDelegatedField.kt @@ -0,0 +1,10 @@ +package cn.tursom.delegation + +import kotlin.reflect.KMutableProperty0 + +class KPropertyMutableDelegatedField( + val delegation: KMutableProperty0, +) : MutableDelegatedField { + override fun getValue(): V = delegation.get() + override fun setValue(value: V) = delegation.set(value) +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/LockMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/LockMutableDelegatedField.kt new file mode 100644 index 0000000..76c2924 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/LockMutableDelegatedField.kt @@ -0,0 +1,28 @@ +package cn.tursom.delegation + +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock +import kotlin.reflect.KProperty + +class LockMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, + private val lock: Lock = ReentrantLock(), +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + constructor( + initValue: V, + lock: Lock = ReentrantLock(), + ) : this(MutableDelegatedFieldValue(initValue), lock) + + override fun getValue(thisRef: T, property: KProperty<*>): V = lock.withLock { + mutableDelegatedField.getValue(thisRef, property) + } + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) = lock.withLock { + mutableDelegatedField.setValue(thisRef, property, value) + } + + override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) = lock.withLock { + mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + } +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedField.kt new file mode 100644 index 0000000..fd4f19e --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedField.kt @@ -0,0 +1,25 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +interface MutableDelegatedField : DelegatedField { + /** + * 用来设置值,不会发生 valueOnSet调用 + */ + fun setValue(value: V) + + /** + * setter委托定义与其默认实现 + */ + operator fun setValue(thisRef: T, property: KProperty<*>, value: V) { + valueOnSet(thisRef, property, value, getValue()) + setValue(value) + } + + /** + * 当值发生设置时应当被调用 + * 流水线式调用 + */ + fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) {} +} + diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedFieldValue.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedFieldValue.kt new file mode 100644 index 0000000..c2aca26 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedFieldValue.kt @@ -0,0 +1,17 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +open class MutableDelegatedFieldValue( + private var initValue: V +) : MutableDelegatedField { + override fun getValue(): V = initValue + override fun getValue(thisRef: T, property: KProperty<*>): V = initValue + override fun setValue(value: V) { + initValue = value + } + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + initValue = value + } +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/NotNullDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/NotNullDelegatedField.kt new file mode 100644 index 0000000..7e82e96 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/NotNullDelegatedField.kt @@ -0,0 +1,7 @@ +package cn.tursom.delegation + +import cn.tursom.core.cast + +class NotNullDelegatedField( + override val delegatedField: DelegatedField, +) : DelegatedField by delegatedField.cast(), DecoratorDelegatedField \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/NotNullMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/NotNullMutableDelegatedField.kt new file mode 100644 index 0000000..9e2b9ad --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/NotNullMutableDelegatedField.kt @@ -0,0 +1,8 @@ +package cn.tursom.delegation + +import cn.tursom.core.cast + +class NotNullMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, +) : MutableDelegatedField by mutableDelegatedField.cast(), DecoratorMutableDelegatedField + diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/ReadWriteLockMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/ReadWriteLockMutableDelegatedField.kt new file mode 100644 index 0000000..4f2d2ee --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/ReadWriteLockMutableDelegatedField.kt @@ -0,0 +1,43 @@ +package cn.tursom.delegation + +import java.util.concurrent.locks.ReadWriteLock +import java.util.concurrent.locks.ReentrantReadWriteLock +import kotlin.concurrent.withLock +import kotlin.concurrent.write +import kotlin.reflect.KProperty + +class ReadWriteLockMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, + private val readWriteLock: ReadWriteLock = ReentrantReadWriteLock(), +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + constructor( + initValue: V, + readWriteLock: ReadWriteLock = ReentrantReadWriteLock(), + ) : this(MutableDelegatedFieldValue(initValue), readWriteLock) + + override fun getValue(thisRef: T, property: KProperty<*>): V { + val rl = readWriteLock.readLock() + rl.lock() + try { + return mutableDelegatedField.getValue(thisRef, property) + } finally { + rl.unlock() + } + } + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + if (readWriteLock is ReentrantReadWriteLock) readWriteLock.write { + mutableDelegatedField.setValue(thisRef, property, value) + } else readWriteLock.writeLock().withLock { + mutableDelegatedField.setValue(thisRef, property, value) + } + } + + override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { + if (readWriteLock is ReentrantReadWriteLock) readWriteLock.write { + mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + } else readWriteLock.writeLock().withLock { + mutableDelegatedField.setValue(thisRef, property, value) + } + } +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/SetterDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/SetterDelegatedField.kt new file mode 100644 index 0000000..140654c --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/SetterDelegatedField.kt @@ -0,0 +1,8 @@ +package cn.tursom.delegation + +class SetterDelegatedField( + override val delegatedField: DelegatedField, + val setter: DelegatedField.(value: V) -> Unit, +) : MutableDelegatedField, DelegatedField by delegatedField, DecoratorDelegatedField { + override fun setValue(value: V) = delegatedField.setter(value) +} diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/SetterMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/SetterMutableDelegatedField.kt new file mode 100644 index 0000000..5bfb42b --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/SetterMutableDelegatedField.kt @@ -0,0 +1,12 @@ +package cn.tursom.delegation + +import kotlin.reflect.KProperty + +class SetterMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, + val setter: MutableDelegatedField.(thisRef: T, property: KProperty<*>, value: V) -> Unit, +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + mutableDelegatedField.setter(thisRef, property, value) + } +} diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/SimpThreadLocalMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/SimpThreadLocalMutableDelegatedField.kt new file mode 100644 index 0000000..0aadf5d --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/SimpThreadLocalMutableDelegatedField.kt @@ -0,0 +1,14 @@ +package cn.tursom.delegation + +import cn.tursom.core.SimpThreadLocal + + +class SimpThreadLocalMutableDelegatedField( + private val threadLocal: SimpThreadLocal, + val new: () -> V +) : MutableDelegatedField { + constructor(new: () -> V) : this(SimpThreadLocal(new = new), new) + + override fun setValue(value: V) = threadLocal.set(value) + override fun getValue(): V = threadLocal.get() +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/ThreadLocalMutableDelegatedField.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/ThreadLocalMutableDelegatedField.kt new file mode 100644 index 0000000..ba5ee3f --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/ThreadLocalMutableDelegatedField.kt @@ -0,0 +1,8 @@ +package cn.tursom.delegation + +class ThreadLocalMutableDelegatedField( + private val threadLocal: ThreadLocal = ThreadLocal() +) : MutableDelegatedField { + override fun setValue(value: V?) = threadLocal.set(value) + override fun getValue(): V? = threadLocal.get() +} \ No newline at end of file diff --git a/utils/delegation/src/main/kotlin/cn/tursom/delegation/delegations.kt b/utils/delegation/src/main/kotlin/cn/tursom/delegation/delegations.kt new file mode 100644 index 0000000..f0e5428 --- /dev/null +++ b/utils/delegation/src/main/kotlin/cn/tursom/delegation/delegations.kt @@ -0,0 +1,95 @@ +@file:Suppress("unused") + +package cn.tursom.delegation + +import cn.tursom.core.SimpThreadLocal +import cn.tursom.core.cast +import cn.tursom.core.castOrNull +import cn.tursom.core.receiver +import java.util.concurrent.Executor +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReadWriteLock +import java.util.concurrent.locks.ReentrantLock +import java.util.concurrent.locks.ReentrantReadWriteLock +import kotlin.reflect.KClass +import kotlin.reflect.KMutableProperty0 +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty0 +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.isAccessible + +fun getDelegate(obj: Any?, field: String): DelegatedField<*, *>? { + obj ?: return null + val kProperty1 = obj.javaClass.kotlin.memberProperties.firstOrNull { it.name == field } + kProperty1?.isAccessible = true + val delegate = kProperty1?.getDelegate(obj) + return delegate.castOrNull() +} + +val KProperty0.getOwnerDelegated: DelegatedField<*, V>? + get() = getDelegate(receiver, name).castOrNull() + +val KProperty0.getDelegatedValue: V? + get() { + val delegate = getDelegate() ?: getOwnerDelegated + return delegate?.castOrNull>()?.getValue() + } + +fun KProperty0.setDelegatedValue(value: V): Boolean { + val delegate = getDelegate() ?: getOwnerDelegated + delegate.castOrNull>()?.setValue(value) ?: return false + return true +} + +/** + * 将可空属性委托为不可空属性 + */ +fun T.delegated(value: V): MutableDelegatedField = MutableDelegatedFieldValue(value) +fun T.delegated(@Suppress("UNUSED_PARAMETER") target: T, value: V): MutableDelegatedField = + MutableDelegatedFieldValue(value) + +val KProperty0.delegated: DelegatedField get() = KPropertyDelegatedField(this) +val KMutableProperty0.delegated: MutableDelegatedField get() = KPropertyMutableDelegatedField(this) +val KProperty0.delegatedNotNull get() = delegated.notNull +val KMutableProperty0.delegatedNotNull: MutableDelegatedField get() = delegated.notNull + +val DelegatedField.notNull: DelegatedField get() = NotNullDelegatedField(this) +val MutableDelegatedField.notNull: MutableDelegatedField + get() = NotNullMutableDelegatedField(cast()) + +val MutableDelegatedField.locked: MutableDelegatedField get() = LockMutableDelegatedField(this) +fun MutableDelegatedField.locked(lock: Lock = ReentrantLock()): MutableDelegatedField = + LockMutableDelegatedField(this, lock) + +val MutableDelegatedField.readWriteLocked: MutableDelegatedField + get() = ReadWriteLockMutableDelegatedField(this) + +fun MutableDelegatedField.readWriteLocked(readWriteLock: ReadWriteLock = ReentrantReadWriteLock()): MutableDelegatedField = + ReadWriteLockMutableDelegatedField(this, readWriteLock) + +fun T.threadLocalDelegated(): MutableDelegatedField = ThreadLocalMutableDelegatedField() +fun T.threadLocalDelegated(type: Class): MutableDelegatedField = ThreadLocalMutableDelegatedField() +fun T.threadLocalDelegated(type: KClass): MutableDelegatedField = + ThreadLocalMutableDelegatedField() + +fun T.threadLocalDelegated(new: () -> V): MutableDelegatedField = SimpThreadLocalMutableDelegatedField(new) +fun T.threadLocalDelegated(simpThreadLocal: SimpThreadLocal, new: () -> V): MutableDelegatedField = + SimpThreadLocalMutableDelegatedField(simpThreadLocal, new) + +fun MutableDelegatedField.filter(filter: T.(old: V, new: V) -> Boolean): MutableDelegatedField = + FilterDelegatedField(this, filter) + +fun DelegatedField.setter(setter: DelegatedField.(value: V) -> Unit): DelegatedField = + SetterDelegatedField(this, setter) + +fun MutableDelegatedField.setter(setter: MutableDelegatedField.(thisRef: T, property: KProperty<*>, value: V) -> Unit): MutableDelegatedField = + SetterMutableDelegatedField(this, setter) + +fun DelegatedField.getter(getter: DelegatedField.(thisRef: T, property: KProperty<*>) -> V): DelegatedField = + GetterDelegatedField(this, getter) + +fun MutableDelegatedField.getter(getter: MutableDelegatedField.(thisRef: T, property: KProperty<*>) -> V): MutableDelegatedField = + GetterMutableDelegatedField(this, getter) + +fun MutableDelegatedField.withExecutor(executor: Executor): MutableDelegatedField = + ExecutorMutableDelegatedField(this, executor) diff --git a/utils/observer/build.gradle b/utils/observer/build.gradle new file mode 100644 index 0000000..f5150db --- /dev/null +++ b/utils/observer/build.gradle @@ -0,0 +1,4 @@ +dependencies { + compile project(":") + compile project(":utils:delegation") +} diff --git a/utils/observer/src/main/kotlin/cn/tursom/observer/Observable.kt b/utils/observer/src/main/kotlin/cn/tursom/observer/Observable.kt new file mode 100644 index 0000000..c8f113e --- /dev/null +++ b/utils/observer/src/main/kotlin/cn/tursom/observer/Observable.kt @@ -0,0 +1,10 @@ +package cn.tursom.observer + +/** + * 标识一个属性可以被指定的 FieldChangeListener 监听 + * 属性的实现者应该实现相应的逻辑 + */ +@RequiresOptIn +@Retention(AnnotationRetention.BINARY) +@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class Observable \ No newline at end of file diff --git a/utils/observer/src/main/kotlin/cn/tursom/observer/ObservableMutableDelegatedField.kt b/utils/observer/src/main/kotlin/cn/tursom/observer/ObservableMutableDelegatedField.kt new file mode 100644 index 0000000..a2c4a4d --- /dev/null +++ b/utils/observer/src/main/kotlin/cn/tursom/observer/ObservableMutableDelegatedField.kt @@ -0,0 +1,64 @@ +package cn.tursom.observer + +import cn.tursom.core.cast +import cn.tursom.delegation.DecoratorMutableDelegatedField +import cn.tursom.delegation.DelegatedFieldAttachmentKey +import cn.tursom.delegation.MutableDelegatedField +import java.util.concurrent.ConcurrentLinkedDeque +import kotlin.reflect.KProperty + +@Observable +class ObservableMutableDelegatedField( + override val mutableDelegatedField: MutableDelegatedField, +) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { + companion object : DelegatedFieldAttachmentKey + + override fun get(key: DelegatedFieldAttachmentKey): K? { + return if (key == Companion) true.cast() else super.get(key) + } + + private val listenerList = ConcurrentLinkedDeque Unit>() + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + val oldValue = getValue() + listenerList.forEach { + thisRef.it(oldValue, value) + } + mutableDelegatedField.setValue(thisRef, property, value) + } + + override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { + listenerList.forEach { + thisRef.it(oldValue, value) + } + mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + } + + fun addListener(listener: T.(old: V, new: V) -> Unit): Observer { + var catch: (T.(old: V, new: V, e: Throwable) -> Unit)? = null + var finally: (T.(old: V, new: V) -> Unit)? = null + listenerList.add { old, new -> + try { + listener(old, new) + } catch (e: Throwable) { + catch?.invoke(this, old, new, e) + } finally { + finally?.invoke(this, old, new) + } + } + return object : Observer { + override fun cancel() = listenerList.remove(listener) + + override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Observer { + catch = handler + return this + } + + override fun finally(handler: T.(old: V, new: V) -> Unit): Observer { + finally = handler + return this + } + + } + } +} \ No newline at end of file diff --git a/utils/observer/src/main/kotlin/cn/tursom/observer/ObservableObserver.kt b/utils/observer/src/main/kotlin/cn/tursom/observer/ObservableObserver.kt new file mode 100644 index 0000000..b7b5007 --- /dev/null +++ b/utils/observer/src/main/kotlin/cn/tursom/observer/ObservableObserver.kt @@ -0,0 +1,6 @@ +package cn.tursom.observer + +interface ObservableObserver : Observer { + infix fun addListener(listener: T.(old: V, new: V) -> Unit): Observer + override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ObservableObserver +} diff --git a/utils/observer/src/main/kotlin/cn/tursom/observer/Observer.kt b/utils/observer/src/main/kotlin/cn/tursom/observer/Observer.kt new file mode 100644 index 0000000..9529cd7 --- /dev/null +++ b/utils/observer/src/main/kotlin/cn/tursom/observer/Observer.kt @@ -0,0 +1,7 @@ +package cn.tursom.observer + +interface Observer { + fun cancel(): Boolean + infix fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Observer + infix fun finally(handler: T.(old: V, new: V) -> Unit): Observer +} \ No newline at end of file diff --git a/utils/observer/src/main/kotlin/cn/tursom/observer/UnmonitoredFieldException.kt b/utils/observer/src/main/kotlin/cn/tursom/observer/UnmonitoredFieldException.kt new file mode 100644 index 0000000..4135fe1 --- /dev/null +++ b/utils/observer/src/main/kotlin/cn/tursom/observer/UnmonitoredFieldException.kt @@ -0,0 +1,14 @@ +package cn.tursom.observer + +class UnmonitoredFieldException : Exception { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) + constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super( + message, + cause, + enableSuppression, + writableStackTrace + ) +} \ No newline at end of file diff --git a/utils/observer/src/main/kotlin/cn/tursom/observer/utils.kt b/utils/observer/src/main/kotlin/cn/tursom/observer/utils.kt new file mode 100644 index 0000000..68e07fd --- /dev/null +++ b/utils/observer/src/main/kotlin/cn/tursom/observer/utils.kt @@ -0,0 +1,120 @@ +package cn.tursom.observer + + +import cn.tursom.core.cast +import cn.tursom.core.receiver +import cn.tursom.delegation.* +import java.util.concurrent.ConcurrentLinkedQueue +import kotlin.reflect.KMutableProperty0 +import kotlin.reflect.KProperty0 +import kotlin.reflect.jvm.isAccessible + +@Observable +fun KMutableProperty0.listenable(): MutableDelegatedField { + isAccessible = true + val delegate = getDelegate() + return if (delegate is MutableDelegatedField<*, *> && delegate[ObservableMutableDelegatedField] == true) { + delegate.cast() + } else { + ObservableMutableDelegatedField(KPropertyMutableDelegatedField(cast())) + } +} + +@Observable +fun listenable(initValue: V): MutableDelegatedField = ObservableMutableDelegatedField( + MutableDelegatedFieldValue(initValue) +) + +@Observable +fun MutableDelegatedField.listenable(): MutableDelegatedField = + ObservableMutableDelegatedField(this) + +@OptIn(Observable::class) +fun KProperty0.getListenableMutableDelegatedField(): ObservableMutableDelegatedField? { + isAccessible = true + var delegate = getDelegate() ?: getDelegate(receiver, name) + if (delegate is DelegatedField<*, *>) { + while (true) { + if (delegate is ObservableMutableDelegatedField<*, *>) { + return delegate.cast() + } + if (delegate is DecoratorDelegatedField<*, *>) { + delegate = delegate.delegatedField + } else { + break + } + } + } else if (delegate is KProperty0<*>) { + return delegate.cast>().getListenableMutableDelegatedField() + } + return null +} + +inline fun T.addChangeListener( + property: T.() -> KProperty0, +): ObservableObserver { + val kProperty0 = property() + + @OptIn(Observable::class) + val delegatedField = kProperty0 + .getListenableMutableDelegatedField() + .cast?>() + ?: throw UnmonitoredFieldException(kProperty0.toString()) + return object : ObservableObserver { + private val selfList = ConcurrentLinkedQueue>() + override fun addListener(listener: T.(old: V, new: V) -> Unit): Observer { + @OptIn(Observable::class) + val listener1 = delegatedField.addListener(listener) + selfList.add(listener1) + return listener1 + } + + override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ObservableObserver { + selfList.forEach { + it.catch(handler) + } + return this + } + + override fun cancel(): Boolean { + selfList.forEach { + it.cancel() + } + return true + } + + override fun finally(handler: T.(old: V, new: V) -> Unit): Observer { + selfList.forEach { + it.finally(handler) + } + return this + } + } +} + + +infix operator fun ObservableObserver.invoke(listener: T.(old: V, new: V) -> Unit): Observer = + addListener(listener) + +infix fun ObservableObserver.with(listener: T.(old: V, new: V) -> Unit): Observer = + addListener(listener) + +infix fun ObservableObserver.and(listener: T.(old: V, new: V) -> Unit): Observer = + addListener(listener) + +infix operator fun ObservableObserver.plus(listener: T.(old: V, new: V) -> Unit): Observer = + addListener(listener) + +infix fun KProperty0.listen(listener: Any.(old: V, new: V) -> Unit): Observer { + @OptIn(Observable::class) + return getListenableMutableDelegatedField() + ?.addListener(listener) + ?: throw UnmonitoredFieldException(toString()) +} + +fun T.listen(property: KProperty0, listener: T.(old: V, new: V) -> Unit): Observer { + @OptIn(Observable::class) + return property.getListenableMutableDelegatedField() + ?.addListener(listener.cast()) + ?: throw UnmonitoredFieldException(toString()) +} diff --git a/utils/src/main/kotlin/cn/tursom/utils/asynclock/AsyncWaitList.kt b/utils/src/main/kotlin/cn/tursom/utils/asynclock/AsyncWaitList.kt index f91150c..6d8b976 100644 --- a/utils/src/main/kotlin/cn/tursom/utils/asynclock/AsyncWaitList.kt +++ b/utils/src/main/kotlin/cn/tursom/utils/asynclock/AsyncWaitList.kt @@ -1,6 +1,6 @@ package cn.tursom.utils.asynclock -import cn.tursom.core.unsafe +import cn.tursom.core.Unsafe.unsafe import java.io.Closeable import kotlin.coroutines.Continuation import kotlin.coroutines.resume diff --git a/utils/src/main/kotlin/cn/tursom/utils/bytebuffer/serialize.kt b/utils/src/main/kotlin/cn/tursom/utils/bytebuffer/serialize.kt index 0f89f6f..85f8c09 100644 --- a/utils/src/main/kotlin/cn/tursom/utils/bytebuffer/serialize.kt +++ b/utils/src/main/kotlin/cn/tursom/utils/bytebuffer/serialize.kt @@ -9,9 +9,9 @@ package cn.tursom.utils.bytebuffer * will support */ +import cn.tursom.core.Unsafe.unsafe import cn.tursom.core.buffer.ByteBuffer import cn.tursom.core.isStatic -import cn.tursom.core.unsafe class UnsupportedException : Exception() diff --git a/web/src/main/kotlin/cn/tursom/web/router/impl/ColonRouter.kt b/web/src/main/kotlin/cn/tursom/web/router/impl/ColonRouter.kt index 2658958..fd47516 100644 --- a/web/src/main/kotlin/cn/tursom/web/router/impl/ColonRouter.kt +++ b/web/src/main/kotlin/cn/tursom/web/router/impl/ColonRouter.kt @@ -1,7 +1,7 @@ package cn.tursom.web.router.impl import cn.tursom.core.binarySearch -import cn.tursom.web.router.* +import cn.tursom.web.router.Router import cn.tursom.web.router.impl.colonnode.AnyColonNode import cn.tursom.web.router.impl.colonnode.ColonNode import cn.tursom.web.router.impl.colonnode.IColonNode @@ -29,31 +29,31 @@ class ColonRouter : Router { routeNode = when { r.isEmpty() -> routeNode - r == "*" -> routeNode.wildSubRouter ?: { + r == "*" -> routeNode.wildSubRouter ?: run { val node = AnyColonNode(routeList, index) routeNode.wildSubRouter = node index = routeList.size - 1 node - }() + } r[0] == ':' -> run { val node = synchronized(routeNode.placeholderRouterList!!) { val matchLength = PlaceholderColonNode.matchLength(routeList, index) - routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength } ?: { + routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength } ?: run { routeNode.addNode(routeList, index, null) routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength }!! - }() + } } index += node.size - 1 node } else -> synchronized(routeNode.subRouterMap) { - routeNode.subRouterMap[r] ?: { + routeNode.subRouterMap[r] ?: run { val node = ColonNode(routeList, index) routeNode.subRouterMap[r] = node node - }() + } } } index++