Skip to content

Commit cf4c4b9

Browse files
committed
feat : array support
1 parent 6299555 commit cf4c4b9

6 files changed

Lines changed: 159 additions & 7 deletions

File tree

examples/src/main/java/com/github/elebras1/flecs/examples/ComplexComponentExample.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.github.elebras1.flecs.Entity;
44
import com.github.elebras1.flecs.World;
55
import com.github.elebras1.flecs.collection.LongList;
6+
import com.github.elebras1.flecs.examples.components.Border;
67
import com.github.elebras1.flecs.examples.components.Ideology;
78
import com.github.elebras1.flecs.examples.components.Minister;
89

@@ -19,6 +20,7 @@ public static void main(String[] args) {
1920
World world = new World();
2021
world.component(Minister.class);
2122
world.component(Ideology.class);
23+
world.component(Border.class);
2224

2325
long start = System.currentTimeMillis();
2426
LongList entityIds = new LongList();
@@ -33,6 +35,10 @@ public static void main(String[] args) {
3335

3436
e.set(new Minister("Minister_" + i, "TAG_" + i, 1.0f, startDate, endDate));
3537
e.set(new Ideology(i % 256, (byte) (i % 100), (short) (i % 5000)));
38+
39+
if (i % 10 == 0) {
40+
e.set(new Border(new int[2000], new int[2000]));
41+
}
3642
}
3743

3844
long creationEnd = System.currentTimeMillis();
@@ -50,4 +56,4 @@ public static void main(String[] args) {
5056

5157
world.close();
5258
}
53-
}
59+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.github.elebras1.flecs.examples.components;
2+
3+
import com.github.elebras1.flecs.annotation.Component;
4+
import com.github.elebras1.flecs.annotation.FixedArray;
5+
6+
@Component
7+
public record Border(@FixedArray(length = 2000) int[] xPixels, @FixedArray(length = 2000) int[] yPixels) {
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.github.elebras1.flecs.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.SOURCE)
9+
@Target(ElementType.RECORD_COMPONENT)
10+
public @interface FixedArray {
11+
int length();
12+
}

src/main/java/com/github/elebras1/flecs/processor/ComponentCodeGenerator.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.github.elebras1.flecs.processor;
22

33

4+
import com.github.elebras1.flecs.annotation.FixedArray;
45
import com.github.elebras1.flecs.annotation.FixedString;
56
import com.palantir.javapoet.*;
67

@@ -62,6 +63,18 @@ private int getStringSize(VariableElement field) {
6263
return DEFAULT_STRING_SIZE;
6364
}
6465

