Skip to content
This repository was archived by the owner on Jan 20, 2023. It is now read-only.

Commit f7308b9

Browse files
authored
Merge pull request #5 from k163377/fix_when
Fix severity
2 parents c3b2be5 + cd8c667 commit f7308b9

File tree

3 files changed

+99
-34
lines changed

3 files changed

+99
-34
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.wrongwrong.mapk.core
2+
3+
class ArgumentBucket(
4+
val bucket: Array<Any?>,
5+
private var initializeStatus: Int,
6+
private val initializeMask: List<Int>,
7+
// clone時の再計算を避けるため1回で済むようにデフォルト値化
8+
private val completionValue: Int = initializeMask.reduce { l, r -> l or r }
9+
) : Cloneable {
10+
val isInitialized: Boolean get() = initializeStatus == completionValue
11+
val notInitializedParameterIndexes: List<Int> get() = initializeMask.indices.filter {
12+
initializeStatus and initializeMask[it] == 0
13+
}
14+
15+
fun setArgument(argument: Any?, index: Int) {
16+
// 先に入ったものを優先するため、初期化済みなら何もしない
17+
if (initializeStatus and initializeMask[index] != 0) return
18+
19+
bucket[index] = argument
20+
initializeStatus = initializeStatus or initializeMask[index]
21+
}
22+
23+
public override fun clone(): ArgumentBucket {
24+
return ArgumentBucket(bucket.copyOf(), initializeStatus, initializeMask, completionValue)
25+
}
26+
}

src/main/kotlin/com/wrongwrong/mapk/core/KFunctionForCall.kt

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,33 @@ import kotlin.reflect.jvm.isAccessible
66

