This commit is contained in:
tursom 2021-04-12 11:22:54 +08:00
parent b0cd840376
commit cc32906fc9
22 changed files with 807 additions and 512 deletions

View File

@ -7,6 +7,7 @@ include("ts-core:ts-pool")
include("ts-core:ts-hash")
include("ts-core:ts-log")
include("ts-core:ts-delegation")
include("ts-core:ts-delegation:ts-observer")
include("ts-core:ts-clone")
include("ts-core:ts-mail")
include("ts-core:ts-coroutine")

View File

@ -0,0 +1,123 @@
package cn.tursom.core
object TextColor {
const val reset = "\u001b[0m"
enum class DisplayType(val code: Int) {
DEFAULT(0), HIGHLIGHT(1), INTENSITY(2), ITALIC(3), UNDERLINE(4),
SLOW_BLINK(5), RAPID_BLINK(6), REVERSE(7), INVISIBLE(8), CROSSED_OUT(9),
UNDERLINE_OFF(24), BLINK_OFF(25), REVERSE_OFF(27), INVISIBLE_OFF(28), CROSSED_OUT_OFF(29),
OVER_LINE(53), OVER_LINE_OFF(55);
val strCode = "\u001b[${code}m"
}
fun textColor(displayType: DisplayType, textColor: Int, backgroundColor: Int) =
"\u001B[${displayType.code};$textColor;${backgroundColor}m"
fun rgbTextColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) =
"\u001B[${displayType.code};38;2;$r;$g;${b}m"
fun rgbBackgroundColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) =
"\u001B[${displayType.code};48;2;$r;$g;${b}m"
const val black = "\u001b[30m"
const val red = "\u001b[31m"
const val green = "\u001b[32m"
const val yellow = "\u001b[33m"
const val blue = "\u001b[34m"
const val magenta = "\u001b[35m"
const val cyan = "\u001b[36m"
const val white = "\u001b[37m"
const val brightBlack = "\u001b[30;1m"
const val brightRed = "\u001b[31;1m"
const val brightGreen = "\u001b[32;1m"
const val brightYellow = "\u001b[33;1m"
const val brightBlue = "\u001b[34;1m"
const val brightMagenta = "\u001b[35;1m"
const val brightCyan = "\u001b[36;1m"
const val brightWhite = "\u001b[37;1m"
val textColor = Array(256) {
"\u001b[38;5;${it}m"
}
fun textColor(color: Int) = textColor[color]
fun textColor(color: Int, displayType: DisplayType = DisplayType.DEFAULT) =
"\u001B[${displayType.code};38;5;${color}m"
const val blackBackground = "\u001b[40m"
const val redBackground = "\u001b[41m"
const val greenBackground = "\u001b[42m"
const val yellowBackground = "\u001b[43m"
const val blueBackground = "\u001b[44m"
const val magentaBackground = "\u001b[45m"
const val cyanBackground = "\u001b[46m"
const val whiteBackground = "\u001b[47m"
const val brightBlackBackground = "\u001b[40;1m"
const val brightRedBackground = "\u001b[41;1m"
const val brightGreenBackground = "\u001b[42;1m"
const val brightYellowBackground = "\u001b[43;1m"
const val brightBlueBackground = "\u001b[44;1m"
const val brightMagentaBackground = "\u001b[45;1m"
const val brightCyanBackground = "\u001b[46;1m"
const val brightWhiteBackground = "\u001b[47;1m"
val backgroundColor = Array(256) {
"\u001b[48;5;${it}m"
}
const val bold = "\u001b[1m"
const val underline = "\u001b[4m"
const val reverseColor = "\u001b[7m"
const val up = "\u001b[1A"
const val down = "\u001b[1B"
const val left = "\u001b[1C"
const val right = "\u001b[1D"
const val downToNextLine = "\u001b[1E"
const val upToPrevLine = "\u001b[1F"
fun up(step: Int) = "\u001b[${step}A"
fun down(step: Int) = "\u001b[${step}B"
fun left(step: Int) = "\u001b[${step}C"
fun right(step: Int) = "\u001b[${step}D"
fun downToNextLine(step: Int) = "\u001b[${step}E"
fun upToPrevLine(step: Int) = "\u001b[${step}F"
fun jumpToLine(line: Int) = "\u001b[${line}G"
fun jump(line: Int, row: Int) = "\u001b[${line};${row}H"
const val cleanScreenToEnd = "\u001b[0J"
const val cleanScreenFromStart = "\u001b[1J"
const val cleanScreen = "\u001b[2J"
const val cleanLineToEnd = "\u001b[0K"
const val cleanLineFromStart = "\u001b[1K"
const val cleanLine = "\u001b[2K"
const val savePosition = "\u001b[s"
const val loadPosition = "\u001b[u"
fun rgbTo8Color(R: Int, G: Int, B: Int): Int {
//8色化处理,取RGB的高1位相与。
val r1 = R shr 5 and 0x4
val g1 = G shr 6 and 0x2
val b1 = B shr 7
return (r1 or g1 or b1) + 1
}
fun rgbTo16Color(R: Int, G: Int, B: Int): Int {
//16色化处理取R、G的高1位和B的高2位相与
val r1 = R shr 4 and 0x8
val g1 = G shr 5 and 0x4
val b1 = B shr 6 and 0x3
return (r1 or g1 or b1) + 1
}
fun rgbTo256Color(r: Int, g: Int, b: Int): Int = ((r / 32 shl 5) + (g / 32 shl 2) + b / 64) and 0xFF
}

View File

