Skip to content

Commit 5c1c0b0

Browse files
committed
collectArguments can produce non-arrays
Also as of 9 it does not need to permute arguments to the end for simple array boxing.
1 parent f2ae53e commit 5c1c0b0

File tree

1 file changed

+49
-30
lines changed
  • src/main/java/com/headius/invokebinder/transform

1 file changed

+49
-30
lines changed

src/main/java/com/headius/invokebinder/transform/Collect.java

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
package com.headius.invokebinder.transform;
1717

1818
import com.headius.invokebinder.Binder;
19+
import com.headius.invokebinder.Util;
1920

2021
import java.lang.invoke.MethodHandle;
2122
import java.lang.invoke.MethodHandles;
2223
import java.lang.invoke.MethodType;
2324

2425
/**
25-
* An argument-boxing transform with a fixed incoming size.
26+
* A filter that takes multiple arguments and replaces them with zero or one argument of a new type.
2627
*
2728
* Equivalent call: MethodHandle.asCollector(Class, int) or MethodHandles.collectArguments
2829
*/
@@ -31,61 +32,68 @@ public class Collect extends Transform {
3132
private final MethodType source;
3233
private final int index;
3334
private final int count;
34-
private final Class<?> arrayType;
35+
private final Class<?> resultType;
3536
private final MethodHandle collector;
3637

37-
public Collect(MethodType source, int index, Class<?> arrayType) {
38+
public Collect(MethodType source, int index, Class<?> resultType) {
3839
this.source = source;
3940
this.index = index;
4041
this.count = source.parameterCount() - index;
41-
this.arrayType = arrayType;
42+
this.resultType = resultType;
4243
this.collector = null;
4344
}
4445

45-
public Collect(MethodType source, int index, Class<?> arrayType, MethodHandle collector) {
46+
public Collect(MethodType source, int index, Class<?> resultType, MethodHandle collector) {
4647
this.source = source;
4748
this.index = index;
4849
this.count = source.parameterCount() - index;
49-
this.arrayType = arrayType;
50+
this.resultType = resultType;
5051
this.collector = collector;
5152
}
5253

53-
public Collect(MethodType source, int index, int count, Class<?> arrayType) {
54+
public Collect(MethodType source, int index, int count, Class<?> resultType) {
5455
this.source = source;
5556
this.index = index;
5657
this.count = count;
57-
this.arrayType = arrayType;
58+
this.resultType = resultType;
5859
this.collector = null;
5960
}
6061

61-
public Collect(MethodType source, int index, int count, Class<?> arrayType, MethodHandle collector) {
62+
public Collect(MethodType source, int index, int count, Class<?> resultType, MethodHandle collector) {
6263
this.source = source;
6364
this.index = index;
6465
this.count = count;
65-
this.arrayType = arrayType;
66+
this.resultType = resultType;
6667
this.collector = collector;
6768
}
6869

6970
public MethodHandle up(MethodHandle target) {
70-
if (onlyTail()) {
71-
// fast path for tail args
72-
if (collector == null) {
73-
return target.asCollector(arrayType, count);
71+
if (collector == null) {
72+
if (Util.isJava9()) {
73+
// Java 9 can collect a subset of non-tail arguments
74+
return target.asCollector(index, resultType, count);
75+
} else {
76+
if (onlyTail()) {
77+
// tail arguments can be array-collected on all Java versions
78+
return target.asCollector(resultType, count);
79+
} else {
80+
// non-tail arguments must be permuted prior to Java 9
81+
Permutes permutes = buildPermutes(source, target.type());
82+
83+
Binder binder = preparePermuteBinder(permutes);
84+
return binder.invoke(target);
85+
}
7486
}
75-
76-
return MethodHandles.collectArguments(target, index, collector);
7787
} else {
78-
Permutes permutes = buildPermutes(source, target.type());
79-
80-
Binder binder = preparePermuteBinder(permutes);
81-
return binder.invoke(target);
88+
// custom collector always collects only as many args as it accepts
89+
return MethodHandles.collectArguments(target, index, collector);
8290
}
8391
}
8492

8593
private Binder preparePermuteBinder(Permutes permutes) {
8694
return Binder.from(source)
8795
.permute(permutes.movePermute)
88-
.collect(source.parameterCount() - count, arrayType, collector)
96+
.collect(source.parameterCount() - count, resultType)
8997
.permute(permutes.moveBackPermute);
9098
}
9199

@@ -94,28 +102,39 @@ public MethodType down(MethodType type) {
94102

95103
return type
96104
.dropParameterTypes(index, index + count)
97-
.insertParameterTypes(index, arrayType);
105+
.insertParameterTypes(index, resultType);
98106
}
99107

100108
private void assertTypesAreCompatible() {
101-
Class<?> componentType = arrayType.getComponentType();
102-
for (int i = index; i < index + count; i++) {
103-
Class<?> in = source.parameterType(i);
104-
assert in.isAssignableFrom(componentType)
105-
: "incoming type " + in.getName() + " not compatible with " + componentType.getName() + "[]";
109+
if (collector == null) {
110+
// default array collector
111+
assert resultType.isArray() : "no collector provided but target type is not array";
112+
Class<?> componentType = resultType.getComponentType();
113+
for (int i = index; i < index + count; i++) {
114+
Class<?> in = source.parameterType(i);
115+
assert in.isAssignableFrom(componentType)
116+
: "incoming type " + in.getName() + " not compatible with " + componentType.getName() + "[]";
117+
}
118+
} else {
119+
for (int i = 0; i < count; i++) {
120+
Class<?> in = source.parameterType(index + i);
121+
Class<?> out = collector.type().parameterType(i);
122+
assert in.isAssignableFrom(out) : "incoming type " + in.getName() + " not compatible with " + out;
123+
}
124+
assert collector.type().returnType().isAssignableFrom(resultType);
106125
}
107126
}
108127

109128
public String toString() {
110-
return "collect at " + index + " into " + arrayType.getName();
129+
return "collect at " + index + " into " + resultType.getName();
111130
}
112131

113132
public String toJava(MethodType incoming) {
114133
StringBuilder builder = new StringBuilder();
115134
if (onlyTail()) {
116135
if (collector == null) {
117136
builder.append("handle = handle.asCollector(");
118-
buildClassArgument(builder, arrayType);
137+
buildClassArgument(builder, resultType);
119138
builder
120139
.append(", ")
121140
.append(count)
@@ -128,7 +147,7 @@ public String toJava(MethodType incoming) {
128147
.append(count)
129148
.append(", ");
130149

131-
buildClassArgument(builder, arrayType);
150+
buildClassArgument(builder, resultType);
132151

133152
builder.append(");");
134153
}

0 commit comments

Comments
 (0)