77
class KFunctionForCall<T>(private val function: KFunction<T>, instance: Any? = null) {
88
val parameters: List<KParameter> = function.parameters
9-
private val originalArray: Array<Any?>
10-
val argumentArray: Array<Any?> get() = originalArray.copyOf()
9+
private val originalArgumentBucket: ArgumentBucket
10+
11+
fun getArgumentBucket(): ArgumentBucket = originalArgumentBucket.clone()
1112

1213
init {
1314
// この関数には確実にアクセスするためアクセシビリティ書き換え
1415
function.isAccessible = true
15-
originalArray = if (instance != null) {
16-
Array(parameters.size) { if (it == 0) instance else null }
16+
originalArgumentBucket = if (instance != null) {
17+
ArgumentBucket(
18+
Array(parameters.size) { if (it == 0) instance else null },
19+
1,
20+
generateSequence(1) { it.shl(1) }
21+
.take(parameters.size)
22+
.toList()
23+
)
1724
} else {
18-
Array(parameters.size) { null }
25+
ArgumentBucket(
26+
Array(parameters.size) { null },
27+
0,
28+
generateSequence(1) { it.shl(1) }
29+
.take(parameters.size)
30+
.toList()
31+
)
1932
}
2033
}
2134

22-
fun call(arguments: Array<Any?>): T {
23-
return function.call(*arguments)
35+
fun call(argumentBucket: ArgumentBucket): T {
36+
return function.call(*argumentBucket.bucket)
2437
}
2538
}

src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,64 +40,90 @@ class KMapper<T : Any> private constructor(
4040
if (parameterMap.isEmpty()) throw IllegalArgumentException("This function is not require arguments.")
4141
}
4242

43-
private fun bindParameters(targetArray: Array<Any?>, src: Any) {
43+
private fun throwExceptionOnNotInitialized(argumentBucket: ArgumentBucket): Nothing {
44+
val notInitializedIndexes = argumentBucket.notInitializedParameterIndexes
45+
function.parameters
46+
.filter { it.index in notInitializedIndexes }
47+
.map { it.name }
48+
.joinToString(", ")
49+
.let {
50+
throw IllegalArgumentException("Not passed arguments: $it")
51+
}
52+
}
53+
54+
private fun bindArguments(argumentBucket: ArgumentBucket, src: Any) {
4455
src::class.memberProperties.forEach { property ->
4556
val javaGetter: Method? = property.javaGetter
4657
if (javaGetter != null && property.visibility == KVisibility.PUBLIC && property.annotations.none { annotation -> annotation is KPropertyIgnore }) {
4758
parameterMap[property.findAnnotation<KGetterAlias>()?.value ?: property.name]?.let {
4859
// javaGetterを呼び出す方が高速
4960
javaGetter.isAccessible = true
50-
targetArray[it.index] = javaGetter.invoke(src)?.let { value -> mapObject(it, value) }
61+
argumentBucket.setArgument(javaGetter.invoke(src)?.let { value -> mapObject(it, value) }, it.index)
62+
// 終了判定
63+
if (argumentBucket.isInitialized) return
5164
}
5265
}
5366
}
5467
}
5568

56-
private fun bindParameters(targetArray: Array<Any?>, src: Map<*, *>) {
69+
private fun bindArguments(argumentBucket: ArgumentBucket, src: Map<*, *>) {
5770
src.forEach { (key, value) ->
5871
parameterMap[key]?.let { param ->
5972
// 取得した内容がnullでなければ適切にmapする
60-
targetArray[param.index] = value?.let { mapObject(param, it) }
73+
argumentBucket.setArgument(value?.let { mapObject(param, it) }, param.index)
74+
// 終了判定
75+
if (argumentBucket.isInitialized) return
6176
}
6277
}
6378
}
6479

65-
private fun bindParameters(targetArray: Array<Any?>, srcPair: Pair<*, *>) {
66-
parameterMap.getValue(srcPair.first.toString()).let {
67-
targetArray[it.index] = srcPair.second?.let { value -> mapObject(it, value) }
80+
private fun bindArguments(argumentBucket: ArgumentBucket, srcPair: Pair<*, *>) {
81+
parameterMap[srcPair.first.toString()]?.let {
82+
argumentBucket.setArgument(srcPair.second?.let { value -> mapObject(it, value) }, it.index)
6883
}
6984
}
7085

7186
fun map(srcMap: Map<String, Any?>): T {
72-
val array: Array<Any?> = function.argumentArray
73-
bindParameters(array, srcMap)
74-
return function.call(array)
87+
val bucket: ArgumentBucket = function.getArgumentBucket()
88+
bindArguments(bucket, srcMap)
89+
90+
if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket)
91+
92+
return function.call(bucket)
7593
}
7694

7795
fun map(srcPair: Pair<String, Any?>): T {
78-
val array: Array<Any?> = function.argumentArray
79-
bindParameters(array, srcPair)
80-
return function.call(array)
96+
val bucket: ArgumentBucket = function.getArgumentBucket()
97+
bindArguments(bucket, srcPair)
98+
99+
if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket)
100+
101+
return function.call(bucket)
81102
}
82103

83104
fun map(src: Any): T {
84-
val array: Array<Any?> = function.argumentArray
85-
bindParameters(array, src)
86-
return function.call(array)
105+
val bucket: ArgumentBucket = function.getArgumentBucket()
106+
bindArguments(bucket, src)
107+
108+
if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket)
109+
110+
return function.call(bucket)
87111
}
88112

89113
fun map(vararg args: Any): T {
90-
val array: Array<Any?> = function.argumentArray
114+
val bucket: ArgumentBucket = function.getArgumentBucket()
91115

92116
listOf(*args).forEach { arg ->
93117
when (arg) {
94-
is Map<*, *> -> bindParameters(array, arg)
95-
is Pair<*, *> -> bindParameters(array, arg)
96-
else -> bindParameters(array, arg)
118+
is Map<*, *> -> bindArguments(bucket, arg)
119+
is Pair<*, *> -> bindArguments(bucket, arg)
120+
else -> bindArguments(bucket, arg)
97121
}
98122
}
99123

100-
return function.call(array)
124+
if (!bucket.isInitialized) throwExceptionOnNotInitialized(bucket)
125+
126+
return function.call(bucket)
101127
}
102128
}
103129

@@ -123,15 +149,15 @@ internal fun <T : Any> getTarget(clazz: KClass<T>): KFunctionForCall<T> {
123149

124150
private fun <T : Any, R : Any> mapObject(param: ParameterForMap<R>, value: T): Any? {
125151
val valueClazz: KClass<*> = value::class
126-
val creator: KFunction<*>? by lazy {
127-
param.getCreator(valueClazz)
128-
}
152+
153+
// パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる
154+
if (param.clazz.isSuperclassOf(valueClazz)) return value
155+
156+
val creator: KFunction<*>? = param.getCreator(valueClazz)
129157

130158
return when {
131-
// パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる
132-
param.clazz.isSuperclassOf(valueClazz) -> value
133159
// creatorに一致する組み合わせが有れば設定されていればそれを使う
134-
creator != null -> creator!!.call(value)
160+
creator != null -> creator.call(value)
135161
// 要求された値がenumかつ元が文字列ならenum mapperでマップ
136162
param.javaClazz.isEnum && value is String -> EnumMapper.getEnum(param.clazz.java, value)
137163
// 要求されているパラメータがStringならtoStringする

0 commit comments

Comments
 (0)