Skip to content

Commit e16181b

Browse files
dfa1claude
andcommitted
refactor: drop GenericArray; all codecs use typed Array subtypes
Add ByteArray (I8/U8), ShortArray (I16/U16), EmptyArray (zero-length). Delete GenericArray — every codec now returns a concrete typed instance so the JIT can constant-fold ValueLayout access and auto-vectorize hot decode loops. Remove Array.NO_CHILDREN (no remaining callers). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5d3b723 commit e16181b

15 files changed

Lines changed: 256 additions & 157 deletions

File tree

core/src/main/java/io/github/dfa1/vortex/core/Array.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package io.github.dfa1.vortex.core;
22

3-
import io.github.dfa1.vortex.core.array.GenericArray;
3+
import io.github.dfa1.vortex.core.array.EmptyArray;
44

55
import java.lang.foreign.MemorySegment;
66

7-
/// Decoded columnar data. Concrete subtypes specialise element access for the
8-
/// JIT; [GenericArray] is the legacy multi-buffer fallback used by codecs that
9-
/// haven't been migrated yet.
7+
/// Decoded columnar data. Concrete subtypes in [io.github.dfa1.vortex.core.array]
8+
/// specialise element access for the JIT; each covers a specific dtype family.
109
///
1110
/// Buffers are `MemorySegment` slices backed by the memory-mapped file; lifetime
1211
/// is tied to the `VortexFile`'s Arena.
@@ -18,10 +17,8 @@
1817
/// should implement this interface.
1918
public interface Array extends ArrayOperations {
2019

21-
Array[] NO_CHILDREN = new Array[0];
22-
2320
static Array empty(DType dtype) {
24-
return new GenericArray(dtype, 0, new MemorySegment[0], NO_CHILDREN, ArrayStats.empty());
21+
return new EmptyArray(dtype);
2522
}
2623

2724
default ArrayStats stats() {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.github.dfa1.vortex.core.array;
2+
3+
import io.github.dfa1.vortex.core.Array;
4+
import io.github.dfa1.vortex.core.ArrayStats;
5+
import io.github.dfa1.vortex.core.DType;
6+
import io.github.dfa1.vortex.core.PType;
7+
8+
import java.lang.foreign.MemorySegment;
9+
import java.lang.foreign.ValueLayout;
10+
11+
/// Concrete [Array] for I8/U8 primitive columns.
12+
public final class ByteArray implements Array {
13+
14+
private final DType dtype;
15+
private final long length;
16+
private final MemorySegment buffer;
17+
private final ArrayStats stats;
18+
19+
public ByteArray(DType dtype, long length, MemorySegment buffer, ArrayStats stats) {
20+
this.dtype = dtype;
21+
this.length = length;
22+
this.buffer = buffer;
23+
this.stats = stats;
24+
}
25+
26+
@Override
27+
public DType dtype() {
28+
return dtype;
29+
}
30+
31+
@Override
32+
public long length() {
33+
return length;
34+
}
35+
36+
@Override
37+
public ArrayStats stats() {
38+
return stats;
39+
}
40+
41+
@Override
42+
public MemorySegment buffer(int i) {
43+
if (i != 0) {
44+
throw new IndexOutOfBoundsException(i);
45+
}
46+
return buffer;
47+
}
48+
49+
@Override
50+
public byte getByte(long i) {
51+
return buffer.get(ValueLayout.JAVA_BYTE, i);
52+
}
53+
54+
@Override
55+
public long getLong(long i) {
56+
byte raw = buffer.get(ValueLayout.JAVA_BYTE, i);
57+
boolean unsigned = dtype instanceof DType.Primitive p && p.ptype() == PType.U8;
58+
return unsigned ? Byte.toUnsignedLong(raw) : raw;
59+
}
60+
61+
@Override
62+
public int getInt(long i) {
63+
return (int) getLong(i);
64+
}
65+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.github.dfa1.vortex.core.array;
2+
3+
import io.github.dfa1.vortex.core.Array;
4+
import io.github.dfa1.vortex.core.ArrayStats;
5+
import io.github.dfa1.vortex.core.DType;
6+
7+
/// Zero-length [Array] returned by [Array#empty]. Has no buffers or children.
8+
public final class EmptyArray implements Array {
9+
10+
private final DType dtype;
11+
12+
public EmptyArray(DType dtype) {
13+
this.dtype = dtype;
14+
}
15+
16+
@Override
17+
public DType dtype() {
18+
return dtype;
19+
}
20+
21+
@Override
22+
public long length() {
23+
return 0;
24+
}
25+
26+
@Override
27+
public ArrayStats stats() {
28+
return ArrayStats.empty();
29+
}
30+
}

core/src/main/java/io/github/dfa1/vortex/core/array/GenericArray.java

Lines changed: 0 additions & 110 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package io.github.dfa1.vortex.core.array;
2+
3+
import io.github.dfa1.vortex.core.Array;
4+
import io.github.dfa1.vortex.core.ArrayStats;
5+
import io.github.dfa1.vortex.core.DType;
6+
import io.github.dfa1.vortex.core.PType;
7+
8+
import java.lang.foreign.MemorySegment;
9+
import java.lang.foreign.ValueLayout;
10+
import java.nio.ByteOrder;
11+
12+
/// Concrete [Array] for I16/U16 primitive columns.
13+
public final class ShortArray implements Array {
14+
15+
private static final ValueLayout.OfShort LAYOUT =
16+
ValueLayout.JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN);
17+
18+
private final DType dtype;
19+
private final long length;
20+
private final MemorySegment buffer;
21+
private final ArrayStats stats;
22+
23+
public ShortArray(DType dtype, long length, MemorySegment buffer, ArrayStats stats) {
24+
this.dtype = dtype;
25+
this.length = length;
26+
this.buffer = buffer;
27+
this.stats = stats;
28+
}
29+
30+
@Override
31+
public DType dtype() {
32+
return dtype;
33+
}
34+
35+
@Override
36+
public long length() {
37+
return length;
38+
}
39+
40+
@Override
41+
public ArrayStats stats() {
42+
return stats;
43+
}
44+
45+
@Override
46+
public MemorySegment buffer(int i) {
47+
if (i != 0) {
48+
throw new IndexOutOfBoundsException(i);
49+
}
50+
return buffer;
51+
}
52+
53+
@Override
54+
public short getShort(long i) {
55+
return buffer.getAtIndex(LAYOUT, i);
56+
}
57+
58+
@Override
59+
public long getLong(long i) {
60+
short raw = buffer.getAtIndex(LAYOUT, i);
61+
boolean unsigned = dtype instanceof DType.Primitive p && p.ptype() == PType.U16;
62+
return unsigned ? Short.toUnsignedLong(raw) : raw;
63+
}
64+
65+
@Override
66+
public int getInt(long i) {
67+
return (int) getLong(i);
68+
}
69+
}

core/src/main/java/io/github/dfa1/vortex/encoding/BitpackedCodec.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
import io.github.dfa1.vortex.core.ArrayStats;
99
import io.github.dfa1.vortex.core.DType;
1010
import io.github.dfa1.vortex.core.PType;
11-
import io.github.dfa1.vortex.core.array.GenericArray;
11+
import io.github.dfa1.vortex.core.array.ByteArray;
1212
import io.github.dfa1.vortex.core.array.IntArray;
1313
import io.github.dfa1.vortex.core.array.LongArray;
14+
import io.github.dfa1.vortex.core.array.ShortArray;
1415
import io.github.dfa1.vortex.core.VortexException;
1516

1617
import java.lang.foreign.MemorySegment;
@@ -587,11 +588,13 @@ public Array decode(DecodeContext ctx) {
587588
applyPatches(ctx, meta.getPatches(), output, ptype.byteSize());
588589
}
589590

591+
MemorySegment ro = output.asReadOnly();
590592
return switch (ptype) {
591-
case I64, U64 -> new LongArray(ctx.dtype(), rowCount, output.asReadOnly(), ArrayStats.empty());
592-
case I32, U32 -> new IntArray(ctx.dtype(), rowCount, output.asReadOnly(), ArrayStats.empty());
593-
default -> new GenericArray(ctx.dtype(), rowCount,
594-
new MemorySegment[]{output.asReadOnly()}, Array.NO_CHILDREN, ArrayStats.empty());
593+
case I64, U64 -> new LongArray(ctx.dtype(), rowCount, ro, ArrayStats.empty());
594+
case I32, U32 -> new IntArray(ctx.dtype(), rowCount, ro, ArrayStats.empty());
595+
case I16, U16 -> new ShortArray(ctx.dtype(), rowCount, ro, ArrayStats.empty());
596+
case I8, U8 -> new ByteArray(ctx.dtype(), rowCount, ro, ArrayStats.empty());
597+
default -> throw new VortexException(CodecId.FASTLANES_BITPACKED, "unsupported ptype " + ptype);
595598
};
596599
}
597600

core/src/main/java/io/github/dfa1/vortex/encoding/ConstantCodec.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
import io.github.dfa1.vortex.core.ArrayStats;
77
import io.github.dfa1.vortex.core.DType;
88
import io.github.dfa1.vortex.core.PType;
9+
import io.github.dfa1.vortex.core.array.ByteArray;
910
import io.github.dfa1.vortex.core.array.DoubleArray;
10-
import io.github.dfa1.vortex.core.array.GenericArray;
11+
import io.github.dfa1.vortex.core.array.FloatArray;
1112
import io.github.dfa1.vortex.core.array.IntArray;
1213
import io.github.dfa1.vortex.core.array.LongArray;
14+
import io.github.dfa1.vortex.core.array.ShortArray;
1315
import io.github.dfa1.vortex.core.array.VarBinArray;
1416
import io.github.dfa1.vortex.core.VortexException;
1517

@@ -98,7 +100,10 @@ public Array decode(DecodeContext ctx) {
98100
case I64, U64 -> new LongArray(ctx.dtype(), n, ro, ArrayStats.empty());
99101
case I32, U32 -> new IntArray(ctx.dtype(), n, ro, ArrayStats.empty());
100102
case F64 -> new DoubleArray(ctx.dtype(), n, ro, ArrayStats.empty());
101-
default -> new GenericArray(ctx.dtype(), n, new MemorySegment[]{ro}, Array.NO_CHILDREN, ArrayStats.empty());
103+
case F32 -> new FloatArray(ctx.dtype(), n, ro, ArrayStats.empty());
104+
case I16, U16 -> new ShortArray(ctx.dtype(), n, ro, ArrayStats.empty());
105+
case I8, U8 -> new ByteArray(ctx.dtype(), n, ro, ArrayStats.empty());
106+
default -> throw new VortexException(CodecId.VORTEX_CONSTANT, "unsupported ptype " + ptype);
102107
};
103108
}
104109