@ -53,8 +53,12 @@ object Utils {
.create()
}
@Suppress("SpellCheckingInspection")
internal val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
@Suppress("SpellCheckingInspection")
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")!! }
@ -62,6 +66,7 @@ object Utils {
val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! }
val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! }
@Suppress("SpellCheckingInspection")
internal val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray()
val receiverField: Field by lazy {
@ -135,7 +140,7 @@ inline fun <T> T?.checkNull(ifNull: () -> Exception): T {
}
}
fun String.emptyToNull() = if (isEmpty()) null else this
fun String.emptyToNull() = ifEmpty { null }
inline fun <reified T> getClazz() = T::class.java
@ -251,7 +256,7 @@ fun <A : Annotation, V : Any> A.changeAnnotationValue(field: KProperty1<A, V>, v
val h = Proxy.getInvocationHandler(this)
val memberValuesField = h.javaClass.getDeclaredField("memberValues")
memberValuesField.isAccessible = true
val memberValues = memberValuesField[h].cast<MutableMap<String, Any>>()
val memberValues = memberValuesField[h].uncheckedCast<MutableMap<String, Any>>()
memberValues[field.name] = value
true
} catch (e: Exception) {
@ -366,7 +371,7 @@ val KProperty<*>.receiver: Any?
val KProperty<*>.owner: Class<*>?
get() = try {
Utils.ownerField.get(this)?.cast<Class<*>>()
Utils.ownerField.get(this)?.uncheckedCast<Class<*>>()
} catch (e: Exception) {
null
} ?: javaClass.getFieldForAll("owner")?.let {
@ -406,16 +411,6 @@ fun Any.serialize(): ByteArray {
return outputStream.toByteArray()
}
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 生成结果否则范湖自身
*/
@ -452,9 +447,9 @@ inline val KClass<*>.companionObjectInstanceOrNull: Any?
null
}
inline val <K : Any, V> Map<K?, V>.notNullKey get() = cast<Map<K, V>>()
inline val <K, V : Any> Map<K, V?>.notNullValue get() = cast<Map<K, V>>()
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = cast<Map<K, V>>()
inline val <K : Any, V> Map<K?, V>.notNullKey get() = uncheckedCast<Map<K, V>>()
inline val <K, V : Any> Map<K, V?>.notNullValue get() = uncheckedCast<Map<K, V>>()
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = uncheckedCast<Map<K, V>>()
inline val <K : Any, V> Map<K?, V>.filterNullKey get() = filter { it.key != null }.notNullKey
inline val <K, V : Any> Map<K, V?>.filterNullValue get() = filter { it.value != null }.notNullValue
@ -466,7 +461,7 @@ val <T : Any> KClass<T>.allMemberProperties: List<KProperty1<T, *>>
!it.java.isInterface
}
while (superClass != null) {
propertiesList.addAll(superClass.memberProperties.cast())
propertiesList.addAll(superClass.memberProperties.uncheckedCast())
superClass = superClass.superclasses.firstOrNull {
!it.java.isInterface
}

View File

@ -6,6 +6,7 @@ plugins {
dependencies {
implementation(project(":"))
implementation(project(":ts-core"))
implementation(project(":ts-core:ts-log"))
implementation(project(":ts-core:ts-datastruct"))
}

View File

@ -0,0 +1,55 @@
package cn.tursom.core.clone
import cn.tursom.core.Unsafe
import cn.tursom.core.uncheckedCast
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KClass
object InstantAllocator {
enum class AllocateFunction { INSTANCE, UNSAFE, KOBJECT, NONE }
private val allocateFunctionMap = ConcurrentHashMap<Class<*>, AllocateFunction>()
@Throws(NoSuchMethodException::class)
operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe)
@Throws(NoSuchMethodException::class)
inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe)
@Throws(NoSuchMethodException::class)
operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe)
@Throws(NoSuchMethodException::class)
operator fun <T> get(clazz: Class<out T>, unsafe: Boolean = true): T {
return when (allocateFunctionMap[clazz]) {
null -> try {
val newInstance = clazz.newInstance()
allocateFunctionMap[clazz] = AllocateFunction.INSTANCE
newInstance
} catch (e: Exception) {
val kClass = clazz.kotlin
val objectInstance = kClass.objectInstance
if (objectInstance != null) {
allocateFunctionMap[clazz] = AllocateFunction.KOBJECT
objectInstance
} else if (unsafe) try {
allocateFunctionMap[clazz] = AllocateFunction.UNSAFE
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
} catch (e: Exception) {
allocateFunctionMap[clazz] = AllocateFunction.NONE
throw NoSuchMethodException("${clazz.name}:<init>()")
} else {
throw NoSuchMethodException("${clazz.name}:<init>()")
}
}
AllocateFunction.INSTANCE -> clazz.newInstance()
AllocateFunction.UNSAFE -> if (unsafe) {
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
} else {
throw NoSuchMethodException("${clazz.name}:<init>()")
}
AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!!
AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:<init>()")
}
}
}

View File

