@@ -2,124 +2,203 @@ package com.mapk.fastkfunction
2
2
3
3
import com.mapk.fastkfunction.argumentbucket.ArgumentBucket
4
4
import com.mapk.fastkfunction.argumentbucket.BucketGenerator
5
- import java.lang.Exception
6
- import java.lang.UnsupportedOperationException
7
5
import java.lang.reflect.Method
8
6
import java.lang.reflect.Modifier
7
+ import java.lang.reflect.Constructor as JavaConstructor
9
8
import kotlin.reflect.KFunction
10
9
import kotlin.reflect.KParameter
11
10
import kotlin.reflect.jvm.isAccessible
12
11
import kotlin.reflect.jvm.javaConstructor
13
12
import kotlin.reflect.jvm.javaMethod
14
13
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()
19
18
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
24
22
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)
27
51
}
28
52
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
+ }
30
71
31
- // methodはTを返せないため強制キャスト
32
72
@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
35
74
36
75
@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
39
77
}
40
78
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
+ }
44
92
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
47
96
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
+ }
49
100
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
54
111
} 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)
111
113
}
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
112
120
}
113
121
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
+ }
115
130
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
+ }
120
180
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)
122
184
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
+ }
125
204
}
0 commit comments