66+
private int getArrayLength(VariableElement field) {
67+
FixedArray annotation = field.getAnnotation(FixedArray.class);
68+
if (annotation != null) {
69+
int length = annotation.length();
70+
if (length <= 0) {
71+
throw new IllegalArgumentException("Field '" + field.getSimpleName() + "': @FixedArray length must be greater than 0. Got: " + length);
72+
}
73+
return length;
74+
}
75+
throw new IllegalArgumentException("Field '" + field.getSimpleName() + "': Missing @FixedArray annotation for array type.");
76+
}
77+
6578
private FieldSpec createLayoutField(String recordName, List<VariableElement> fields) {
6679
CodeBlock.Builder layoutBuilder = CodeBlock.builder().add("$L.createStructLayout($S", LAYOUT_FIELD_CLASS, recordName);
6780

@@ -76,10 +89,15 @@ private FieldSpec createLayoutField(String recordName, List<VariableElement> fie
7689
if ("java.lang.String".equals(type)) {
7790
int size = this.getStringSize(field);
7891
layoutBuilder.add("$L.$L($L).withName($S)", LAYOUT_FIELD_CLASS, layoutMethod, size, fieldName);
92+
} else if (type.endsWith("[]")) {
93+
int length = this.getArrayLength(field);
94+
layoutBuilder.add("$L.$L($L).withName($S)", LAYOUT_FIELD_CLASS, layoutMethod, length, fieldName);
7995
} else {
8096
layoutBuilder.add("$L.$L().withName($S)", LAYOUT_FIELD_CLASS, layoutMethod, fieldName);
8197
}
82-
if (i < fields.size() - 1) layoutBuilder.add(",\n");
98+
if (i < fields.size() - 1) {
99+
layoutBuilder.add(",\n");
100+
}
83101
}
84102
layoutBuilder.unindent();
85103
}
@@ -129,6 +147,9 @@ private MethodSpec createWriteMethod(String recordName, List<VariableElement> fi
129147
if ("java.lang.String".equals(typeName)) {
130148
int size = this.getStringSize(field);
131149
method.addStatement("$L.set(segment, $L, data.$L(), $L)", LAYOUT_FIELD_CLASS, offsetName, fieldName, size);
150+
} else if (typeName.endsWith("[]")) {
151+
int length = this.getArrayLength(field);
152+
method.addStatement("$L.set(segment, $L, data.$L(), $L)", LAYOUT_FIELD_CLASS, offsetName, fieldName, length);
132153
} else {
133154
method.addStatement("$L.set(segment, $L, data.$L())", LAYOUT_FIELD_CLASS, offsetName, fieldName);
134155
}
@@ -152,6 +173,9 @@ private MethodSpec createReadMethod(String packageName, String recordName, List<
152173
if ("java.lang.String".equals(typeName)) {
153174
int size = this.getStringSize(field);
154175
method.addStatement("$T $L = $L.$L(segment, $L, $L)", String.class, fieldName, LAYOUT_FIELD_CLASS, getterMethod, offsetName, size);
176+
} else if (typeName.endsWith("[]")) {
177+
int length = this.getArrayLength(field);
178+
method.addStatement("$L $L = $L.$L(segment, $L, $L)", typeName, fieldName, LAYOUT_FIELD_CLASS, getterMethod, offsetName, length);
155179
} else {
156180
method.addStatement("$L $L = $L.$L(segment, $L)", typeName, fieldName, LAYOUT_FIELD_CLASS, getterMethod, offsetName);
157181
}
@@ -218,7 +242,14 @@ private String getLayoutMethod(String type) {
218242
case "float" -> "floatLayout";
219243
case "double" -> "doubleLayout";
220244
case "boolean" -> "booleanLayout";
221-
case "java.lang.String" -> "sequenceLayout";
245+
case "byte[]" -> "byteArrayLayout";
246+
case "short[]" -> "shortArrayLayout";
247+
case "int[]" -> "intArrayLayout";
248+
case "long[]" -> "longArrayLayout";
249+
case "float[]" -> "floatArrayLayout";
250+
case "double[]" -> "doubleArrayLayout";
251+
case "boolean[]" -> "booleanArrayLayout";
252+
case "java.lang.String" -> "stringLayout";
222253
default -> throw new IllegalArgumentException("Unsupported type: " + type);
223254
};
224255
}
@@ -232,6 +263,13 @@ private String getGetterMethod(String type) {
232263
case "float" -> "getFloat";
233264
case "double" -> "getDouble";
234265
case "boolean" -> "getBoolean";
266+
case "byte[]" -> "getByteArray";
267+
case "short[]" -> "getShortArray";
268+
case "int[]" -> "getIntArray";
269+
case "long[]" -> "getLongArray";
270+
case "float[]" -> "getFloatArray";
271+
case "double[]" -> "getDoubleArray";
272+
case "boolean[]" -> "getBooleanArray";
235273
case "java.lang.String" -> "getFixedString";
236274
default -> throw new IllegalArgumentException("Unsupported type: " + type);
237275
};

src/main/java/com/github/elebras1/flecs/processor/ComponentProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
@SupportedAnnotationTypes("com.github.elebras1.flecs.annotation.Component")
1414
public class ComponentProcessor extends AbstractProcessor {
1515

16-
private static final Set<String> SUPPORTED_TYPES = Set.of("byte", "short", "int", "long", "float", "double", "boolean", "java.lang.String");
16+
private static final Set<String> SUPPORTED_TYPES = Set.of("byte", "short", "int", "long", "float", "double", "boolean", "byte[]", "short[]", "int[]", "long[]", "float[]", "double[]", "boolean[]", "java.lang.String");
1717
private Messager messager;
1818
private Filer filer;
1919
private ComponentCodeGenerator generator;

src/main/java/com/github/elebras1/flecs/util/LayoutField.java

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,35 @@ public static MemoryLayout booleanLayout() {
3939
return ValueLayout.JAVA_BOOLEAN;
4040
}
4141

42-
public static MemoryLayout sequenceLayout(int capacity) {
42+
public static MemoryLayout intArrayLayout(int length) {
43+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_INT);
44+
}
45+
46+
public static MemoryLayout longArrayLayout(int length) {
47+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_LONG);
48+
}
49+
50+
public static MemoryLayout floatArrayLayout(int length) {
51+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_FLOAT);
52+
}
53+
54+
public static MemoryLayout doubleArrayLayout(int length) {
55+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_DOUBLE);
56+
}
57+
58+
public static MemoryLayout byteArrayLayout(int length) {
59+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_BYTE);
60+
}
61+
62+
public static MemoryLayout shortArrayLayout(int length) {
63+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_SHORT);
64+
}
65+
66+
public static MemoryLayout booleanArrayLayout(int length) {
67+
return MemoryLayout.sequenceLayout(length, ValueLayout.JAVA_BOOLEAN);
68+
}
69+
70+
public static MemoryLayout stringLayout(int capacity) {
4371
return MemoryLayout.sequenceLayout(capacity, ValueLayout.JAVA_BYTE);
4472
}
4573

