From 2a89a9cc8c1787df3279fc822120ecab793938a4 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 23 Jul 2026 15:21:00 +0200 Subject: [PATCH] Generate the TNumber value splits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value split and value-time split of tint and tfloat return the temporal fragments alongside a per-fragment value-bin out-parameter (and, for the value-time split, a parallel time-bin out-parameter), the same split shape as the time split with the bin dimension carrying a base value rather than a timestamp. Add the value bin dimension to the split-key map: an int bin array reads the number component through getInt, a double bin array through getDouble. The split fold already walks its bin dimensions in order, so the one-dimensional value split and the two-dimensional value-time split both fold into records — (number, fragment) and (number, time, fragment) — with no further change. A parity test checks the int value split and the float value-time split against direct GeneratedFunctions calls. --- .../src/main/java/ObjectLayerGenerator.java | 8 ++- .../GeneratedConcreteNumberParityTest.java | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/codegen/src/main/java/ObjectLayerGenerator.java b/codegen/src/main/java/ObjectLayerGenerator.java index 9c5a31144..fbbe3f129 100644 --- a/codegen/src/main/java/ObjectLayerGenerator.java +++ b/codegen/src/main/java/ObjectLayerGenerator.java @@ -692,15 +692,17 @@ private static String cleanType(String c) { * model that dimension. A bin out-parameter is a pointer to an array of the bin-start values * ({@code T **}); the reader dereferences the array pointer ({@code $arr}) and reads element * {@code _i}. This slice supports the time dimension (a {@code TimestampTz} array → an - * {@code OffsetDateTime}, the {@code time} column of the SQL composite); the value dimension of the - * numeric subclasses (an {@code int}/{@code double} array → the {@code number} column) and the space - * dimension of the spatial subclasses (a {@code GSERIALIZED} array → the {@code point} column) extend + * {@code OffsetDateTime}, the {@code time} column of the SQL composite) and the value dimension of the + * numeric subclasses (an {@code int}/{@code double} array → the {@code number} column); the space + * dimension of the spatial subclasses (a {@code GSERIALIZED} array → the {@code point} column) extends * this map when those classes are generated. */ private static SplitKey splitKey(String outParamCType) { return switch (outParamCType) { case "TimestampTz **" -> new SplitKey("time", "java.time.OffsetDateTime", "utils.TimestampTzConverter.toOffsetDateTime($arr.getLong((long) _i * Long.BYTES))"); + case "int **" -> new SplitKey("number", "int", "$arr.getInt((long) _i * Integer.BYTES)"); + case "double **" -> new SplitKey("number", "double", "$arr.getDouble((long) _i * Double.BYTES)"); default -> null; }; } diff --git a/jmeos-core/src/test/java/types/temporal/generated/GeneratedConcreteNumberParityTest.java b/jmeos-core/src/test/java/types/temporal/generated/GeneratedConcreteNumberParityTest.java index 4849478f0..2f87dfd71 100644 --- a/jmeos-core/src/test/java/types/temporal/generated/GeneratedConcreteNumberParityTest.java +++ b/jmeos-core/src/test/java/types/temporal/generated/GeneratedConcreteNumberParityTest.java @@ -1,12 +1,19 @@ package types.temporal.generated; import functions.GeneratedFunctions; +import jnr.ffi.Memory; import jnr.ffi.Pointer; +import jnr.ffi.Runtime; import org.junit.jupiter.api.Test; import types.basic.tfloat.TFloatSeq; import types.basic.tint.TIntSeq; import types.temporal.Temporal; import types.temporal.TemporalType; +import utils.ConversionUtils; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -87,4 +94,54 @@ void floatSurfaceMatchesTheLibrary() { assertEquals(GeneratedFunctions.tfloat_out(p, 6), g.out(6)); } + + @Test + void intValueSplitMatchesTheLibrary() { + TIntSeq a = new TIntSeq("[1@2019-09-01, 3@2019-09-02, 5@2019-09-03]"); + Pointer p = a.getInner(); + GeneratedTInt g = genInt(a); + Runtime rt = Runtime.getSystemRuntime(); + + // valueSplit folds the fragment array and the parallel int bins into (number, fragment) records. + Pointer bins = Memory.allocate(rt, Long.BYTES); + Pointer count = Memory.allocate(rt, Integer.BYTES); + Pointer frags = GeneratedFunctions.tint_value_split(p, 2, 0, bins, count); + Pointer binsArr = bins.getPointer(0); + List split = g.valueSplit(2, 0); + + assertEquals(count.getInt(0), split.size()); + for (int i = 0; i < split.size(); i++) { + assertEquals(binsArr.getInt((long) i * Integer.BYTES), split.get(i).number()); + assertEquals(id(frags.getPointer((long) i * Long.BYTES)), id(split.get(i).fragment())); + } + } + + @Test + void floatValueTimeSplitMatchesTheLibrary() { + TFloatSeq a = new TFloatSeq("[1@2019-09-01, 3@2019-09-02, 5@2019-09-03]"); + Pointer p = a.getInner(); + GeneratedTFloat g = genFloat(a); + Runtime rt = Runtime.getSystemRuntime(); + + Duration duration = Duration.ofDays(1); + OffsetDateTime torigin = OffsetDateTime.parse("2019-09-01T00:00:00Z"); + + // valueTimeSplit is 2-D: the fragment array zips with a value-bin array and a time-bin array. + Pointer vbins = Memory.allocate(rt, Long.BYTES); + Pointer tbins = Memory.allocate(rt, Long.BYTES); + Pointer count = Memory.allocate(rt, Integer.BYTES); + Pointer frags = GeneratedFunctions.tfloat_value_time_split(p, 2.0, + ConversionUtils.timedelta_to_interval(duration), 0.0, torigin, vbins, tbins, count); + Pointer vbinsArr = vbins.getPointer(0); + Pointer tbinsArr = tbins.getPointer(0); + List split = g.valueTimeSplit(2.0, duration, 0.0, torigin); + + assertEquals(count.getInt(0), split.size()); + for (int i = 0; i < split.size(); i++) { + assertEquals(vbinsArr.getDouble((long) i * Double.BYTES), split.get(i).number()); + assertEquals(utils.TimestampTzConverter.toOffsetDateTime(tbinsArr.getLong((long) i * Long.BYTES)), + split.get(i).time()); + assertEquals(id(frags.getPointer((long) i * Long.BYTES)), id(split.get(i).fragment())); + } + } }