|
6 | 6 | import io.github.dfa1.vortex.reader.array.BoolArray; |
7 | 7 | import io.github.dfa1.vortex.reader.array.ByteArray; |
8 | 8 | import io.github.dfa1.vortex.reader.array.ChunkedByteArray; |
| 9 | +import io.github.dfa1.vortex.reader.array.DictDoubleArray; |
9 | 10 | import io.github.dfa1.vortex.reader.array.DictLongArray; |
10 | 11 | import io.github.dfa1.vortex.reader.array.MaskedArray; |
11 | 12 | import io.github.dfa1.vortex.reader.array.MaterializedBoolArray; |
@@ -303,6 +304,26 @@ void dictFilterFloatAggregateBoxesFloatExtremes() { |
303 | 304 | assertThat(result.max()).isInstanceOf(Float.class).isEqualTo(4.0f); |
304 | 305 | } |
305 | 306 |
|
| 307 | + @Test |
| 308 | + void dictDoubleFilterDrivesTheLane() { |
| 309 | + // Given a double-valued dict filter (a DictDoubleArray pool) — the aggregate lane's |
| 310 | + // double-domain pool lowering, which the long-dict randomized sweep never reaches |
| 311 | + Array filter = dictDoubleColumn(new double[]{1.5, 2.5}, new int[]{1, 0, 1, 1}); |
| 312 | + Chunk chunk = chunk(4, Map.of( |
| 313 | + "f0", filter, |
| 314 | + "v", longArray(new Reference(new long[]{1, 2, 4, 8}, null), false))); |
| 315 | + |
| 316 | + // When the kernel folds over the rows where the dict value is > 2.0 (code 1: rows 0, 2, 3) |
| 317 | + FilteredAggregate result = Compute.filteredAggregate(chunk, RowFilter.gt("f0", 2.0), "v"); |
| 318 | + |
| 319 | + // Then the selected rows fold exactly as the value-level evaluation would |
| 320 | + assertThat(result.selectedRows()).isEqualTo(3L); |
| 321 | + assertThat(result.aggNonNullCount()).isEqualTo(3L); |
| 322 | + assertThat(result.sum()).isEqualTo(1L + 4L + 8L); |
| 323 | + assertThat(result.min()).isEqualTo(1L); |
| 324 | + assertThat(result.max()).isEqualTo(8L); |
| 325 | + } |
| 326 | + |
306 | 327 | @Test |
307 | 328 | void andOfOneDictLeafUnwrapsToTheLane() { |
308 | 329 | // Given a one-element AND around a dict comparison leaf — RowFilter.and(...) wraps a single |
@@ -495,6 +516,16 @@ private static Array dictColumn(long[] pool, int[] codes) { |
495 | 516 | return DictLongArray.of(DType.I64, codes.length, poolArray, byteArray(codes, 0, codes.length)); |
496 | 517 | } |
497 | 518 |
|
| 519 | + /// Builds a flat-coded double-valued dict column for the double-domain dict-lane case. |
| 520 | + private static Array dictDoubleColumn(double[] pool, int[] codes) { |
| 521 | + MemorySegment poolSeg = ARENA.allocate(Math.max(8L, pool.length * 8L), 8); |
| 522 | + for (int i = 0; i < pool.length; i++) { |
| 523 | + poolSeg.setAtIndex(PTypeIO.LE_DOUBLE, i, pool[i]); |
| 524 | + } |
| 525 | + MaterializedDoubleArray poolArray = new MaterializedDoubleArray(DType.F64, pool.length, poolSeg); |
| 526 | + return DictDoubleArray.of(DType.F64, codes.length, poolArray, byteArray(codes, 0, codes.length)); |
| 527 | + } |
| 528 | + |
498 | 529 | private static MaterializedByteArray byteArray(int[] codes, int from, int to) { |
499 | 530 | MemorySegment segment = ARENA.allocate(Math.max(1L, (long) to - from)); |
500 | 531 | for (int i = from; i < to; i++) { |
|
0 commit comments