-
Notifications
You must be signed in to change notification settings - Fork 0
/
FlatArrayReflList.java
126 lines (103 loc) · 3.16 KB
/
FlatArrayReflList.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package com.github.stepancheg.mhlang.examples;
import org.objenesis.instantiator.ObjectInstantiator;
import org.objenesis.strategy.StdInstantiatorStrategy;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.Arrays;
/**
* Reflective implementation of {@link com.github.stepancheg.mhlang.examples.FlatArrayMhList}.
*
* <p>Implemented to compare performance of plain reflection vs MH reflection.
*/
public class FlatArrayReflList<T> extends AbstractList<T> {
private final Factory<T> factory;
/** Array of arrays. */
private Object[] fields;
/** Current size. */
private int size = 0;
/** Current capacity. */
private int capacity = 0;
private FlatArrayReflList(Factory<T> factory, Object[] fields) {
this.factory = factory;
this.fields = fields;
}
@Override
public T get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException();
}
T t = factory.instantiator.newInstance();
Field[] fields1 = factory.fields;
for (int i = 0; i < fields1.length; i++) {
Field field = fields1[i];
try {
field.set(t, Array.get(fields[i], index));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return t;
}
@Override
public boolean add(T t) {
if (size == capacity) {
doubleCapacity();
}
Field[] fields1 = factory.fields;
for (int i = 0; i < fields1.length; i++) {
Field field = fields1[i];
try {
Array.set(fields[i], size, field.get(t));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
size += 1;
return true;
}
private void doubleCapacity() {
int newCap = Math.max(size * 2, 10);
Field[] fields1 = factory.fields;
for (int i = 0; i < fields1.length; i++) {
Object array = fields[i];
Object newArray = copyOf(array, newCap);
fields[i] = newArray;
}
this.capacity = newCap;
}
private static Object copyOf(Object array, int newCap) {
return Array.newInstance(array.getClass().getComponentType(), newCap);
}
@Override
public int size() {
return size;
}
public static class Factory<T> {
private final ObjectInstantiator<T> instantiator;
private final Field[] fields;
private final Object[] arrays;
public Factory(Class<T> tClass) {
Field[] fields = tClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
}
this.fields = fields;
this.arrays = Arrays.stream(fields).map(f -> Array.newInstance(f.getType(), 0)).toArray();
instantiator = new StdInstantiatorStrategy().newInstantiatorOf(tClass);
}
public FlatArrayReflList<T> newArrayList() {
return new FlatArrayReflList<>(this, arrays.clone());
}
private static Class<?> fieldArrayComponentType(Field field) {
if (field.getType().isPrimitive()) {
return field.getType();
} else {
return Object.class;
}
}
private static Class<?> fieldArrayType(Field field) {
return Array.newInstance(fieldArrayComponentType(field), 0).getClass();
}
}
}