@@ -67,8 +95,35 @@ public static void set(MemorySegment segment, long offset, long value) {
6795
segment.set(ValueLayout.JAVA_LONG, offset, value);
6896
}
6997

70-
public static void set(MemorySegment segment, long offset, boolean value) {
71-
segment.set(ValueLayout.JAVA_BOOLEAN, offset, value);
98+
public static void set(MemorySegment segment, long offset, int[] value, int capacity) {
99+
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_INT, offset, capacity);
100+
}
101+
102+
public static void set(MemorySegment segment, long offset, long[] value, int capacity) {
103+
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_LONG, offset, capacity);
104+
}
105+
106+
public static void set(MemorySegment segment, long offset, float[] value, int capacity) {
107+
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_FLOAT, offset, capacity);
108+
}
109+
110+
public static void set(MemorySegment segment, long offset, double[] value, int capacity) {
111+
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_DOUBLE, offset, capacity);
112+
}
113+
114+
public static void set(MemorySegment segment, long offset, byte[] value, int capacity) {
115+
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_BYTE, offset, capacity);
116+
}
117+
118+
public static void set(MemorySegment segment, long offset, short[] value, int capacity) {
119+
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_SHORT, offset, capacity);
120+
}
121+
122+
public static void set(MemorySegment segment, long offset, boolean[] value, int capacity) {
123+
int len = Math.min(value.length, capacity);
124+
for (int i = 0; i < len; i++) {
125+
segment.set(ValueLayout.JAVA_BYTE, offset + i, (byte) (value[i] ? 1 : 0));
126+
}
72127
}
73128

74129
public static void set(MemorySegment segment, long offset, String value, int capacity) {
@@ -111,6 +166,39 @@ public static boolean getBoolean(MemorySegment segment, long offset) {
111166
return segment.get(ValueLayout.JAVA_BOOLEAN, offset);
112167
}
113168

169+
public static int[] getIntArray(MemorySegment segment, long offset, int length) {
170+
return segment.asSlice(offset, length * ValueLayout.JAVA_INT.byteSize()).toArray(ValueLayout.JAVA_INT);
171+
}
172+
173+
public static long[] getLongArray(MemorySegment segment, long offset, int length) {
174+
return segment.asSlice(offset, length * ValueLayout.JAVA_LONG.byteSize()).toArray(ValueLayout.JAVA_LONG);
175+
}
176+
177+
public static float[] getFloatArray(MemorySegment segment, long offset, int length) {
178+
return segment.asSlice(offset, length * ValueLayout.JAVA_FLOAT.byteSize()).toArray(ValueLayout.JAVA_FLOAT);
179+
}
180+
181+
public static double[] getDoubleArray(MemorySegment segment, long offset, int length) {
182+
return segment.asSlice(offset, length * ValueLayout.JAVA_DOUBLE.byteSize()).toArray(ValueLayout.JAVA_DOUBLE);
183+
}
184+
185+
public static byte[] getByteArray(MemorySegment segment, long offset, int length) {
186+
return segment.asSlice(offset, length * ValueLayout.JAVA_BYTE.byteSize()).toArray(ValueLayout.JAVA_BYTE);
187+
}
188+
189+
public static short[] getShortArray(MemorySegment segment, long offset, int length) {
190+
return segment.asSlice(offset, length * ValueLayout.JAVA_SHORT.byteSize()).toArray(ValueLayout.JAVA_SHORT);
191+
}
192+
193+
public static boolean[] getBooleanArray(MemorySegment segment, long offset, int length) {
194+
boolean[] result = new boolean[length];
195+
for (int i = 0; i < length; i++) {
196+
byte value = segment.get(ValueLayout.JAVA_BYTE, offset + i);
197+
result[i] = value != 0;
198+
}
199+
return result;
200+
}
201+
114202
public static String getFixedString(MemorySegment segment, long offset, int capacity) {
115203
return segment.asSlice(offset, capacity).getString(0);
116204
}

0 commit comments

Comments
 (0)