|
20 | 20 | import io.github.dfa1.vortex.reader.array.DictIntArray; |
21 | 21 | import io.github.dfa1.vortex.reader.array.DictLongArray; |
22 | 22 | import io.github.dfa1.vortex.reader.array.DoubleArray; |
23 | | -import io.github.dfa1.vortex.reader.array.EmptyArray; |
24 | 23 | import io.github.dfa1.vortex.reader.array.FloatArray; |
25 | | -import io.github.dfa1.vortex.reader.array.GenericArray; |
26 | 24 | import io.github.dfa1.vortex.reader.array.IntArray; |
27 | | -import io.github.dfa1.vortex.reader.array.LazyConstantBoolArray; |
28 | | -import io.github.dfa1.vortex.reader.array.LazyConstantByteArray; |
29 | | -import io.github.dfa1.vortex.reader.array.LazyConstantDoubleArray; |
30 | | -import io.github.dfa1.vortex.reader.array.LazyConstantFloatArray; |
31 | | -import io.github.dfa1.vortex.reader.array.LazyConstantIntArray; |
32 | | -import io.github.dfa1.vortex.reader.array.LazyConstantLongArray; |
33 | | -import io.github.dfa1.vortex.reader.array.LazyConstantShortArray; |
34 | | -import io.github.dfa1.vortex.reader.array.LazyConstantDecimalArray; |
35 | | -import io.github.dfa1.vortex.reader.array.LazyDecimalArray; |
36 | | -import io.github.dfa1.vortex.reader.array.LazyDecimalBytePartsArray; |
37 | | -import io.github.dfa1.vortex.reader.array.LazyRunEndBoolArray; |
38 | | -import io.github.dfa1.vortex.reader.array.LazySparseBoolArray; |
39 | 25 | import io.github.dfa1.vortex.reader.array.LongArray; |
40 | 26 | import io.github.dfa1.vortex.reader.array.MaskedArray; |
41 | | -import io.github.dfa1.vortex.reader.array.MaterializedBoolArray; |
42 | | -import io.github.dfa1.vortex.reader.array.MaterializedByteArray; |
43 | | -import io.github.dfa1.vortex.reader.array.MaterializedDoubleArray; |
44 | | -import io.github.dfa1.vortex.reader.array.MaterializedFloatArray; |
45 | | -import io.github.dfa1.vortex.reader.array.MaterializedIntArray; |
46 | | -import io.github.dfa1.vortex.reader.array.MaterializedLongArray; |
47 | | -import io.github.dfa1.vortex.reader.array.MaterializedShortArray; |
48 | 27 | import io.github.dfa1.vortex.reader.array.OffsetBoolArray; |
49 | 28 | import io.github.dfa1.vortex.reader.array.OffsetByteArray; |
50 | 29 | import io.github.dfa1.vortex.reader.array.OffsetDoubleArray; |
51 | 30 | import io.github.dfa1.vortex.reader.array.OffsetFloatArray; |
52 | 31 | import io.github.dfa1.vortex.reader.array.OffsetIntArray; |
53 | 32 | import io.github.dfa1.vortex.reader.array.OffsetLongArray; |
54 | 33 | import io.github.dfa1.vortex.reader.array.OffsetShortArray; |
55 | | -import io.github.dfa1.vortex.reader.array.NullArray; |
56 | 34 | import io.github.dfa1.vortex.reader.array.ShortArray; |
57 | 35 | import io.github.dfa1.vortex.reader.array.StructArray; |
58 | 36 | import io.github.dfa1.vortex.reader.array.VarBinArray; |
@@ -279,150 +257,14 @@ private static long readUnsigned(MemorySegment seg, long idx, PType ptype) { |
279 | 257 |
|
280 | 258 | // ── Zone-map pruning ────────────────────────────────────────────────────── |
281 | 259 |
|
282 | | - private static Map<String, Array> truncateColumns(Map<String, Array> columns, long rows, |
283 | | - SegmentAllocator arena) { |
| 260 | + private static Map<String, Array> truncateColumns(Map<String, Array> columns, long rows) { |
284 | 261 | var result = new LinkedHashMap<String, Array>(columns.size()); |
285 | 262 | for (var entry : columns.entrySet()) { |
286 | | - result.put(entry.getKey(), truncateArray(entry.getValue(), rows, arena)); |
| 263 | + result.put(entry.getKey(), Array.truncated(entry.getValue(), rows)); |
287 | 264 | } |
288 | 265 | return Map.copyOf(result); |
289 | 266 | } |
290 | 267 |
|
291 | | - private static Array truncateArray(Array arr, long rows, SegmentAllocator arena) { |
292 | | - if (arr.length() <= rows) { |
293 | | - return arr; |
294 | | - } |
295 | | - // Chunked* cases must precede the LongArray/IntArray/etc catch-alls below — a |
296 | | - // ChunkedLongArray IS a LongArray, but slicing it via ArraySegments.of would |
297 | | - // materialise the entire column before slicing (defeating the zero-copy win |
298 | | - // we just added). Instead, keep the prefix children intact and recursively |
299 | | - // truncate the boundary child. |
300 | | - return switch (arr) { |
301 | | - case ChunkedLongArray a -> truncateChunkedLong(a, rows, arena); |
302 | | - case ChunkedIntArray a -> truncateChunkedInt(a, rows, arena); |
303 | | - case ChunkedDoubleArray a -> truncateChunkedDouble(a, rows, arena); |
304 | | - case ChunkedFloatArray a -> truncateChunkedFloat(a, rows, arena); |
305 | | - case ChunkedShortArray a -> truncateChunkedShort(a, rows, arena); |
306 | | - case ChunkedByteArray a -> truncateChunkedByte(a, rows, arena); |
307 | | - case ChunkedBoolArray a -> truncateChunkedBool(a, rows, arena); |
308 | | - // Dict* cases must precede the LongArray/etc catch-alls below: a DictLongArray |
309 | | - // IS a LongArray, but the catch-all materialises via ArraySegments.of which |
310 | | - // would scatter the entire column to truncate. Instead keep the values |
311 | | - // dictionary intact and just truncate the codes — codes are a primitive Array |
312 | | - // that recursively flows through this same switch. |
313 | | - case DictLongArray a -> |
314 | | - DictLongArray.of(a.dtype(), rows, a.values(), truncateArray(a.codes(), rows, arena)); |
315 | | - case DictIntArray a -> |
316 | | - DictIntArray.of(a.dtype(), rows, a.values(), truncateArray(a.codes(), rows, arena)); |
317 | | - case DictDoubleArray a -> |
318 | | - DictDoubleArray.of(a.dtype(), rows, a.values(), truncateArray(a.codes(), rows, arena)); |
319 | | - case DictFloatArray a -> |
320 | | - DictFloatArray.of(a.dtype(), rows, a.values(), truncateArray(a.codes(), rows, arena)); |
321 | | - // LazyConstant* cases must precede the LongArray / IntArray / etc catch-alls: |
322 | | - // each LazyConstantXxxArray IS a typed Array, but the catch-all would |
323 | | - // materialise a length-sized buffer just to slice it. Truncating a constant |
324 | | - // array is a no-buffer length swap. |
325 | | - case LazyConstantLongArray a -> new LazyConstantLongArray(a.dtype(), rows, a.value()); |
326 | | - case LazyConstantIntArray a -> new LazyConstantIntArray(a.dtype(), rows, a.value()); |
327 | | - case LazyConstantDoubleArray a -> new LazyConstantDoubleArray(a.dtype(), rows, a.value()); |
328 | | - case LazyConstantFloatArray a -> new LazyConstantFloatArray(a.dtype(), rows, a.value()); |
329 | | - case LazyConstantShortArray a -> new LazyConstantShortArray(a.dtype(), rows, a.value()); |
330 | | - case LazyConstantByteArray a -> new LazyConstantByteArray(a.dtype(), rows, a.value()); |
331 | | - case LazyConstantBoolArray a -> new LazyConstantBoolArray(a.dtype(), rows, a.value()); |
332 | | - case LongArray a -> |
333 | | - new MaterializedLongArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, rows * Long.BYTES)); |
334 | | - case IntArray a -> |
335 | | - new MaterializedIntArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, rows * Integer.BYTES)); |
336 | | - case DoubleArray a -> |
337 | | - new MaterializedDoubleArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, rows * Double.BYTES)); |
338 | | - case FloatArray a -> |
339 | | - new MaterializedFloatArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, rows * Float.BYTES)); |
340 | | - case ShortArray a -> |
341 | | - new MaterializedShortArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, rows * Short.BYTES)); |
342 | | - case ByteArray a -> new MaterializedByteArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, rows)); |
343 | | - case LazyRunEndBoolArray a -> |
344 | | - new LazyRunEndBoolArray(a.dtype(), rows, a.values(), a.runEnds(), a.offset()); |
345 | | - case LazySparseBoolArray a -> |
346 | | - new LazySparseBoolArray(a.dtype(), rows, a.fillValue(), a.patchValues(), a.patchIndices(), a.offset()); |
347 | | - case BoolArray a -> |
348 | | - new MaterializedBoolArray(a.dtype(), rows, ArraySegments.of(a, arena).asSlice(0, (rows + 7) / 8)); |
349 | | - case NullArray a -> new NullArray(a.dtype(), rows); |
350 | | - case VarBinArray a -> a.truncate(rows); |
351 | | - case MaskedArray a -> { |
352 | | - Array truncChild = truncateArray(a.inner(), rows, arena); |
353 | | - BoolArray v = a.validity(); |
354 | | - BoolArray truncValidity = (v != null) ? (BoolArray) truncateArray(v, rows, arena) : null; |
355 | | - yield new MaskedArray(truncChild, truncValidity); |
356 | | - } |
357 | | - case EmptyArray a -> a; |
358 | | - case GenericArray a -> a.withLength(rows); |
359 | | - case LazyDecimalArray a -> |
360 | | - new LazyDecimalArray(a.dtype(), rows, a.buf().asSlice(0, rows * (long) a.byteWidth()), a.byteWidth()); |
361 | | - case LazyDecimalBytePartsArray a -> |
362 | | - new LazyDecimalBytePartsArray(a.dtype(), rows, truncateArray(a.msp(), rows, arena)); |
363 | | - case LazyConstantDecimalArray a -> |
364 | | - new LazyConstantDecimalArray(a.dtype(), rows, a.value(), a.byteWidth()); |
365 | | - default -> |
366 | | - throw new VortexException("limit: truncation not supported for " + arr.getClass().getSimpleName()); |
367 | | - }; |
368 | | - } |
369 | | - |
370 | | - /// Truncates a `ChunkedXxxArray` by keeping full children that fit within |
371 | | - /// `rows` and recursively truncating the boundary child. Avoids the |
372 | | - /// full-column materialisation that the {@link LongArray}/{@link IntArray}/etc. |
373 | | - /// catch-all cases would trigger via {@link ArraySegments#of(Array, SegmentAllocator)}. |
374 | | - private static Array truncateChunkedLong(ChunkedLongArray arr, long rows, SegmentAllocator arena) { |
375 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
376 | | - return ChunkedLongArray.of(arr.dtype(), rows, kept); |
377 | | - } |
378 | | - |
379 | | - private static Array truncateChunkedInt(ChunkedIntArray arr, long rows, SegmentAllocator arena) { |
380 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
381 | | - return ChunkedIntArray.of(arr.dtype(), rows, kept); |
382 | | - } |
383 | | - |
384 | | - private static Array truncateChunkedDouble(ChunkedDoubleArray arr, long rows, SegmentAllocator arena) { |
385 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
386 | | - return ChunkedDoubleArray.of(arr.dtype(), rows, kept); |
387 | | - } |
388 | | - |
389 | | - private static Array truncateChunkedFloat(ChunkedFloatArray arr, long rows, SegmentAllocator arena) { |
390 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
391 | | - return ChunkedFloatArray.of(arr.dtype(), rows, kept); |
392 | | - } |
393 | | - |
394 | | - private static Array truncateChunkedShort(ChunkedShortArray arr, long rows, SegmentAllocator arena) { |
395 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
396 | | - return ChunkedShortArray.of(arr.dtype(), rows, kept); |
397 | | - } |
398 | | - |
399 | | - private static Array truncateChunkedByte(ChunkedByteArray arr, long rows, SegmentAllocator arena) { |
400 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
401 | | - return ChunkedByteArray.of(arr.dtype(), rows, kept); |
402 | | - } |
403 | | - |
404 | | - private static Array truncateChunkedBool(ChunkedBoolArray arr, long rows, SegmentAllocator arena) { |
405 | | - List<Array> kept = collectTruncatedChildren(arr.children(), arr.offsets(), rows, arena); |
406 | | - return ChunkedBoolArray.of(arr.dtype(), rows, kept); |
407 | | - } |
408 | | - |
409 | | - private static List<Array> collectTruncatedChildren(Array[] children, long[] offsets, |
410 | | - long rows, SegmentAllocator arena) { |
411 | | - var kept = new ArrayList<Array>(children.length); |
412 | | - for (int i = 0; i < children.length; i++) { |
413 | | - long start = offsets[i]; |
414 | | - long end = offsets[i + 1]; |
415 | | - if (start >= rows) { |
416 | | - break; |
417 | | - } |
418 | | - if (end <= rows) { |
419 | | - kept.add(children[i]); |
420 | | - } else { |
421 | | - kept.add(truncateArray(children[i], rows - start, arena)); |
422 | | - } |
423 | | - } |
424 | | - return kept; |
425 | | - } |
426 | 268 |
|
427 | 269 | @Override |
428 | 270 | public boolean hasNext() { |
@@ -470,7 +312,7 @@ public Chunk next() { |
470 | 312 | try { |
471 | 313 | Map<String, Array> columns = buildColumnMap(spec, arena); |
472 | 314 | if (chunkRows < spec.rowCount()) { |
473 | | - columns = truncateColumns(columns, chunkRows, arena); |
| 315 | + columns = truncateColumns(columns, chunkRows); |
474 | 316 | } |
475 | 317 | rowsReturned += chunkRows; |
476 | 318 | Map<String, DType> chunkDtypes = new java.util.LinkedHashMap<>(); |
|
0 commit comments