core/src/main/java/io/github/dfa1/vortex/encoding/DeltaCodec.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import io.github.dfa1.vortex.core.ArrayStats;
66
import io.github.dfa1.vortex.core.DType;
77
import io.github.dfa1.vortex.core.PType;
8-
import io.github.dfa1.vortex.core.array.GenericArray;
8+
import io.github.dfa1.vortex.core.array.ByteArray;
99
import io.github.dfa1.vortex.core.array.IntArray;
1010
import io.github.dfa1.vortex.core.array.LongArray;
11+
import io.github.dfa1.vortex.core.array.ShortArray;
1112
import io.github.dfa1.vortex.core.VortexException;
1213

1314
import java.lang.foreign.Arena;
@@ -256,8 +257,9 @@ public Array decode(DecodeContext ctx) {
256257
return switch (ptype) {
257258
case I64, U64 -> new LongArray(ctx.dtype(), rowCount, seg, ArrayStats.empty());
258259
case I32, U32 -> new IntArray(ctx.dtype(), rowCount, seg, ArrayStats.empty());
259-
default -> new GenericArray(ctx.dtype(), rowCount,
260-
new MemorySegment[]{seg}, Array.NO_CHILDREN, ArrayStats.empty());
260+
case I16, U16 -> new ShortArray(ctx.dtype(), rowCount, seg, ArrayStats.empty());
261+
case I8, U8 -> new ByteArray(ctx.dtype(), rowCount, seg, ArrayStats.empty());
262+
default -> throw new VortexException(CodecId.FASTLANES_DELTA, "unsupported ptype " + ptype);
261263
};
262264
}
263265
}

0 commit comments

Comments
 (0)