From 7a3fcf91cc78d6d8214d6e21e3c8f67775ddac79 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Mon, 24 Feb 2020 22:45:00 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=E5=A4=89=E6=95=B0=E5=90=8D=E3=82=92?= =?UTF-8?q?=E4=BD=BF=E3=81=84=E6=96=B9=E3=81=AB=E5=90=88=E3=82=8F=E3=81=9B?= =?UTF-8?q?=E3=81=A6=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ついでにオリジナルはlist化して厳密に取り扱うよう修正 --- .../com/wrongwrong/mapk/core/KFunctionForCall.kt | 10 +++++----- src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt b/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt index 97fdab6..7e875ed 100644 --- a/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt +++ b/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt @@ -6,16 +6,16 @@ import kotlin.reflect.jvm.isAccessible class KFunctionForCall(private val function: KFunction, instance: Any? = null) { val parameters: List = function.parameters - private val originalArray: Array - val argumentArray: Array get() = originalArray.copyOf() + private val originalArgumentBucket: List + val argumentBucket: Array get() = originalArgumentBucket.toTypedArray() init { // この関数には確実にアクセスするためアクセシビリティ書き換え function.isAccessible = true - originalArray = if (instance != null) { - Array(parameters.size) { if (it == 0) instance else null } + originalArgumentBucket = if (instance != null) { + List(parameters.size) { if (it == 0) instance else null } } else { - Array(parameters.size) { null } + List(parameters.size) { null } } } diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt index 9a1934c..b87a68d 100644 --- a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt +++ b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt @@ -69,25 +69,25 @@ class KMapper private constructor( } fun map(srcMap: Map): T { - val array: Array = function.argumentArray + val array: Array = function.argumentBucket bindParameters(array, srcMap) return function.call(array) } fun map(srcPair: Pair): T { - val array: Array = function.argumentArray + val array: Array = function.argumentBucket bindParameters(array, srcPair) return function.call(array) } fun map(src: Any): T { - val array: Array = function.argumentArray + val array: Array = function.argumentBucket bindParameters(array, src) return function.call(array) } fun map(vararg args: Any): T { - val array: Array = function.argumentArray + val array: Array = function.argumentBucket listOf(*args).forEach { arg -> when (arg) { From 5ab12b9a294a0bf3082e25bd2ee27d06a1ecb281 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Mon, 24 Feb 2020 22:46:46 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E5=A4=89=E6=95=B0=E5=90=8D=E3=82=92?= =?UTF-8?q?=E4=BD=BF=E3=81=84=E6=96=B9=E3=81=AB=E5=90=88=E3=82=8F=E3=81=9B?= =?UTF-8?q?=E3=81=A6=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wrongwrong/mapk/core/KMapper.kt | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt index b87a68d..bbf401a 100644 --- a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt +++ b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt @@ -40,50 +40,50 @@ class KMapper private constructor( if (parameterMap.isEmpty()) throw IllegalArgumentException("This function is not require arguments.") } - private fun bindParameters(targetArray: Array, src: Any) { + private fun bindParameters(targetBucket: Array, src: Any) { src::class.memberProperties.forEach { property -> val javaGetter: Method? = property.javaGetter if (javaGetter != null && property.visibility == KVisibility.PUBLIC && property.annotations.none { annotation -> annotation is KPropertyIgnore }) { parameterMap[property.findAnnotation()?.value ?: property.name]?.let { // javaGetterを呼び出す方が高速 javaGetter.isAccessible = true - targetArray[it.index] = javaGetter.invoke(src)?.let { value -> mapObject(it, value) } + targetBucket[it.index] = javaGetter.invoke(src)?.let { value -> mapObject(it, value) } } } } } - private fun bindParameters(targetArray: Array, src: Map<*, *>) { + private fun bindParameters(targetBucket: Array, src: Map<*, *>) { src.forEach { (key, value) -> parameterMap[key]?.let { param -> // 取得した内容がnullでなければ適切にmapする - targetArray[param.index] = value?.let { mapObject(param, it) } + targetBucket[param.index] = value?.let { mapObject(param, it) } } } } - private fun bindParameters(targetArray: Array, srcPair: Pair<*, *>) { + private fun bindParameters(targetBucket: Array, srcPair: Pair<*, *>) { parameterMap.getValue(srcPair.first.toString()).let { - targetArray[it.index] = srcPair.second?.let { value -> mapObject(it, value) } + targetBucket[it.index] = srcPair.second?.let { value -> mapObject(it, value) } } } fun map(srcMap: Map): T { - val array: Array = function.argumentBucket - bindParameters(array, srcMap) - return function.call(array) + val bucket: Array = function.argumentBucket + bindParameters(bucket, srcMap) + return function.call(bucket) } fun map(srcPair: Pair): T { - val array: Array = function.argumentBucket - bindParameters(array, srcPair) - return function.call(array) + val bucket: Array = function.argumentBucket + bindParameters(bucket, srcPair) + return function.call(bucket) } fun map(src: Any): T { - val array: Array = function.argumentBucket - bindParameters(array, src) - return function.call(array) + val bucket: Array = function.argumentBucket + bindParameters(bucket, src) + return function.call(bucket) } fun map(vararg args: Any): T { From 4e78bbeffa24c7e16893e244d0dc25ac7abe2836 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Tue, 25 Feb 2020 00:09:40 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=E5=88=9D=E6=9C=9F=E5=8C=96=E7=8A=B6?= =?UTF-8?q?=E6=B3=81=E3=82=92=E7=AE=A1=E7=90=86=E3=81=99=E3=82=8B=E3=81=9F?= =?UTF-8?q?=E3=82=81=E3=81=AE=E3=83=90=E3=82=B1=E3=83=84=E3=82=AF=E3=83=A9?= =?UTF-8?q?=E3=82=B9=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wrongwrong/mapk/core/ArgumentBucket.kt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/kotlin/com/wrongwrong/mapk/core/ArgumentBucket.kt diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/ArgumentBucket.kt b/src/main/kotlin/com/wrongwrong/mapk/core/ArgumentBucket.kt new file mode 100644 index 0000000..0a3b291 --- /dev/null +++ b/src/main/kotlin/com/wrongwrong/mapk/core/ArgumentBucket.kt @@ -0,0 +1,26 @@ +package com.wrongwrong.mapk.core + +class ArgumentBucket( + val bucket: Array, + private var initializeStatus: Int, + private val initializeMask: List, + // clone時の再計算を避けるため1回で済むようにデフォルト値化 + private val completionValue: Int = initializeMask.reduce { l, r -> l or r } +) : Cloneable { + val isInitialized: Boolean get() = initializeStatus == completionValue + val notInitializedParameterIndexes: List get() = initializeMask.indices.filter { + initializeStatus and initializeMask[it] == 0 + } + + fun setArgument(argument: Any?, index: Int) { + // 先に入ったものを優先するため、初期化済みなら何もしない + if (initializeStatus and initializeMask[index] != 0) return + + bucket[index] = argument + initializeStatus = initializeStatus or initializeMask[index] + } + + public override fun clone(): ArgumentBucket { + return ArgumentBucket(bucket.copyOf(), initializeStatus, initializeMask, completionValue) + } +} From 9c799c33c9bb2b91ffe0a15af2adc9e20a8ad3e2 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Tue, 25 Feb 2020 00:10:09 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=E5=BC=95=E6=95=B0=E3=81=AF=E3=83=90?= =?UTF-8?q?=E3=82=B1=E3=83=84=E3=82=AF=E3=83=A9=E3=82=B9=E3=81=A7=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wrongwrong/mapk/core/KFunctionForCall.kt | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt b/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt index 7e875ed..0802090 100644 --- a/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt +++ b/src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt @@ -6,20 +6,33 @@ import kotlin.reflect.jvm.isAccessible class KFunctionForCall(private val function: KFunction, instance: Any? = null) { val parameters: List = function.parameters - private val originalArgumentBucket: List - val argumentBucket: Array get() = originalArgumentBucket.toTypedArray() + private val originalArgumentBucket: ArgumentBucket + + fun getArgumentBucket(): ArgumentBucket = originalArgumentBucket.clone() init { // この関数には確実にアクセスするためアクセシビリティ書き換え function.isAccessible = true originalArgumentBucket = if (instance != null) { - List(parameters.size) { if (it == 0) instance else null } + ArgumentBucket( + Array(parameters.size) { if (it == 0) instance else null }, + 1, + generateSequence(1) { it.shl(1) } + .take(parameters.size) + .toList() + ) } else { - List(parameters.size) { null } + ArgumentBucket( + Array(parameters.size) { null }, + 0, + generateSequence(1) { it.shl(1) } + .take(parameters.size) + .toList() + ) } } - fun call(arguments: Array): T { - return function.call(*arguments) + fun call(argumentBucket: ArgumentBucket): T { + return function.call(*argumentBucket.bucket) } } From 413e4b862aa49935a935a965fd12655175dd5422 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Tue, 25 Feb 2020 00:10:24 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=E3=83=90=E3=82=B1=E3=83=84=E3=82=AF?= =?UTF-8?q?=E3=83=A9=E3=82=B9=E3=82=92=E7=94=A8=E3=81=84=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wrongwrong/mapk/core/KMapper.kt | 62 +++++++++++++------ 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt index bbf401a..7d4b9c4 100644 --- a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt +++ b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt @@ -40,64 +40,90 @@ class KMapper private constructor( if (parameterMap.isEmpty()) throw IllegalArgumentException("This function is not require arguments.") } - private fun bindParameters(targetBucket: Array, src: Any) { + private fun throwExceptionOnNotInitialized(argumentBucket: ArgumentBucket): Nothing { + val notInitializedIndexes = argumentBucket.notInitializedParameterIndexes + function.parameters + .filter { it.index in notInitializedIndexes } + .map { it.name } + .joinToString(", ") + .let { + throw IllegalArgumentException("Not passed arguments: $it") + } + } + + private fun bindArguments(argumentBucket: ArgumentBucket, src: Any) { src::class.memberProperties.forEach { property -> val javaGetter: Method? = property.javaGetter if (javaGetter != null && property.visibility == KVisibility.PUBLIC && property.annotations.none { annotation -> annotation is KPropertyIgnore }) { parameterMap[property.findAnnotation()?.value ?: property.name]?.let { // javaGetterを呼び出す方が高速 javaGetter.isAccessible = true - targetBucket[it.index] = javaGetter.invoke(src)?.let { value -> mapObject(it, value) } + argumentBucket.setArgument(javaGetter.invoke(src)?.let { value -> mapObject(it, value) }, it.index) + // 終了判定 + if (argumentBucket.isInitialized) return } } } } - private fun bindParameters(targetBucket: Array, src: Map<*, *>) { + private fun bindArguments(argumentBucket: ArgumentBucket, src: Map<*, *>) { src.forEach { (key, value) -> parameterMap[key]?.let { param -> // 取得した内容がnullでなければ適切にmapする - targetBucket[param.index] = value?.let { mapObject(param, it) } + argumentBucket.setArgument(value?.let { mapObject(param, it) }, param.index) + // 終了判定 + if (argumentBucket.isInitialized) return } } } - private fun bindParameters(targetBucket: Array, srcPair: Pair<*, *>) { - parameterMap.getValue(srcPair.first.toString()).let { - targetBucket[it.index] = srcPair.second?.let { value -> mapObject(it, value) } + private fun bindArguments(argumentBucket: ArgumentBucket, srcPair: Pair<*, *>) { + parameterMap[srcPair.first.toString()]?.let { + argumentBucket.setArgument(srcPair.second?.let { value -> mapObject(it, value) }, it.index) } } fun map(srcMap: Map): T { - val bucket: Array = function.argumentBucket - bindParameters(bucket, srcMap) + val bucket: ArgumentBucket = function.getArgumentBucket() + bindArguments(bucket, srcMap) + + if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket) + return function.call(bucket) } fun map(srcPair: Pair): T { - val bucket: Array = function.argumentBucket - bindParameters(bucket, srcPair) + val bucket: ArgumentBucket = function.getArgumentBucket() + bindArguments(bucket, srcPair) + + if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket) + return function.call(bucket) } fun map(src: Any): T { - val bucket: Array = function.argumentBucket - bindParameters(bucket, src) + val bucket: ArgumentBucket = function.getArgumentBucket() + bindArguments(bucket, src) + + if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket) + return function.call(bucket) } fun map(vararg args: Any): T { - val array: Array = function.argumentBucket + val bucket: ArgumentBucket = function.getArgumentBucket() listOf(*args).forEach { arg -> when (arg) { - is Map<*, *> -> bindParameters(array, arg) - is Pair<*, *> -> bindParameters(array, arg) - else -> bindParameters(array, arg) + is Map<*, *> -> bindArguments(bucket, arg) + is Pair<*, *> -> bindArguments(bucket, arg) + else -> bindArguments(bucket, arg) } } - return function.call(array) + if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket) + + return function.call(bucket) } } From cd8c667e3e4aa24442d6cd8fdb732bb5e848eb23 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Tue, 25 Feb 2020 10:03:50 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=E5=90=8C=E3=81=98=E3=82=82=E3=81=97?= =?UTF-8?q?=E3=81=8F=E3=81=AF=E3=82=B5=E3=83=96=E3=82=AF=E3=83=A9=E3=82=B9?= =?UTF-8?q?=E3=81=AE=E5=88=A4=E5=AE=9A=E3=82=92=E5=A4=96=E5=87=BA=E3=81=97?= =?UTF-8?q?=E3=81=97=E3=81=A6lazy=E5=AE=A3=E8=A8=80=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt index 7d4b9c4..c67d38e 100644 --- a/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt +++ b/src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt @@ -149,15 +149,15 @@ internal fun getTarget(clazz: KClass): KFunctionForCall { private fun mapObject(param: ParameterForMap, value: T): Any? { val valueClazz: KClass<*> = value::class - val creator: KFunction<*>? by lazy { - param.getCreator(valueClazz) - } + + // パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる + if (param.clazz.isSuperclassOf(valueClazz)) return value + + val creator: KFunction<*>? = param.getCreator(valueClazz) return when { - // パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる - param.clazz.isSuperclassOf(valueClazz) -> value // creatorに一致する組み合わせが有れば設定されていればそれを使う - creator != null -> creator!!.call(value) + creator != null -> creator.call(value) // 要求された値がenumかつ元が文字列ならenum mapperでマップ param.javaClazz.isEnum && value is String -> EnumMapper.getEnum(param.clazz.java, value) // 要求されているパラメータがStringならtoStringする