@ -1,110 +1,22 @@
@file:Suppress("unused")
package cn.tursom.core.clone
import cn.tursom.core.Unsafe
import cn.tursom.core.cast
import cn.tursom.core.*
import cn.tursom.core.datastruct.ArrayMap
import cn.tursom.core.datastruct.KPropertyValueMap
import cn.tursom.core.datastruct.ReadWriteMap
import cn.tursom.core.datastruct.SoftArrayMap
import cn.tursom.core.final
import cn.tursom.log.impl.Slf4jImpl
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaType
/**
* clone 使用的日志对象
*/
private val logger = Slf4jImpl.getLogger()
/**
* clone 使用的对象属性类型
*/
typealias Property<T> = KProperty1<T, Any?>
val Any.valueMap: Map<String, Any?>
get() = if (this is Map<*, *>) {
cast()
} else {
KPropertyValueMap(this)
}
private val injectMapCache = ReadWriteMap<KClass<*>, ArrayMap<String, Property<*>?>>(SoftArrayMap(HashMap()))
val <T : Any> KClass<T>.injectMap: ArrayMap<String, Property<T>?>
@Suppress("UNCHECKED_CAST")
get() = let {
var valueMap = injectMapCache[it] as ArrayMap<String, Property<T>?>?
if (valueMap == null) {
val properties = it.memberProperties
valueMap = ArrayMap(properties.size)
(properties as Collection<Property<T>>).forEach { property ->
property.isAccessible = true
valueMap[property.name] = property
}
injectMapCache[it] = valueMap as ArrayMap<String, Property<*>?>
}
valueMap.copy()
}
private val <T : Any> T.injectMap: ArrayMap<String, Property<T>?>
@Suppress("UNCHECKED_CAST")
get() = (this::class as KClass<T>).injectMap
private val <T> Array<out Pair<Property<*>, Property<T>?>>.injectMap get() = iterator().injectMap
private val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
get() = let {
val valueMap = ArrayMap<String, Property<T>?>()
@Suppress("UNCHECKED_CAST")
forEach { (k, field) ->
field?.isAccessible = true
valueMap[k.name] = field
}
//logger.trace("Iterator.injectMap: {}", valueMap)
valueMap
}
private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<T>?> = this::class
.cast<KClass<T>>()
.injectMap
.also {
if (clazz == null) return@also
val clazzThis = this::class.java
fun import(relation: Relation, property: Property<T>) {
if (relation.clazz != clazz) return
//logger.trace("relation {} to {}", relation.property, property.name)
it[relation.property] = when {
relation.skip -> null
relation.handler.isEmpty() -> property
else -> try {
val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java)
handler.isAccessible = true
object : KMutableProperty1<T, Any?>, KProperty1<T, Any?> by property {
override val setter: KMutableProperty1.Setter<T, Any?> get() = TODO()
override fun set(receiver: T, value: Any?) =
handler(this@injectMap, value).inject(receiver, property)
}
} catch (e: Exception) {
//logger.warn("an exception caused on generate inject handler", e)
null
}
}
}
fun parseAnnotation(annotation: Annotation, property: Property<T>) {
when (annotation) {
is Relation -> import(annotation, property)
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
}
}
this::class.memberProperties.cast<Collection<KProperty1<T, *>>>().forEach { property ->
property.annotations.forEach { annotation -> parseAnnotation(annotation, property) }
(property.javaField ?: return@forEach).annotations.forEach { annotation ->
parseAnnotation(annotation, property)
}
}
}
/**
* 用于形式化的将List中的数据映射到实体类上
@ -122,7 +34,7 @@ private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<
*/
inline fun <reified T : Any, S : Any> List<S?>.clone(
unsafe: Boolean = true,
vararg relation: Pair<Property<S>, Property<T>?>
vararg relation: Pair<Property<S>, Property<T>?>,
): List<T> {
val list = ArrayList<T>(size)
val memberMap = T::class.injectMap
@ -131,25 +43,28 @@ inline fun <reified T : Any, S : Any> List<S?>.clone(
}
forEach {
it ?: return@forEach
val target = instance<T>(unsafe) ?: return@forEach
list.add(it.inject(target, memberMap.iterator()))
try {
val target = InstantAllocator[T::class.java, unsafe]
list.add(it.inject(target, memberMap.iterator()))
} catch (e: Exception) {
}
}
return list
}
inline fun <reified T : Any> List<Any?>.clone(
unsafe: Boolean = true,
vararg relation: Property<T>?
): T = clone(instance<T>(unsafe)!!, relation.iterator())
vararg relation: Property<T>?,
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
fun <T : Any> List<Any?>.clone(
target: T,
vararg relation: Property<T>?
vararg relation: Property<T>?,
): T = clone(target, relation.iterator())
fun <T : Any> List<Any?>.clone(
target: T,
relation: Iterator<Property<T>?>
relation: Iterator<Property<T>?>,
): T = relation.mapIndexed { index, kProperty1 ->
(kProperty1 ?: return@mapIndexed null).name to this[index]
}.clone(target)
@ -157,29 +72,30 @@ fun <T : Any> List<Any?>.clone(
/**
* 新建并拷贝
* @author 王景阔
* 创建类型 T 的实例
* 并将对象两个的所有同名字段拷贝进新建的实例中
* @return 新建的实例
* @param unsafe 是否允许使用 Unsafe 创建对象unsafe 不需调用构造函数可以在没有默认构造函数的情况下生成对象
*/
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(instance<T>(unsafe)!!)
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(InstantAllocator[T::class.java, unsafe])
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(instance(unsafe, clazz)!!)
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(InstantAllocator[clazz, unsafe])
@JvmName("unsafeClone")
inline fun <reified T : Any> Any.clone(
unsafe: Boolean = true,
vararg relation: Pair<String, Property<T>?>
): T = clone(instance<T>(unsafe)!!, relation.iterator())
vararg relation: Pair<String, Property<T>?>,
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
inline fun <reified T : Any, S : Any> S.clone(
unsafe: Boolean = true,
vararg relation: Pair<Property<S>, Property<T>?>
): T = clone(instance<T>(unsafe)!!, relation.iterator())
vararg relation: Pair<Property<S>, Property<T>?>,
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
fun Any.cloneMap(): Map<in String, Any?> = when (this) {
is Map<*, *> -> @Suppress("UNCHECKED_CAST") (this as Map<Any?, Any?>).mapKeys { it.key.toString() }
is Map<*, *> -> uncheckedCast<Map<Any?, Any?>>().mapKeys { it.key.toString() }
is Iterator<*> -> {
val valueMap = HashMap<String, Any?>()
(this as Iterator<Any?>).forEach {
@ -201,22 +117,22 @@ fun <T : Any> Any.clone(target: T): T = apply { injectWithoutProperty(target) }.
fun <T : Any, S : Any> S.clone(
target: T,
iterator: Iterator<Pair<Property<S>, Property<T>?>>
iterator: Iterator<Pair<Property<S>, Property<T>?>>,
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
valueMap
//.also { logger.trace("clone {} into {}, value map:{}", this, target, it) }
.also { logger.trace("clone {} into {}, value map:{}", this, target, it) }
.clone(target, iterator.injectMap.iterator(), this::class)
}
fun <T : Any> Any.clone(
target: T,
vararg relation: Pair<String, Property<T>?>
vararg relation: Pair<String, Property<T>?>,
): T = clone(target, relation.iterator())
@JvmName("unsafeClone")
fun <T : Any> Any.clone(
target: T,
iterator: Iterator<Pair<String, Property<T>?>>
iterator: Iterator<Pair<String, Property<T>?>>,
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
valueMap.clone(target, iterator, this::class)
}
@ -225,9 +141,9 @@ fun <T : Any> Any.clone(
fun <T : Any> Map<in String, Any?>.clone(
target: T,
iterator: Iterator<Pair<String, Property<T>?>>,
clazz: KClass<*>? = null
clazz: KClass<*>? = null,
): T {
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
val memberMap = target.injectMap(clazz)
iterator.forEach { (k, v) ->
memberMap[k] = v
}
@ -238,9 +154,9 @@ fun <T : Any> Map<in String, Any?>.clone(
fun <T : Any> Map<in String, Any?>.clone(
target: T,
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
clazz: KClass<*>? = null
clazz: KClass<*>? = null,
): T {
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
val memberMap = target.injectMap(clazz)
iterator.forEach { (k, v) ->
memberMap[k.get(target)?.toString() ?: return@forEach] = v
}
@ -251,13 +167,13 @@ fun <T : Any> Map<in String, Any?>.clone(
fun <T : Any> Map<in String, Any?>.clone(
target: T,
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
clazz: KClass<*>? = null
clazz: KClass<*>? = null,
): T {
val memberMap = target.injectMap(clazz)
iterator.forEach { (k, v) ->
memberMap[k ?: return@forEach] = v
}
//logger.trace("inject {} into {}, mapping: {}", this, target, memberMap)
logger.trace("inject {} into {}, mapping: {}", this, target, memberMap)
return inject(target, memberMap.iterator())
}
@ -268,229 +184,6 @@ fun <T : Any> Any.checkPropertyClone(target: T, ifClone: () -> T): T =
target
}
//fun <T> Any.checkPropertyClone(targetClass: KClass<out Any>, ifClone: () -> T): T {
// if (targetClass.findAnnotation<NoPropertyClone>()?.classList?.contains(this::class) != true)
// ifClone()
//}
fun <T : Any> Any.injectWithoutProperty(target: T): T {
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try {
val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java)
handler.isAccessible = true
handler(target, this)?.inject(target, property)
} catch (e: Exception) {
//logger.warn("an exception caused on global inject", e)
}
}
target::class.memberProperties
.cast<Collection<KProperty1<Any, *>>>()
.forEach { property ->
property.annotations.forEach { annotation ->
when (annotation) {
is Relation -> parseAnnotation(annotation, property)
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
}
}
property.javaField?.annotations?.forEach { annotation ->
when (annotation) {
is Relation -> parseAnnotation(annotation, property)
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
}
}
}
return target
}
fun <T : Any> Any.inject(
target: T,
iterator: Iterator<Pair<String?, Property<T>?>>
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
@JvmName("injectMap")
fun <T : Any> Any.inject(
target: T,
iterator: Iterator<Map.Entry<String?, Property<T>?>>
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
fun <T : Any> Map<in String, Any?>.inject(
target: T,
iterator: Iterator<Pair<String, Property<T>?>>
): T {
iterator.forEach { (k, t) ->
val value = this[k] ?: return@forEach
value.inject(target, t ?: return@forEach)
}
return target
}
fun <T : Any> Map<in String, Any?>.p2pInject(
target: T,
iterator: Iterator<Pair<Property<T>, Property<T>?>>
): T {
iterator.forEach { (k, t) ->
val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach
value.inject(target, t ?: return@forEach)
}
return target
}
@JvmName("injectMap")
fun <T : Any> Map<in String, Any?>.inject(
target: T,
iterator: Iterator<Map.Entry<String, Property<T>?>>
): T {
iterator.forEach { (k, t) ->
val value = this[k] ?: return@forEach
value.inject(target, t ?: return@forEach)
}
return target
}
fun <T : Any> Any.inject(target: T, property: Property<T>) {
//logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
when (property) {
is KMutableProperty1<*, *> -> {
@Suppress("UNCHECKED_CAST")
property as KMutableProperty1<T, Any?>
property.isAccessible = true
try {
property.set(target, cast(this, property.returnType.javaType.cast()) ?: return)
} catch (e: ClassCastException) {
//logger.trace("inject failed", e)
}
}
else -> {
val field = property.javaField ?: return
field.isAccessible = true
field.final = false
try {
field.set(target, cast(this, field.type) ?: return)
} catch (e: Exception) {
//logger.trace("inject failed", e)
}
}
}
}
fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) {
source
} else when (target) {
Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar()
Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()
?.toChar()
java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
String::class.java -> source.toString()
else -> source
}
fun <T : Any> T.read(source: Any?): T = source?.clone(this) ?: this
fun <T : Any, S : Any> T.read(
source: S?,
vararg relation: Pair<Property<S>, Property<T>?>
): T = source?.clone(this, relation.iterator()) ?: this
fun <T : Any> T.read(
source: Map<in String, Any?>?,
vararg relation: Pair<String, Property<T>?>
): T = source?.clone(this, relation.iterator()) ?: this
fun <T : Any> T.p2pRead(
source: Map<in String, Any?>?,
vararg relation: Pair<Property<T>, Property<T>?>
): T {
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
return source?.p2pInject(this, relation.iterator()) ?: this
}
fun <T : Any> T.p2pRead(
source: Map<in String, Any?>?
): T {
source ?: return this
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
val relation = properties.mapNotNull { property ->
val key = property.javaField?.getAnnotation(Key::class.java)?.key ?: return@mapNotNull null
val keyProperty = properties.find { it.name == key } ?: return@mapNotNull null
keyProperty to property
}
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
return source.p2pInject(this, relation.iterator())
}
fun <T : Any> T.p2pRead(
source: Any?
): T {
source ?: return this
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
properties.forEach { property ->
val keyAnnotation = property.javaField?.getAnnotation(Key::class.java) ?: return@forEach
if (keyAnnotation.handler.isEmpty()) return@forEach
if (keyAnnotation.clazz.isInstance(source).not()) return@forEach
val handler = this::class.java.getDeclaredMethod(keyAnnotation.handler, keyAnnotation.clazz.java)
(handler(this, source) ?: return@forEach).inject(this, property)
}
return this
}
fun <T : Any, S : Any> List<T>.read(
source: List<S>,
vararg relation: Pair<Property<S>, Property<T>?>
): List<T> {
val memberMap = this[0].injectMap as MutableMap<String, Property<T>?>
relation.forEach { (k, v) ->
memberMap[k.name] = v
}
return source.mapIndexed { index, it -> it.inject(this[index], memberMap.iterator()) }
}
inline fun <reified T : Any> read(vararg values: Any, unsafe: Boolean = true): T {
val instance = instance<T>(unsafe)!!
values.forEach {
it.clone(instance)
}
return instance
}
inline fun <reified T : Any> read(value: Any, unsafe: Boolean = true): T = value.clone(unsafe)
fun <T : Any> T.readWithoutProperty(vararg values: Any): T {
values.forEach {
it.injectWithoutProperty(this)
}
return this
}
inline fun <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T? = try {
clazz.newInstance()!!
} catch (e: Exception) {
if (unsafe) {
@Suppress("UNCHECKED_CAST")
Unsafe.unsafe.allocateInstance(clazz) as T?
} else {
null
}
}
inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) -> Pair<K, V>?): Map<K, V> {
val map = ArrayMap<K, V>()
@ -502,6 +195,113 @@ inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) ->
return map
}
fun <T : Any> T.mapRead(map: Map<in String, Any?>, key: KProperty1<T, *>): T {
return read(map[key.get(this)?.toString() ?: return this] ?: return this)
fun <T : Any, F : Any?> T.set(field: KProperty1<T, F>, value: F): T {
(value as Any?)?.inject(this, field as Property<T>)
return this
}
fun <T : Any> T.deepClone(): T = when (this) {
is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this
is CharArray -> copyOf().uncheckedCast()
is BooleanArray -> copyOf().uncheckedCast()
is ByteArray -> copyOf().uncheckedCast()
is ShortArray -> copyOf().uncheckedCast()
is IntArray -> copyOf().uncheckedCast()
is LongArray -> copyOf().uncheckedCast()
is FloatArray -> copyOf().uncheckedCast()
is DoubleArray -> copyOf().uncheckedCast()
else -> deepClone(HashMap())
}
private fun <T : Any> T.deepClone(clonedMap: MutableMap<Any, Any>): T =
clonedMap[this]?.uncheckedCast<T>() ?: when (this) {
is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this
is CharArray -> copyOf().uncheckedCast()
is BooleanArray -> copyOf().uncheckedCast()
is ByteArray -> copyOf().uncheckedCast()
is ShortArray -> copyOf().uncheckedCast()
is IntArray -> copyOf().uncheckedCast()
is LongArray -> copyOf().uncheckedCast()
is FloatArray -> copyOf().uncheckedCast()
is DoubleArray -> copyOf().uncheckedCast()
is Array<*> -> {
val instance = java.lang.reflect.Array.newInstance(javaClass.componentType, size).uncheckedCast<Array<Any?>>()
forEachIndexed { index, it ->
instance[index] = it?.deepClone(clonedMap)
}
instance.uncheckedCast()
}
else -> {
val clazz = javaClass
val newInstance = unsafeInstance(clazz)!!
clonedMap[this] = newInstance
clazz.forAllFields { field ->
if (field.isStatic()) return@forAllFields
field.isAccessible = true
field.set(newInstance, field.get(this)?.deepClone(clonedMap))
}
newInstance
}
}
fun Any?.details(name: String = "", skipStatic: Boolean = true) = buildString {
this@details.details(HashMap(), this, "", name, skipStatic)
}
private fun Any?.details(
map: MutableMap<Any, Int>,
builder: StringBuilder,
indentation: String,
name: String = "",
skipStatic: Boolean = true,
directValue: String = "|- ",
objectValue: String = "/- ",
hint: String = "${TextColor.red}|${TextColor.reset} ",
tmpIndentation: String = "",
type: String? = null,
) {
when (this) {
null, is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*>, is String ->
builder.append("$indentation$tmpIndentation$directValue$name(${type ?: this?.javaClass?.name ?: "null"}): $this\n")
is CharArray -> builder.append("$indentation$tmpIndentation$directValue$name(CharArray): ${String(this)}\n")
is BooleanArray -> builder.append("$indentation$tmpIndentation$directValue$name(BooleanArray): ${asList()}\n")
is ByteArray -> builder.append("$indentation$tmpIndentation$directValue$name(ByteArray): 0x${toHexString()}\n")
is ShortArray -> builder.append("$indentation$tmpIndentation$directValue$name(ShortArray): ${asList()}\n")
is IntArray -> builder.append("$indentation$tmpIndentation$directValue$name(IntArray): ${asList()}\n")
is LongArray -> builder.append("$indentation$tmpIndentation$directValue$name(LongArray): ${asList()}\n")
is FloatArray -> builder.append("$indentation$tmpIndentation$directValue$name(FloatArray): ${asList()}\n")
is DoubleArray -> builder.append("$indentation$tmpIndentation$directValue$name(DoubleArray): ${asList()}\n")
is Array<*> -> {
builder.append("$indentation$tmpIndentation$objectValue$name: (Array<${javaClass.componentType.name}>, ${hashCode()})\n")
if (this !in map) {
map[this] = hashCode()
val newIndentation = "$indentation$hint"
forEachIndexed { index, it ->
val newTmpIndentation = "|- ${name.ifEmpty { "array" }}[$index]"
it.details(
map, builder, newIndentation,
skipStatic = skipStatic,
directValue = " = ",
objectValue = " = /- ",
hint = "${TextColor.red}|${TextColor.reset} ${" ".repeat(newTmpIndentation.length + 1)}${TextColor.red}|${TextColor.reset} ",
tmpIndentation = newTmpIndentation
)
}
}
}
in map -> builder.append("$indentation$tmpIndentation$directValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${map[this]}, generated)\n")
else -> {
map[this] = this.hashCode()
builder.append("$indentation$tmpIndentation$objectValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${hashCode()})\n")
val newIndentation = "$indentation$hint"
javaClass.forAllFields { field ->
if (skipStatic && field.isStatic()) {
return@forAllFields
}
field.isAccessible = true
val value = field.get(this)
value.details(map, builder, newIndentation, field.name, skipStatic, type = field.type.name)
}
}
}
}

View File

@ -0,0 +1,270 @@
package cn.tursom.core.clone
import cn.tursom.core.Unsafe
import cn.tursom.core.allMemberProperties
import cn.tursom.core.datastruct.KPropertyValueMap
import cn.tursom.core.datastruct.SoftArrayMap
import cn.tursom.core.unaryPlus
import cn.tursom.core.uncheckedCast
import cn.tursom.log.impl.Slf4jImpl
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
import kotlin.reflect.*
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaType
private val logger = Slf4jImpl().logger
val Any.valueMap: Map<String, Any?>
get() = if (this is Map<*, *>) {
uncheckedCast()
} else {
KPropertyValueMap(this)
}
private val injectMapCache = SoftArrayMap<KClass<*>, Map<String, Property<*>?>>(ConcurrentHashMap())
val <T : Any> KClass<T>.injectMap: MutableMap<String, Property<T>?>
@Suppress("UNCHECKED_CAST")
get() {
var injectMap = injectMapCache[this] as Map<String, Property<T>?>?
if (injectMap == null) {
injectMap = allMemberProperties.associateByTo(HashMap()) { property ->
property.isAccessible = true
property.name
}
injectMapCache[this] = injectMap as Map<String, Property<*>?>
}
return HashMap(injectMap)
}
internal val <T : Any> T.injectMap: MutableMap<String, Property<T>?>
get() = this::class.uncheckedCast<KClass<T>>().injectMap
internal val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
get() = let {
val valueMap = HashMap<String, Property<T>?>()
@Suppress("UNCHECKED_CAST")
forEach { (k, field) ->
field?.isAccessible = true
valueMap[k.name] = field
}
logger.trace("Iterator.injectMap: {}", valueMap)
valueMap
}
internal fun <T : Any> T.injectMap(targetClazz: KClass<*>?): MutableMap<String, Property<T>?> = this::class
.uncheckedCast<KClass<T>>()
.injectMap
.also { injectMap ->
if (targetClazz == null) return@also
val clazzThis = this::class.java
fun import(relation: Relation, property: Property<T>) {
if (relation.clazz != targetClazz) return
var propertyName = relation.property
if (propertyName.isBlank()) {
propertyName = property.name
}
logger.trace("relation {} to {}", propertyName, property.name)
injectMap[propertyName] = when {
relation.skip -> null
relation.handler.isEmpty() -> property
else -> try {
val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java)
handler.isAccessible = true
object : KMutableProperty1<T, Any?>, KProperty1<T, Any?> by property {
override val setter: KMutableProperty1.Setter<T, Any?>
get() = object : KMutableProperty1.Setter<T, Any?>, KCallable<Unit> by property.uncheckedCast() {
override val isExternal: Boolean get() = false
override val isInfix: Boolean get() = false
override val isInline: Boolean get() = false
override val isOperator: Boolean get() = false
override val isSuspend: Boolean get() = false
override val property: KProperty<Any?> get() = property
override fun invoke(receiver: T, value: Any?) =
handler(this@injectMap, value).inject(receiver, property)
}
override fun set(receiver: T, value: Any?) = try {
handler(this@injectMap, value).inject(receiver, property)
} catch (e: Exception) {
logger.trace("", e)
}
}
} catch (e: Exception) {
logger.warn("an exception caused on generate inject handler", e)
null
}
}
}
fun parseAnnotation(annotation: Annotation, property: Property<T>) {
when (annotation) {
is Relation -> import(annotation, property)
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
}
}
this::class.memberProperties.uncheckedCast<Collection<KProperty1<T, *>>>().forEach { property ->
property.annotations.forEach { annotation -> parseAnnotation(annotation, property) }
(property.javaField ?: return@forEach).annotations.forEach { annotation ->
parseAnnotation(annotation, property)
}
}
}
fun <T : Any> Any.injectWithoutProperty(target: T): T {
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try {
val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java)
handler.isAccessible = true
handler(target, this)?.inject(target, property)
} catch (e: Exception) {
logger.trace("an exception caused on global inject", e)
}
}
target::class.memberProperties
.uncheckedCast<Collection<KProperty1<Any, *>>>()
.forEach { property ->
property.annotations.forEach { annotation ->
when (annotation) {
is Relation -> parseAnnotation(annotation, property)
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
}
}
property.javaField?.annotations?.forEach { annotation ->
when (annotation) {
is Relation -> parseAnnotation(annotation, property)
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
}
}
}
return target
}
fun <T : Any> Any.inject(
target: T,
iterator: Iterator<Pair<String?, Property<T>?>>,
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
@JvmName("injectMap")
fun <T : Any> Any.inject(
target: T,
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
fun <T : Any> Map<in String, Any?>.inject(
target: T,
iterator: Iterator<Pair<String, Property<T>?>>,
): T {
iterator.forEach { (k, t) ->
val value = this[k] ?: return@forEach
value.inject(target, t ?: return@forEach)
}
return target
}
/**
* point to point inject
* 通过指定映射关系从本map中取出数据并注入到目标对象中
*
*/
fun <T : Any> Map<in String, Any?>.p2pInject(
target: T,
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
): T {
iterator.forEach { (k, t) ->
val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach
value.inject(target, t ?: return@forEach)
}
return target
}
@JvmName("injectMap")
fun <T : Any> Map<in String, Any?>.inject(
target: T,
iterator: Iterator<Map.Entry<String, Property<T>?>>,
): T {
iterator.forEach { (k, t) ->
val value = this[k] ?: return@forEach
value.inject(target, t ?: return@forEach)
}
return target
}
fun <T : Any> Any.inject(target: T, property: Property<T>) {
logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
when (property) {
is KMutableProperty1<*, *> -> {
@Suppress("UNCHECKED_CAST")
property as KMutableProperty1<T, Any?>
property.isAccessible = true
try {
property.set(target, cast(this, property.returnType.javaType.uncheckedCast()) ?: return)
} catch (e: ClassCastException) {
if (logger.isTraceEnabled) {
logger.trace("inject {} failed", property.name, e)
}
} catch (e: Exception) {
logger.error("inject {} failed", property.name, e)
}
}
else -> {
val field = property.javaField ?: return
field.isAccessible = true
try {
field.set(target, cast(this, field.type) ?: return)
} catch (e: ClassCastException) {
if (logger.isTraceEnabled) {
logger.trace("inject {} failed", property.name, e)
}
} catch (e: Exception) {
logger.error("inject {} failed", property.name, e)
}
}
}
}
fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) {
source
} else when (target) {
Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar()
Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()
?.toChar()
java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
String::class.java -> source.toString()
else -> source
}
inline fun <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T = InstantAllocator[clazz, unsafe]
fun <T> unsafeInstance(clazz: Class<T>, unsafe: Boolean = true): T? = if (unsafe) {
@Suppress("UNCHECKED_CAST")
Unsafe.unsafe.allocateInstance(clazz) as T?
} else {
null
}

View File

@ -1,6 +1,6 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
import cn.tursom.core.uncheckedCast
@Suppress("MemberVisibilityCanBePrivate")
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
@ -149,7 +149,7 @@ open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
override fun setValue(newValue: V): V = value.also { value = newValue }
override fun compareTo(other: K): Int {
return if (key is Comparable<*>) {
key.cast<Comparable<K>>().compareTo(other)
key.uncheckedCast<Comparable<K>>().compareTo(other)
} else {
-1
}

View File

@ -1,11 +1,11 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
import cn.tursom.core.uncheckedCast
class DefaultValueMap<K, V>(
private val map: Map<K, V?>,
private val defaultValue: (K) -> V
) : Map<K, V> by map.cast() {
private val defaultValue: (K) -> V,
) : Map<K, V> by map.uncheckedCast() {
override val entries: Set<Map.Entry<K, V>> get() = Entry()
override val values: Collection<V> get() = Values()
@ -21,8 +21,8 @@ class DefaultValueMap<K, V>(
}
inner class Entry(
private val entries: Set<Map.Entry<K, V?>> = map.entries
) : Set<Map.Entry<K, V>> by entries.cast() {
private val entries: Set<Map.Entry<K, V?>> = map.entries,
) : Set<Map.Entry<K, V>> by entries.uncheckedCast() {
override val size: Int get() = entries.count { it.value != null }
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
override fun iterator(): Iterator<Map.Entry<K, V>> = EntryIterator()
@ -32,7 +32,7 @@ class DefaultValueMap<K, V>(
private var next: Map.Entry<K, V>? = null
override fun hasNext(): Boolean {
while (iterator.hasNext()) {
next = iterator.next().cast()
next = iterator.next().uncheckedCast()
if (next?.value != null) {
return true
}
@ -44,13 +44,13 @@ class DefaultValueMap<K, V>(
next != null -> next
hasNext() -> next
else -> throw NoSuchElementException()
}.cast()
}.uncheckedCast()
}
}
inner class Values(
private val values: Collection<V?> = map.values
) : Collection<V> by values.cast() {
private val values: Collection<V?> = map.values,
) : Collection<V> by values.uncheckedCast() {
override val size: Int get() = values.count { it != null }
override fun isEmpty(): Boolean = values.first { it != null } == null
override fun iterator(): Iterator<V> = ValuesIterator()
@ -61,7 +61,7 @@ class DefaultValueMap<K, V>(
override fun hasNext(): Boolean {
while (iterator.hasNext()) {
next = iterator.next().cast()
next = iterator.next().uncheckedCast()
if (next != null) {
return true
}
@ -73,7 +73,7 @@ class DefaultValueMap<K, V>(
next != null -> next
hasNext() -> next
else -> throw NoSuchElementException()
}.cast()
}.uncheckedCast()
}
}
}

View File

@ -1,11 +1,11 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
import cn.tursom.core.uncheckedCast
class DefaultValueMutableMap<K, V>(
private val map: MutableMap<K, V?>,
private val defaultValue: (K) -> V
) : MutableMap<K, V> by map.cast() {
private val defaultValue: (K) -> V,
) : MutableMap<K, V> by map.uncheckedCast() {
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = Entry()
override val values: MutableCollection<V> get() = Values()
@ -19,19 +19,19 @@ class DefaultValueMutableMap<K, V>(
}
inner class Entry(
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.cast() {
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries,
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.uncheckedCast() {
override val size: Int get() = entries.count { it.value != null }
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = EntryIterator()
inner class EntryIterator(
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator()
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.cast() {
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator(),
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.uncheckedCast() {
private var next: Map.Entry<K, V>? = null
override fun hasNext(): Boolean {
while (iterator.hasNext()) {
next = iterator.next().cast()
next = iterator.next().uncheckedCast()
if (next?.value != null) {
return true
}
@ -43,25 +43,25 @@ class DefaultValueMutableMap<K, V>(
next != null -> next
hasNext() -> next
else -> throw NoSuchElementException()
}.cast()
}.uncheckedCast()
}
}
inner class Values(
private val values: MutableCollection<V?> = map.values
) : MutableCollection<V> by values.cast() {
private val values: MutableCollection<V?> = map.values,
) : MutableCollection<V> by values.uncheckedCast() {
override val size: Int get() = values.count { it != null }
override fun isEmpty(): Boolean = values.first { it != null } == null
override fun iterator(): MutableIterator<V> = ValuesIterator()
inner class ValuesIterator(
private val iterator: MutableIterator<V?> = values.iterator()
) : MutableIterator<V> by iterator.cast() {
private val iterator: MutableIterator<V?> = values.iterator(),
) : MutableIterator<V> by iterator.uncheckedCast() {
private var next: V? = null
override fun hasNext(): Boolean {
while (iterator.hasNext()) {
next = iterator.next().cast()
next = iterator.next().uncheckedCast()
if (next != null) {
return true
}
@ -73,7 +73,7 @@ class DefaultValueMutableMap<K, V>(
next != null -> next
hasNext() -> next
else -> throw NoSuchElementException()
}.cast()
}.uncheckedCast()
}
}
}

View File

@ -1,6 +1,6 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
import cn.tursom.core.uncheckedCast
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
@ -23,7 +23,7 @@ class KPropertyValueMap(val target: Any) : Map<String, Any?> {
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
var map = propertiesMapCache[clazz]
if (map == null) {
map = clazz.memberProperties.cast<Collection<KProperty1<Any, *>>>().let { properties ->
map = clazz.memberProperties.uncheckedCast<Collection<KProperty1<Any, *>>>().let { properties ->
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
properties.forEach {
it.isAccessible = true

View File

@ -1,6 +1,6 @@
package cn.tursom.core.datastruct
import cn.tursom.core.cast
import cn.tursom.core.uncheckedCast
@Suppress("MemberVisibilityCanBePrivate")
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
@ -17,8 +17,8 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
@Suppress("LeakingThis")
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().cast()
override val values: MutableCollection<V> get() = arrValue.asList().cast<MutableList<V>>().subList(0, end)
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().uncheckedCast()
override val values: MutableCollection<V> get() = arrValue.asList().uncheckedCast<MutableList<V>>().subList(0, end)
/**
* @param key 查找的键
@ -59,7 +59,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
fun setByIndex(index: Int, value: V): V? {
val oldValue = arrValue[end]
arrValue[index] = value
return oldValue.cast()
return oldValue.uncheckedCast()
}
override fun delete(key: K): V? {
@ -72,7 +72,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1)
end--
return oldValue.cast()
return oldValue.uncheckedCast()
}
override fun clear() {
@ -83,7 +83,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
return if (end <= 0) {
null
} else {
arrValue[0].cast()
arrValue[0].uncheckedCast()
}
}
@ -109,7 +109,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
return if (index < 0 || index >= end) {
null
} else {
arr[index].cast()
arr[index].uncheckedCast()
}
}
@ -117,7 +117,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
return if (index < 0 || index >= end) {
null
} else {
arrValue[index].cast()
arrValue[index].uncheckedCast()
}
}
@ -194,10 +194,10 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
val map: ParallelArrayMap<K, V>,
val index: Int
) : MutableMap.MutableEntry<K, V> {
override val key: K get() = map.getKeyByIndex(index).cast()
override val value: V get() = map.getByIndex(index).cast()
override val key: K get() = map.getKeyByIndex(index).uncheckedCast()
override val value: V get() = map.getByIndex(index).uncheckedCast()
override fun setValue(newValue: V): V {
return map.setByIndex(index, newValue).cast()
return map.setByIndex(index, newValue).uncheckedCast()
}
}
}

View File

@ -2,8 +2,10 @@
package cn.tursom.core.delegation
import cn.tursom.core.*
import java.util.concurrent.ConcurrentLinkedQueue
import cn.tursom.core.SimpThreadLocal
import cn.tursom.core.castOrNull
import cn.tursom.core.receiver
import cn.tursom.core.uncheckedCast
import java.util.concurrent.Executor
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReadWriteLock
@ -126,99 +128,3 @@ fun <T, V> MutableDelegatedField<T, V>.getter(getter: MutableDelegatedField<T, V
fun <T, V> MutableDelegatedField<T, V>.withExecutor(executor: Executor): MutableDelegatedField<T, V> =
ExecutorMutableDelegatedField(this, executor)
@Listenable
fun <V> KMutableProperty0<V>.listenable(): MutableDelegatedField<Any, V> {
isAccessible = true
val delegate = getDelegate()
return if (delegate is MutableDelegatedField<*, *> && delegate[ListenableMutableDelegatedField] == true) {
@OptIn(UncheckedCast::class)
delegate.cast()
} else {
@OptIn(UncheckedCast::class)
(ListenableMutableDelegatedField(KPropertyMutableDelegatedField(cast())))
}
}
@Listenable
fun <V> listenable(initValue: V): MutableDelegatedField<Any, V> = ListenableMutableDelegatedField(
MutableDelegatedFieldValue(initValue)
)
@Listenable
fun <T, V> MutableDelegatedField<T, V>.listenable(): MutableDelegatedField<T, V> =
ListenableMutableDelegatedField(this)
@JvmName("listenable1")
@Listenable
fun <T, V> listenable(delegatedField: MutableDelegatedField<T, V>): MutableDelegatedField<T, V> =
ListenableMutableDelegatedField(delegatedField)
infix operator fun <T, V> ListenableListener<T, V>.plus(listener: T.(old: V, new: V) -> Unit): Listener<T, V> =
addListener(listener)
@OptIn(Listenable::class)
fun <V> KProperty0<V>.getListenableMutableDelegatedField(): ListenableMutableDelegatedField<Any, V>? {
isAccessible = true
var delegate = getDelegate() ?: getDelegate(receiver, name)
if (delegate is DelegatedField<*, *>) {
while (true) {
if (delegate is ListenableMutableDelegatedField<*, *>) {
@OptIn(UncheckedCast::class)
return delegate.cast()
}
if (delegate is DecoratorDelegatedField<*, *>) {
delegate = delegate.delegatedField
} else {
break
}
}
} else if (delegate is KProperty0<*> && delegate != this) {
@OptIn(UncheckedCast::class)
return delegate.cast<KProperty0<V>>().getListenableMutableDelegatedField()
}
return null
}
inline fun <T, V> T.addChangeListener(
property: T.() -> KProperty0<V>,
): ListenableListener<T, V> {
val kProperty0 = property()
@OptIn(Listenable::class, UncheckedCast::class)
val delegatedField = kProperty0
.getListenableMutableDelegatedField()
.cast<ListenableMutableDelegatedField<T, V>?>()
?: throw UnmonitoredFieldException(kProperty0.toString())
return object : ListenableListener<T, V> {
private val selfList = ConcurrentLinkedQueue<Listener<T, V>>()
override fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V> {
@OptIn(Listenable::class)
val listener1 = delegatedField.addListener(listener)
selfList.add(listener1)
return listener1
}
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V> {
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): Listener<T, V> {
selfList.forEach {
it.finally(handler)
}
return this
}
}
}

View File

@ -0,0 +1,32 @@
plugins {
kotlin("jvm")
`maven-publish`
}
dependencies {
implementation(project(":ts-core"))
implementation(project(":ts-core:ts-delegation"))
}
@kotlin.Suppress("UNCHECKED_CAST")
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
tasks.register("install") {
finalizedBy(tasks["publishToMavenLocal"])
}
publishing {
publications {
create<MavenPublication>("maven") {
groupId = project.group.toString()
artifactId = project.name
version = project.version.toString()
from(components["java"])
try {
artifact(tasks["sourcesJar"])
} catch (e: Exception) {
}
}
}
}

View File

@ -1,4 +1,4 @@
package cn.tursom.core.delegation
package cn.tursom.core.delegation.observer
/**
* 标识一个属性可以被指定的 FieldChangeListener 监听

View File

@ -1,4 +1,4 @@
package cn.tursom.core.delegation
package cn.tursom.core.delegation.observer
interface ListenableListener<out T, V> : Listener<T, V> {
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V>

View File

@ -1,5 +1,8 @@
package cn.tursom.core.delegation
package cn.tursom.core.delegation.observer
import cn.tursom.core.delegation.DecoratorMutableDelegatedField
import cn.tursom.core.delegation.DelegatedFieldAttachmentKey
import cn.tursom.core.delegation.MutableDelegatedField
import cn.tursom.core.uncheckedCast
import java.util.concurrent.ConcurrentLinkedDeque
import kotlin.reflect.KProperty

View File

@ -1,4 +1,4 @@
package cn.tursom.core.delegation
package cn.tursom.core.delegation.observer
interface Listener<out T, V> {
fun cancel(): Boolean

View File

@ -1,4 +1,4 @@
package cn.tursom.core.delegation
package cn.tursom.core.delegation.observer
class UnmonitoredFieldException : Exception {
constructor() : super()

View File

@ -0,0 +1,109 @@
@file:Suppress("unused")
package cn.tursom.core.delegation.observer
import cn.tursom.core.UncheckedCast
import cn.tursom.core.cast
import cn.tursom.core.delegation.*
import cn.tursom.core.receiver
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
@Listenable
fun <V> KMutableProperty0<V>.listenable(): MutableDelegatedField<Any, V> {
isAccessible = true
val delegate = getDelegate()
return if (delegate is MutableDelegatedField<*, *> && delegate[ListenableMutableDelegatedField] == true) {
@OptIn(UncheckedCast::class)
delegate.cast()
} else {
@OptIn(UncheckedCast::class)
(ListenableMutableDelegatedField(KPropertyMutableDelegatedField(cast())))
}
}
@Listenable
fun <V> listenable(initValue: V): MutableDelegatedField<Any, V> = ListenableMutableDelegatedField(
MutableDelegatedFieldValue(initValue)
)
@Listenable
fun <T, V> MutableDelegatedField<T, V>.listenable(): MutableDelegatedField<T, V> =
ListenableMutableDelegatedField(this)
@JvmName("listenable1")
@Listenable
fun <T, V> listenable(delegatedField: MutableDelegatedField<T, V>): MutableDelegatedField<T, V> =
ListenableMutableDelegatedField(delegatedField)
infix operator fun <T, V> ListenableListener<T, V>.plus(listener: T.(old: V, new: V) -> Unit): Listener<T, V> =
addListener(listener)
@OptIn(Listenable::class)
fun <V> KProperty0<V>.getListenableMutableDelegatedField(): ListenableMutableDelegatedField<Any, V>? {
isAccessible = true
var delegate = getDelegate() ?: getDelegate(receiver, name)
if (delegate is DelegatedField<*, *>) {
while (true) {
if (delegate is ListenableMutableDelegatedField<*, *>) {
@OptIn(UncheckedCast::class)
return delegate.cast()
}
if (delegate is DecoratorDelegatedField<*, *>) {
delegate = delegate.delegatedField
} else {
break
}
}
} else if (delegate is KProperty0<*> && delegate != this) {
@OptIn(UncheckedCast::class)
return delegate.cast<KProperty0<V>>().getListenableMutableDelegatedField()
}
return null
}
inline fun <T, V> T.addChangeListener(
property: T.() -> KProperty0<V>,
): ListenableListener<T, V> {
val kProperty0 = property()
@OptIn(Listenable::class, UncheckedCast::class)
val delegatedField = kProperty0
.getListenableMutableDelegatedField()
.cast<ListenableMutableDelegatedField<T, V>?>()
?: throw UnmonitoredFieldException(kProperty0.toString())
return object : ListenableListener<T, V> {
private val selfList = ConcurrentLinkedQueue<Listener<T, V>>()
override fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V> {
@OptIn(Listenable::class)
val listener1 = delegatedField.addListener(listener)
selfList.add(listener1)
return listener1
}
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V> {
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): Listener<T, V> {
selfList.forEach {
it.finally(handler)
}
return this
}
}
}

View File

@ -1,7 +1,7 @@
package cn.tursom.core.encrypt
import cn.tursom.core.Unsafe
import cn.tursom.core.cast
import cn.tursom.core.uncheckedCast
import java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
@ -72,7 +72,7 @@ class ECC(
val standardCurveLineSet by lazy {
try {
Unsafe {
Class.forName("sun.security.ec.CurveDB")["nameMap"].cast<Map<String, Any>>().keys
Class.forName("sun.security.ec.CurveDB")["nameMap"].uncheckedCast<Map<String, Any>>().keys
}
} catch (e: Exception) {
emptySet()

View File

@ -5,9 +5,9 @@ plugins {
dependencies {
implementation(project(":"))
implementation(group = "org.slf4j", name = "slf4j-api", version = "1.7.29")
implementation(group = "ch.qos.logback", name = "logback-core", version = "1.2.3")
implementation(group = "ch.qos.logback", name = "logback-classic", version = "1.2.3")
api(group = "org.slf4j", name = "slf4j-api", version = "1.7.29")
api(group = "ch.qos.logback", name = "logback-core", version = "1.2.3")
api(group = "ch.qos.logback", name = "logback-classic", version = "1.2.3")
}
@kotlin.Suppress("UNCHECKED_CAST")