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

Commit a71e323

Browse files
committed
パフォーマンス向上のため全面的に書き直し
1 parent 68d4b52 commit a71e323

File tree

1 file changed

+171
-92
lines changed

1 file changed

+171
-92
lines changed

src/main/kotlin/com/mapk/fastkfunction/FastKFunction.kt

Lines changed: 171 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,124 +2,203 @@ package com.mapk.fastkfunction
22

33
import com.mapk.fastkfunction.argumentbucket.ArgumentBucket
44
import com.mapk.fastkfunction.argumentbucket.BucketGenerator
5-
import java.lang.Exception
6-
import java.lang.UnsupportedOperationException
75
import java.lang.reflect.Method
86
import java.lang.reflect.Modifier
7+
import java.lang.reflect.Constructor as JavaConstructor
98
import kotlin.reflect.KFunction
109
import kotlin.reflect.KParameter
1110
import kotlin.reflect.jvm.isAccessible
1211
import kotlin.reflect.jvm.javaConstructor
1312
import kotlin.reflect.jvm.javaMethod
1413

15-
class FastKFunction<T>(private val function: KFunction<T>, instance: Any? = null) {
16-
val valueParameters: List<KParameter> // 公開するのはバインドに使うパラメータのみ
17-
private val fullInitializedFunction: (Array<out Any?>) -> T
18-
private val bucketGenerator: BucketGenerator
14+
sealed class FastKFunction<T> {
15+
abstract val valueParameters: List<KParameter>
16+
internal abstract val bucketGenerator: BucketGenerator
17+
fun generateBucket(): ArgumentBucket = bucketGenerator.generateBucket()
1918

20-
companion object {
21-
private fun List<KParameter>.checkParameters(instance: Any?) = apply {
22-
if (isEmpty() || (instance != null && size == 1))
23-
throw IllegalArgumentException("This function is not require arguments.")
19+
abstract fun callBy(bucket: ArgumentBucket): T
20+
abstract fun callByCollection(args: Collection<Any?>): T
21+
abstract fun call(vararg args: Any?): T
2422

25-
if (3 <= size && get(0).kind != KParameter.Kind.VALUE && get(1).kind != KParameter.Kind.VALUE)
26-
throw IllegalArgumentException("This function is require multiple instances.")
23+
internal class Constructor<T>(
24+
private val function: KFunction<T>,
25+
private val constructor: JavaConstructor<T>,
26+
override val valueParameters: List<KParameter>
27+
) : FastKFunction<T>() {
28+
override val bucketGenerator = BucketGenerator(valueParameters, null)
29+
30+
override fun callBy(bucket: ArgumentBucket): T = if (bucket.isFullInitialized()) {
31+
constructor.newInstance(*bucket.getValueArray())
32+
} else {
33+
function.callBy(bucket)
34+
}
35+
36+
override fun callByCollection(args: Collection<Any?>): T = constructor.newInstance(*args.toTypedArray())
37+
38+
override fun call(vararg args: Any?): T = constructor.newInstance(*args)
39+
}
40+
41+
internal class Function<T>(
42+
private val function: KFunction<T>,
43+
override val valueParameters: List<KParameter>
44+
) : FastKFunction<T>() {
45+
override val bucketGenerator = BucketGenerator(valueParameters, null)
46+
47+
override fun callBy(bucket: ArgumentBucket): T = if (bucket.isFullInitialized()) {
48+
function.call(*bucket.getValueArray())
49+
} else {
50+
function.callBy(bucket)
2751
}
2852

29-
private fun <T> getFunctionCall(function: KFunction<T>): (Array<out Any?>) -> T = { function.call(*it) }
53+
override fun callByCollection(args: Collection<Any?>): T = function.call(*args.toTypedArray())
54+
55+
override fun call(vararg args: Any?): T = function.call(*args)
56+
}
57+
58+
internal class TopLevelFunction<T>(
59+
private val function: KFunction<T>,
60+
private val method: Method,
61+
override val valueParameters: List<KParameter>
62+
) : FastKFunction<T>() {
63+
override val bucketGenerator = BucketGenerator(valueParameters, null)
64+
65+
@Suppress("UNCHECKED_CAST")
66+
override fun callBy(bucket: ArgumentBucket): T = if (bucket.isFullInitialized()) {
67+
method.invoke(null, *bucket.getValueArray()) as T
68+
} else {
69+
function.callBy(bucket)
70+
}
3071

31-
// methodはTを返せないため強制キャスト
3272
@Suppress("UNCHECKED_CAST")
33-
private fun <T> getStaticMethodCall(method: Method, instance: Any): (Array<out Any?>) -> T =
34-
{ method.invoke(null, instance, *it) as T }
73+
override fun callByCollection(args: Collection<Any?>): T = method.invoke(null, *args.toTypedArray()) as T
3574

3675
@Suppress("UNCHECKED_CAST")
37-
private fun <T> getInstanceMethodCall(method: Method, instance: Any): (Array<out Any?>) -> T =
38-
{ method.invoke(instance, *it) as T }
76+
override fun call(vararg args: Any?): T = method.invoke(null, *args) as T
3977
}
4078

41-
init {
42-
// 引数を要求しないか、複数のインスタンスを求める場合エラーとする
43-
val parameters: List<KParameter> = function.parameters.checkParameters(instance)
79+
internal class TopLevelExtensionFunction<T>(
80+
private val function: KFunction<T>,
81+
private val method: Method,
82+
private val extensionReceiver: Any?,
83+
override val bucketGenerator: BucketGenerator,
84+
override val valueParameters: List<KParameter>
85+
) : FastKFunction<T>() {
86+
@Suppress("UNCHECKED_CAST")
87+
override fun callBy(bucket: ArgumentBucket): T = if (bucket.isFullInitialized()) {
88+
method.invoke(null, extensionReceiver, *bucket.getValueArray()) as T
89+
} else {
90+
function.callBy(bucket)
91+
}
4492

45-
// この関数には確実にアクセスするためアクセシビリティ書き換え
46-
function.isAccessible = true
93+
@Suppress("UNCHECKED_CAST")
94+
override fun callByCollection(args: Collection<Any?>): T =
95+
method.invoke(null, extensionReceiver, *args.toTypedArray()) as T
4796

48-
val constructor = function.javaConstructor
97+
@Suppress("UNCHECKED_CAST")
98+
override fun call(vararg args: Any?): T = method.invoke(null, extensionReceiver, *args) as T
99+
}
49100

50-
if (constructor != null) {
51-
valueParameters = parameters
52-
bucketGenerator = BucketGenerator(parameters, null)
53-
fullInitializedFunction = { constructor.newInstance(*it) }
101+
internal class InstanceFunction<T>(
102+
private val function: KFunction<T>,
103+
private val method: Method,
104+
private val instance: Any,
105+
override val bucketGenerator: BucketGenerator,
106+
override val valueParameters: List<KParameter>
107+
) : FastKFunction<T>() {
108+
@Suppress("UNCHECKED_CAST")
109+
override fun callBy(bucket: ArgumentBucket): T = if (bucket.isFullInitialized()) {
110+
method.invoke(instance, *bucket.getValueArray()) as T
54111
} else {
55-
val method = function.javaMethod!!
56-
57-
when (parameters[0].kind) {
58-
KParameter.Kind.EXTENSION_RECEIVER -> {
59-
// 対象が拡張関数ならinstanceはreceiver、指定が無ければエラー
60-
instance ?: throw IllegalArgumentException(
61-
"Function requires EXTENSION_RECEIVER instance, but is not present."
62-
)
63-
64-
valueParameters = parameters.subList(1, parameters.size)
65-
bucketGenerator = BucketGenerator(parameters, instance)
66-
fullInitializedFunction = getStaticMethodCall(method, instance)
67-
}
68-
KParameter.Kind.INSTANCE -> {
69-
valueParameters = parameters.subList(1, parameters.size)
70-
71-
// 対象がインスタンスを要求する関数ならinstanceはobject、与えられたインスタンスがnullでもobjectからの取得を試みる
72-
val nonNullInstance = instance ?: try {
73-
method.declaringObject!!
74-
} catch (e: Exception) {
75-
throw IllegalArgumentException("Function requires INSTANCE parameter, but is not present.", e)
76-
}
77-
78-
bucketGenerator = BucketGenerator(parameters, nonNullInstance)
79-
fullInitializedFunction = getInstanceMethodCall(method, nonNullInstance)
80-
}
81-
KParameter.Kind.VALUE -> {
82-
valueParameters = parameters
83-
bucketGenerator = BucketGenerator(parameters, null)
84-
85-
fullInitializedFunction = if (instance != null) {
86-
// staticメソッドならば渡されたのが拡張関数でinstanceはレシーバと見做す
87-
if (Modifier.isStatic(method.modifiers)) {
88-
getStaticMethodCall(method, instance)
89-
} else {
90-
getInstanceMethodCall(method, instance)
91-
}
92-
} else {
93-
// staticメソッドかつ引数の数がKFunctionの引数の数と変わらない場合はトップレベル関数(= 実体はstatic関数)
94-
if (Modifier.isStatic(method.modifiers) && parameters.size == method.parameters.size) {
95-
@Suppress("UNCHECKED_CAST")
96-
{ method.invoke(null, *it) as T }
97-
} else {
98-
try {
99-
// 定義先がobjectであればインスタンスを利用した呼び出しを行い、そうでなければ普通に呼び出す
100-
method.declaringObject
101-
?.let { instanceFromClass -> getInstanceMethodCall(method, instanceFromClass) }
102-
?: getFunctionCall(function)
103-
} catch (e: UnsupportedOperationException) {
104-
// トップレベル関数でobjectInstanceを取得しようとするとUnsupportedOperationExceptionになるためtryする
105-
getFunctionCall(function)
106-
}
107-
}
108-
}
109-
}
110-
}
112+
function.callBy(bucket)
111113
}
114+
115+
@Suppress("UNCHECKED_CAST")
116+
override fun callByCollection(args: Collection<Any?>): T = method.invoke(instance, *args.toTypedArray()) as T
117+
118+
@Suppress("UNCHECKED_CAST")
119+
override fun call(vararg args: Any?): T = method.invoke(instance, *args) as T
112120
}
113121

114-
fun generateBucket(): ArgumentBucket = bucketGenerator.generateBucket()
122+
companion object {
123+
private fun List<KParameter>.checkParameters(instance: Any?) = also {
124+
if (isEmpty() || (instance != null && size == 1))
125+
throw IllegalArgumentException("This function is not require arguments.")
126+
127+
if (3 <= size && get(0).kind != KParameter.Kind.VALUE && get(1).kind != KParameter.Kind.VALUE)
128+
throw IllegalArgumentException("This function is require multiple instances.")
129+
}
115130

116-
fun callBy(bucket: ArgumentBucket): T = if (bucket.isFullInitialized())
117-
fullInitializedFunction(bucket.getValueArray())
118-
else
119-
function.callBy(bucket)
131+
private fun <T> topLevelFunctionOf(
132+
function: KFunction<T>, instance: Any?, parameters: List<KParameter>, method: Method
133+
): FastKFunction<T> {
134+
return if (parameters[0].kind == KParameter.Kind.EXTENSION_RECEIVER) {
135+
// KParameter.Kind.EXTENSION_RECEIVERの要求が有れば確定で拡張関数
136+
// 対象が拡張関数ならinstanceはreceiver、指定が無ければエラー
137+
instance ?: throw IllegalArgumentException(
138+
"Function requires EXTENSION_RECEIVER instance, but is not present."
139+
)
140+
141+
val generator = BucketGenerator(parameters, instance)
142+
val valueParameters = parameters.subList(1, parameters.size)
143+
144+
TopLevelExtensionFunction(function, method, instance, generator, valueParameters)
145+
} else if (method.parameters.size != parameters.size) {
146+
// javaMethodのパラメータサイズとKFunctionのパラメータサイズが違う場合も拡張関数
147+
// インスタンスが設定されていれば高速呼び出し、そうじゃなければ通常の関数呼び出し
148+
instance
149+
?.let {
150+
val generator = BucketGenerator(parameters, instance)
151+
val valueParameters = parameters.subList(1, parameters.size)
152+
153+
TopLevelExtensionFunction(function, method, instance, generator, valueParameters)
154+
} ?: Function(function, parameters)
155+
} else {
156+
// トップレベル関数
157+
TopLevelFunction(function, method, parameters)
158+
}
159+
}
160+
161+
private fun <T> instanceFunctionOf(
162+
function: KFunction<T>, inputtedInstance: Any?, parameters: List<KParameter>, method: Method
163+
): FastKFunction<T> {
164+
val instance = inputtedInstance ?: method.declaringObject
165+
166+
return if (parameters[0].kind == KParameter.Kind.INSTANCE) {
167+
instance ?: throw IllegalArgumentException("Function requires INSTANCE parameter, but is not present.")
168+
169+
val generator = BucketGenerator(parameters, instance)
170+
val valueParameters = parameters.subList(1, parameters.size)
171+
172+
InstanceFunction(function, method, instance, generator, valueParameters)
173+
} else {
174+
instance
175+
?.let {
176+
InstanceFunction(function, method, instance, BucketGenerator(parameters, null), parameters)
177+
} ?: Function(function, parameters)
178+
}
179+
}
120180

121-
fun callByCollection(args: Collection<Any?>): T = fullInitializedFunction(args.toTypedArray())
181+
fun <T> of(function: KFunction<T>, instance: Any? = null): FastKFunction<T> {
182+
// 引数を要求しないか、複数のインスタンスを求める場合エラーとする
183+
val parameters: List<KParameter> = function.parameters.checkParameters(instance)
122184

123-
@Suppress("UNCHECKED_CAST")
124-
fun call(vararg args: Any?): T = fullInitializedFunction(args)
185+
// この関数には確実にアクセスするためアクセシビリティ書き換え
186+
function.isAccessible = true
187+
188+
val constructor = function.javaConstructor
189+
190+
return if (constructor != null) {
191+
Constructor(function, constructor, parameters)
192+
} else {
193+
val method = function.javaMethod!!
194+
195+
// Methodがstatic関数ならfunctionはトップレベル関数
196+
if (Modifier.isStatic(method.modifiers)) {
197+
topLevelFunctionOf(function, instance, parameters, method)
198+
} else {
199+
instanceFunctionOf(function, instance, parameters, method)
200+
}
201+
}
202+
}
203+
}
125204
}

0 commit comments

Comments
 (0)