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

Commit 7995a8a

Browse files
authored
Merge pull request #25 from k163377/getter_cache
Add get cache and fixes.
2 parents 66006aa + aa9ca10 commit 7995a8a

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group = "com.mapk"
9-
version = "0.21"
9+
version = "0.22"
1010

1111
java {
1212
sourceCompatibility = JavaVersion.VERSION_1_8

src/main/kotlin/com/mapk/kmapper/KMapper.kt

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import com.mapk.core.getAliasOrName
88
import com.mapk.core.isUseDefaultArgument
99
import com.mapk.core.toKConstructor
1010
import java.lang.reflect.Method
11+
import java.util.concurrent.ConcurrentHashMap
12+
import java.util.concurrent.ConcurrentMap
1113
import kotlin.reflect.KClass
1214
import kotlin.reflect.KFunction
1315
import kotlin.reflect.KParameter
@@ -31,7 +33,20 @@ class KMapper<T : Any> private constructor(
3133
.filter { it.kind != KParameter.Kind.INSTANCE && !it.isUseDefaultArgument() }
3234
.associate { (parameterNameConverter(it.getAliasOrName()!!)) to ParameterForMap.newInstance(it) }
3335

36+
private val getCache: ConcurrentMap<KClass<*>, List<(Any, ArgumentBucket) -> Unit>> = ConcurrentHashMap()
37+
3438
private fun bindArguments(argumentBucket: ArgumentBucket, src: Any) {
39+
val clazz = src::class
40+
41+
// キャッシュヒットしたら登録した内容に沿って取得処理を行う
42+
getCache[clazz]?.let { getters ->
43+
// 取得対象フィールドは十分絞り込んでいると考えられるため、終了判定は行わない
44+
getters.forEach { it(src, argumentBucket) }
45+
return
46+
}
47+
48+
val tempCacheArrayList = ArrayList<(Any, ArgumentBucket) -> Unit>()
49+
3550
src::class.memberProperties.forEach outer@{ property ->
3651
// propertyが公開されていない場合は処理を行わない
3752
if (property.visibility != KVisibility.PUBLIC) return@outer
@@ -46,14 +61,22 @@ class KMapper<T : Any> private constructor(
4661
if (it is KGetterAlias) alias = it.value
4762
}
4863

49-
parameterMap[alias ?: property.name]?.let {
50-
// javaGetterを呼び出す方が高速
64+
parameterMap[alias ?: property.name]?.let { param ->
5165
javaGetter.isAccessible = true
52-
argumentBucket.putIfAbsent(it.param, javaGetter.invoke(src)?.let { value -> it.mapObject(value) })
53-
// 終了判定
54-
if (argumentBucket.isInitialized) return
66+
67+
val tempCache = { value: Any, bucket: ArgumentBucket ->
68+
// 初期化済みであれば高コストな取得処理は行わない
69+
if (!bucket.containsKey(param.param)) {
70+
// javaGetterを呼び出す方が高速
71+
bucket.putIfAbsent(param.param, javaGetter.invoke(value)?.let { param.mapObject(it) })
72+
}
73+
}
74+
tempCache(src, argumentBucket)
75+
tempCacheArrayList.add(tempCache)
76+
// キャッシュの整合性を保つため、ここでは終了判定を行わない
5577
}
5678
}
79+
getCache.putIfAbsent(clazz, tempCacheArrayList)
5780
}
5881

5982
private fun bindArguments(argumentBucket: ArgumentBucket, src: Map<*, *>) {

src/main/kotlin/com/mapk/kmapper/ParameterForMap.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.mapk.kmapper
22

33
import com.mapk.core.EnumMapper
4+
import java.util.concurrent.ConcurrentHashMap
5+
import java.util.concurrent.ConcurrentMap
46
import kotlin.reflect.KClass
57
import kotlin.reflect.KFunction
68
import kotlin.reflect.KParameter
@@ -13,7 +15,7 @@ internal class ParameterForMap<T : Any> private constructor(val param: KParamete
1315
// リストの長さが小さいと期待されるためこの形で実装しているが、理想的にはmap的なものが使いたい
1416
private val converters: Set<Pair<KClass<*>, KFunction<T>>> = clazz.getConverters()
1517

16-
private val convertCache: MutableMap<KClass<*>, (Any) -> Any?> = HashMap()
18+
private val convertCache: ConcurrentMap<KClass<*>, (Any) -> Any?> = ConcurrentHashMap()
1719

1820
fun <U : Any> mapObject(value: U): Any? {
1921
val valueClazz: KClass<*> = value::class
@@ -23,7 +25,7 @@ internal class ParameterForMap<T : Any> private constructor(val param: KParamete
2325

2426
// パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる
2527
if (clazz.isSuperclassOf(valueClazz)) {
26-
convertCache[valueClazz] = { value }
28+
convertCache.putIfAbsent(valueClazz) { it }
2729
return value
2830
}
2931

@@ -38,7 +40,7 @@ internal class ParameterForMap<T : Any> private constructor(val param: KParamete
3840
clazz == String::class -> { { it.toString() } }
3941
else -> throw IllegalArgumentException("Can not convert $valueClazz to $clazz")
4042
}
41-
convertCache[valueClazz] = lambda
43+
convertCache.putIfAbsent(valueClazz, lambda)
4244
return lambda(value)
4345
}
4446

0 commit comments

Comments
 (0)