From 242d3839750704c30deef39017a5cab812ba4439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Zim=C3=A1nyi?= Date: Wed, 2 Sep 2026 23:44:09 +0200 Subject: [PATCH 1/2] Build a temporal value from an array of temporal values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MEOS reads an array of its own values through a pointer to the first element and a count — `tsequence_make`, `tsequenceset_make`, `temporal_merge_array` and the trgeometry twin of each. The object layer takes that as one C# array: the wrappers' pointers are gathered into an `IntPtr[]` and pinned across the call. The pin lasts exactly that long because the array is the caller's throughout — `tsequence_make_free` is the twin that takes ownership, and it does so by calling `tsequence_make` and then `pfree_array` on the array it passed, which is sound only if `tsequence_make` neither frees nor retains it. Eight constructors reach the object layer that way, 611 methods against 607. The length parameter never appears in the C# signature, so it cannot disagree with the array. That also settles which parameter is an array at all: the length is named `count`, while a parameter named `n` is the index of the `*_n` accessors, whose pointer is the receiver and no array — reading `n` as a length turns `trgeometry_instant_n(temp, n)` into a call passing the receiver's own length. Three tests: a sequence made of three instants reads back as the text of all three, merging two sequences answers four instants across two sequences, and an empty array reaches MEOS as the invalid argument it is. --- MEOS.NET.Tests/CountedArrayTests.cs | 54 +++++++++++++++++ MEOS.NET/Types/BigIntSet.g.cs | 2 + MEOS.NET/Types/BigIntSpan.g.cs | 2 + MEOS.NET/Types/BigIntSpanSet.g.cs | 2 + MEOS.NET/Types/Box.g.cs | 2 + MEOS.NET/Types/CbufferSet.g.cs | 2 + MEOS.NET/Types/Collection.g.cs | 2 + MEOS.NET/Types/DateSet.g.cs | 2 + MEOS.NET/Types/DateSpan.g.cs | 2 + MEOS.NET/Types/DateSpanSet.g.cs | 2 + MEOS.NET/Types/FloatSet.g.cs | 2 + MEOS.NET/Types/FloatSpan.g.cs | 2 + MEOS.NET/Types/FloatSpanSet.g.cs | 2 + MEOS.NET/Types/GeogSet.g.cs | 2 + MEOS.NET/Types/GeomSet.g.cs | 2 + MEOS.NET/Types/IntSet.g.cs | 2 + MEOS.NET/Types/IntSpan.g.cs | 2 + MEOS.NET/Types/IntSpanSet.g.cs | 2 + MEOS.NET/Types/NpointSet.g.cs | 2 + MEOS.NET/Types/PoseSet.g.cs | 2 + MEOS.NET/Types/STBox.g.cs | 2 + MEOS.NET/Types/Set.g.cs | 2 + MEOS.NET/Types/Span.g.cs | 2 + MEOS.NET/Types/SpanSet.g.cs | 2 + MEOS.NET/Types/TAlpha.g.cs | 2 + MEOS.NET/Types/TBigint.g.cs | 2 + MEOS.NET/Types/TBigintInst.g.cs | 2 + MEOS.NET/Types/TBigintSeq.g.cs | 2 + MEOS.NET/Types/TBigintSeqSet.g.cs | 2 + MEOS.NET/Types/TBool.g.cs | 2 + MEOS.NET/Types/TBoolInst.g.cs | 2 + MEOS.NET/Types/TBoolSeq.g.cs | 2 + MEOS.NET/Types/TBoolSeqSet.g.cs | 2 + MEOS.NET/Types/TBox.g.cs | 2 + MEOS.NET/Types/TCbuffer.g.cs | 2 + MEOS.NET/Types/TCbufferInst.g.cs | 2 + MEOS.NET/Types/TCbufferSeq.g.cs | 2 + MEOS.NET/Types/TCbufferSeqSet.g.cs | 2 + MEOS.NET/Types/TFloat.g.cs | 2 + MEOS.NET/Types/TFloatInst.g.cs | 2 + MEOS.NET/Types/TFloatSeq.g.cs | 2 + MEOS.NET/Types/TFloatSeqSet.g.cs | 2 + MEOS.NET/Types/TGeo.g.cs | 2 + MEOS.NET/Types/TGeogPoint.g.cs | 2 + MEOS.NET/Types/TGeogPointInst.g.cs | 2 + MEOS.NET/Types/TGeogPointSeq.g.cs | 2 + MEOS.NET/Types/TGeogPointSeqSet.g.cs | 2 + MEOS.NET/Types/TGeography.g.cs | 2 + MEOS.NET/Types/TGeographyInst.g.cs | 2 + MEOS.NET/Types/TGeographySeq.g.cs | 2 + MEOS.NET/Types/TGeographySeqSet.g.cs | 2 + MEOS.NET/Types/TGeomPoint.g.cs | 2 + MEOS.NET/Types/TGeomPointInst.g.cs | 2 + MEOS.NET/Types/TGeomPointSeq.g.cs | 2 + MEOS.NET/Types/TGeomPointSeqSet.g.cs | 2 + MEOS.NET/Types/TGeometry.g.cs | 2 + MEOS.NET/Types/TGeometryInst.g.cs | 2 + MEOS.NET/Types/TGeometrySeq.g.cs | 2 + MEOS.NET/Types/TGeometrySeqSet.g.cs | 2 + MEOS.NET/Types/TInstant.g.cs | 2 + MEOS.NET/Types/TInt.g.cs | 2 + MEOS.NET/Types/TIntInst.g.cs | 2 + MEOS.NET/Types/TIntSeq.g.cs | 2 + MEOS.NET/Types/TIntSeqSet.g.cs | 2 + MEOS.NET/Types/TJsonb.g.cs | 2 + MEOS.NET/Types/TJsonbInst.g.cs | 2 + MEOS.NET/Types/TJsonbSeq.g.cs | 2 + MEOS.NET/Types/TJsonbSeqSet.g.cs | 2 + MEOS.NET/Types/TNpoint.g.cs | 2 + MEOS.NET/Types/TNpointInst.g.cs | 2 + MEOS.NET/Types/TNpointSeq.g.cs | 2 + MEOS.NET/Types/TNpointSeqSet.g.cs | 2 + MEOS.NET/Types/TNumber.g.cs | 2 + MEOS.NET/Types/TPoint.g.cs | 2 + MEOS.NET/Types/TPose.g.cs | 2 + MEOS.NET/Types/TPoseInst.g.cs | 2 + MEOS.NET/Types/TPoseSeq.g.cs | 2 + MEOS.NET/Types/TPoseSeqSet.g.cs | 2 + MEOS.NET/Types/TRGeometry.g.cs | 21 +++++++ MEOS.NET/Types/TRGeometryInst.g.cs | 2 + MEOS.NET/Types/TRGeometrySeq.g.cs | 2 + MEOS.NET/Types/TRGeometrySeqSet.g.cs | 2 + MEOS.NET/Types/TSequence.g.cs | 21 +++++++ MEOS.NET/Types/TSequenceSet.g.cs | 21 +++++++ MEOS.NET/Types/TSpatial.g.cs | 2 + MEOS.NET/Types/TText.g.cs | 2 + MEOS.NET/Types/TTextInst.g.cs | 2 + MEOS.NET/Types/TTextSeq.g.cs | 2 + MEOS.NET/Types/TTextSeqSet.g.cs | 2 + MEOS.NET/Types/Temporal.g.cs | 21 +++++++ MEOS.NET/Types/TextSet.g.cs | 2 + MEOS.NET/Types/TsTzSet.g.cs | 2 + MEOS.NET/Types/TsTzSpan.g.cs | 2 + MEOS.NET/Types/TsTzSpanSet.g.cs | 2 + tools/objectgen.py | 88 ++++++++++++++++++++++++---- 95 files changed, 392 insertions(+), 12 deletions(-) create mode 100644 MEOS.NET.Tests/CountedArrayTests.cs diff --git a/MEOS.NET.Tests/CountedArrayTests.cs b/MEOS.NET.Tests/CountedArrayTests.cs new file mode 100644 index 0000000..bc9eeac --- /dev/null +++ b/MEOS.NET.Tests/CountedArrayTests.cs @@ -0,0 +1,54 @@ +using MEOS.NET.Enums; +using MEOS.NET.Types; + +namespace MEOS.NET.Tests +{ + /// + /// MEOS reads an array of its own values through a pointer to the first + /// element and a count, so a method taking one takes a C# array and answers + /// its length to MEOS. + /// + [TestClass] + public class CountedArrayTests : MeosTest + { + [TestMethod] + public void ASequenceIsMadeOfItsInstants() + { + Temporal[] instants = + [ + TFloat.In("25.0@2024-12-06")!, + TFloat.In("27.0@2024-12-07")!, + TFloat.In("30.0@2024-12-09")!, + ]; + + Temporal sequence = TSequence.Make(instants, true, true, InterpType.Linear, true)!; + + Assert.AreEqual(3, sequence.NumInstants()); + Assert.AreEqual( + "[25@2024-12-06 00:00:00+00, 27@2024-12-07 00:00:00+00, 30@2024-12-09 00:00:00+00]", + sequence.ToString()); + } + + [TestMethod] + public void MergingAnArrayOfTemporalValuesJoinsThem() + { + Temporal[] parts = + [ + TFloat.In("[25.0@2024-12-06, 27.0@2024-12-07]")!, + TFloat.In("[30.0@2024-12-09, 32.0@2024-12-10]")!, + ]; + + Temporal merged = Temporal.MergeArray(parts)!; + + Assert.AreEqual(4, merged.NumInstants()); + Assert.AreEqual(2, merged.NumSequences()); + } + + [TestMethod] + public void AnEmptyArrayIsARequestMeosRefuses() + { + Assert.ThrowsException( + () => TSequence.Make([], true, true, InterpType.Linear, true)); + } + } +} diff --git a/MEOS.NET/Types/BigIntSet.g.cs b/MEOS.NET/Types/BigIntSet.g.cs index c2cbf30..493945d 100644 --- a/MEOS.NET/Types/BigIntSet.g.cs +++ b/MEOS.NET/Types/BigIntSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/BigIntSpan.g.cs b/MEOS.NET/Types/BigIntSpan.g.cs index 16bf168..bc3c38e 100644 --- a/MEOS.NET/Types/BigIntSpan.g.cs +++ b/MEOS.NET/Types/BigIntSpan.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/BigIntSpanSet.g.cs b/MEOS.NET/Types/BigIntSpanSet.g.cs index 50aa718..73c6e84 100644 --- a/MEOS.NET/Types/BigIntSpanSet.g.cs +++ b/MEOS.NET/Types/BigIntSpanSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/Box.g.cs b/MEOS.NET/Types/Box.g.cs index cd06e96..4147bb6 100644 --- a/MEOS.NET/Types/Box.g.cs +++ b/MEOS.NET/Types/Box.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/CbufferSet.g.cs b/MEOS.NET/Types/CbufferSet.g.cs index 52cf06f..755bbbe 100644 --- a/MEOS.NET/Types/CbufferSet.g.cs +++ b/MEOS.NET/Types/CbufferSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/Collection.g.cs b/MEOS.NET/Types/Collection.g.cs index 6b65e5b..7ffd7cc 100644 --- a/MEOS.NET/Types/Collection.g.cs +++ b/MEOS.NET/Types/Collection.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/DateSet.g.cs b/MEOS.NET/Types/DateSet.g.cs index 81b5c43..de8374a 100644 --- a/MEOS.NET/Types/DateSet.g.cs +++ b/MEOS.NET/Types/DateSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/DateSpan.g.cs b/MEOS.NET/Types/DateSpan.g.cs index cc95052..76d299f 100644 --- a/MEOS.NET/Types/DateSpan.g.cs +++ b/MEOS.NET/Types/DateSpan.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/DateSpanSet.g.cs b/MEOS.NET/Types/DateSpanSet.g.cs index 7b671a2..296627d 100644 --- a/MEOS.NET/Types/DateSpanSet.g.cs +++ b/MEOS.NET/Types/DateSpanSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/FloatSet.g.cs b/MEOS.NET/Types/FloatSet.g.cs index be1b2fa..e2dc05e 100644 --- a/MEOS.NET/Types/FloatSet.g.cs +++ b/MEOS.NET/Types/FloatSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/FloatSpan.g.cs b/MEOS.NET/Types/FloatSpan.g.cs index 75fcf5a..bba4ef0 100644 --- a/MEOS.NET/Types/FloatSpan.g.cs +++ b/MEOS.NET/Types/FloatSpan.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/FloatSpanSet.g.cs b/MEOS.NET/Types/FloatSpanSet.g.cs index 528ef1f..ea65d63 100644 --- a/MEOS.NET/Types/FloatSpanSet.g.cs +++ b/MEOS.NET/Types/FloatSpanSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/GeogSet.g.cs b/MEOS.NET/Types/GeogSet.g.cs index e37f3fe..107f2ca 100644 --- a/MEOS.NET/Types/GeogSet.g.cs +++ b/MEOS.NET/Types/GeogSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/GeomSet.g.cs b/MEOS.NET/Types/GeomSet.g.cs index 6f92b60..f091385 100644 --- a/MEOS.NET/Types/GeomSet.g.cs +++ b/MEOS.NET/Types/GeomSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/IntSet.g.cs b/MEOS.NET/Types/IntSet.g.cs index 296ffd7..eada4ca 100644 --- a/MEOS.NET/Types/IntSet.g.cs +++ b/MEOS.NET/Types/IntSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/IntSpan.g.cs b/MEOS.NET/Types/IntSpan.g.cs index d5682c2..13d26cf 100644 --- a/MEOS.NET/Types/IntSpan.g.cs +++ b/MEOS.NET/Types/IntSpan.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/IntSpanSet.g.cs b/MEOS.NET/Types/IntSpanSet.g.cs index 25421a4..df3fbb2 100644 --- a/MEOS.NET/Types/IntSpanSet.g.cs +++ b/MEOS.NET/Types/IntSpanSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/NpointSet.g.cs b/MEOS.NET/Types/NpointSet.g.cs index cc40491..74516e7 100644 --- a/MEOS.NET/Types/NpointSet.g.cs +++ b/MEOS.NET/Types/NpointSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/PoseSet.g.cs b/MEOS.NET/Types/PoseSet.g.cs index c11b9fc..43edda2 100644 --- a/MEOS.NET/Types/PoseSet.g.cs +++ b/MEOS.NET/Types/PoseSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/STBox.g.cs b/MEOS.NET/Types/STBox.g.cs index 1364163..fff3d92 100644 --- a/MEOS.NET/Types/STBox.g.cs +++ b/MEOS.NET/Types/STBox.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/Set.g.cs b/MEOS.NET/Types/Set.g.cs index 4591a62..c8b16ae 100644 --- a/MEOS.NET/Types/Set.g.cs +++ b/MEOS.NET/Types/Set.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/Span.g.cs b/MEOS.NET/Types/Span.g.cs index 4d1d016..1199e83 100644 --- a/MEOS.NET/Types/Span.g.cs +++ b/MEOS.NET/Types/Span.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/SpanSet.g.cs b/MEOS.NET/Types/SpanSet.g.cs index 0223c92..b5ed634 100644 --- a/MEOS.NET/Types/SpanSet.g.cs +++ b/MEOS.NET/Types/SpanSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TAlpha.g.cs b/MEOS.NET/Types/TAlpha.g.cs index c87c5e8..a75e539 100644 --- a/MEOS.NET/Types/TAlpha.g.cs +++ b/MEOS.NET/Types/TAlpha.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBigint.g.cs b/MEOS.NET/Types/TBigint.g.cs index a042297..2018749 100644 --- a/MEOS.NET/Types/TBigint.g.cs +++ b/MEOS.NET/Types/TBigint.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBigintInst.g.cs b/MEOS.NET/Types/TBigintInst.g.cs index 53f7416..402640c 100644 --- a/MEOS.NET/Types/TBigintInst.g.cs +++ b/MEOS.NET/Types/TBigintInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBigintSeq.g.cs b/MEOS.NET/Types/TBigintSeq.g.cs index eb92b2b..0c8c5bc 100644 --- a/MEOS.NET/Types/TBigintSeq.g.cs +++ b/MEOS.NET/Types/TBigintSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBigintSeqSet.g.cs b/MEOS.NET/Types/TBigintSeqSet.g.cs index 1c0a8a8..d5f271f 100644 --- a/MEOS.NET/Types/TBigintSeqSet.g.cs +++ b/MEOS.NET/Types/TBigintSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBool.g.cs b/MEOS.NET/Types/TBool.g.cs index 64d2b27..fc5bd1d 100644 --- a/MEOS.NET/Types/TBool.g.cs +++ b/MEOS.NET/Types/TBool.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBoolInst.g.cs b/MEOS.NET/Types/TBoolInst.g.cs index 3a14e5a..3f7d07c 100644 --- a/MEOS.NET/Types/TBoolInst.g.cs +++ b/MEOS.NET/Types/TBoolInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBoolSeq.g.cs b/MEOS.NET/Types/TBoolSeq.g.cs index dcc7129..c3d0456 100644 --- a/MEOS.NET/Types/TBoolSeq.g.cs +++ b/MEOS.NET/Types/TBoolSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBoolSeqSet.g.cs b/MEOS.NET/Types/TBoolSeqSet.g.cs index 73c8520..22dabc6 100644 --- a/MEOS.NET/Types/TBoolSeqSet.g.cs +++ b/MEOS.NET/Types/TBoolSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TBox.g.cs b/MEOS.NET/Types/TBox.g.cs index d7e3c17..dd855a3 100644 --- a/MEOS.NET/Types/TBox.g.cs +++ b/MEOS.NET/Types/TBox.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TCbuffer.g.cs b/MEOS.NET/Types/TCbuffer.g.cs index c5d3404..15fa255 100644 --- a/MEOS.NET/Types/TCbuffer.g.cs +++ b/MEOS.NET/Types/TCbuffer.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TCbufferInst.g.cs b/MEOS.NET/Types/TCbufferInst.g.cs index cfb28fb..f3e4ed3 100644 --- a/MEOS.NET/Types/TCbufferInst.g.cs +++ b/MEOS.NET/Types/TCbufferInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TCbufferSeq.g.cs b/MEOS.NET/Types/TCbufferSeq.g.cs index a914339..1f7edf1 100644 --- a/MEOS.NET/Types/TCbufferSeq.g.cs +++ b/MEOS.NET/Types/TCbufferSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TCbufferSeqSet.g.cs b/MEOS.NET/Types/TCbufferSeqSet.g.cs index e2d07be..bafdc5b 100644 --- a/MEOS.NET/Types/TCbufferSeqSet.g.cs +++ b/MEOS.NET/Types/TCbufferSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TFloat.g.cs b/MEOS.NET/Types/TFloat.g.cs index cf10297..4b2e1a9 100644 --- a/MEOS.NET/Types/TFloat.g.cs +++ b/MEOS.NET/Types/TFloat.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TFloatInst.g.cs b/MEOS.NET/Types/TFloatInst.g.cs index 45e38fd..77ae2b9 100644 --- a/MEOS.NET/Types/TFloatInst.g.cs +++ b/MEOS.NET/Types/TFloatInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TFloatSeq.g.cs b/MEOS.NET/Types/TFloatSeq.g.cs index f0860ca..cbc06cb 100644 --- a/MEOS.NET/Types/TFloatSeq.g.cs +++ b/MEOS.NET/Types/TFloatSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TFloatSeqSet.g.cs b/MEOS.NET/Types/TFloatSeqSet.g.cs index e8b94c9..7abe65f 100644 --- a/MEOS.NET/Types/TFloatSeqSet.g.cs +++ b/MEOS.NET/Types/TFloatSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeo.g.cs b/MEOS.NET/Types/TGeo.g.cs index be2ce7a..b13a2d6 100644 --- a/MEOS.NET/Types/TGeo.g.cs +++ b/MEOS.NET/Types/TGeo.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeogPoint.g.cs b/MEOS.NET/Types/TGeogPoint.g.cs index 7000248..1cc5bdd 100644 --- a/MEOS.NET/Types/TGeogPoint.g.cs +++ b/MEOS.NET/Types/TGeogPoint.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeogPointInst.g.cs b/MEOS.NET/Types/TGeogPointInst.g.cs index e1e6325..bcf02c9 100644 --- a/MEOS.NET/Types/TGeogPointInst.g.cs +++ b/MEOS.NET/Types/TGeogPointInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeogPointSeq.g.cs b/MEOS.NET/Types/TGeogPointSeq.g.cs index eb4f4a7..099af6c 100644 --- a/MEOS.NET/Types/TGeogPointSeq.g.cs +++ b/MEOS.NET/Types/TGeogPointSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeogPointSeqSet.g.cs b/MEOS.NET/Types/TGeogPointSeqSet.g.cs index 090e73e..f31d686 100644 --- a/MEOS.NET/Types/TGeogPointSeqSet.g.cs +++ b/MEOS.NET/Types/TGeogPointSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeography.g.cs b/MEOS.NET/Types/TGeography.g.cs index 73a6594..3555fbf 100644 --- a/MEOS.NET/Types/TGeography.g.cs +++ b/MEOS.NET/Types/TGeography.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeographyInst.g.cs b/MEOS.NET/Types/TGeographyInst.g.cs index 23b2feb..98ea92c 100644 --- a/MEOS.NET/Types/TGeographyInst.g.cs +++ b/MEOS.NET/Types/TGeographyInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeographySeq.g.cs b/MEOS.NET/Types/TGeographySeq.g.cs index a132e8c..df793a5 100644 --- a/MEOS.NET/Types/TGeographySeq.g.cs +++ b/MEOS.NET/Types/TGeographySeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeographySeqSet.g.cs b/MEOS.NET/Types/TGeographySeqSet.g.cs index c5f1e78..7676ed3 100644 --- a/MEOS.NET/Types/TGeographySeqSet.g.cs +++ b/MEOS.NET/Types/TGeographySeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeomPoint.g.cs b/MEOS.NET/Types/TGeomPoint.g.cs index 1ad0ebf..3dd793e 100644 --- a/MEOS.NET/Types/TGeomPoint.g.cs +++ b/MEOS.NET/Types/TGeomPoint.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeomPointInst.g.cs b/MEOS.NET/Types/TGeomPointInst.g.cs index 8a87535..110488d 100644 --- a/MEOS.NET/Types/TGeomPointInst.g.cs +++ b/MEOS.NET/Types/TGeomPointInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeomPointSeq.g.cs b/MEOS.NET/Types/TGeomPointSeq.g.cs index 08ad3b4..8b1fd8a 100644 --- a/MEOS.NET/Types/TGeomPointSeq.g.cs +++ b/MEOS.NET/Types/TGeomPointSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeomPointSeqSet.g.cs b/MEOS.NET/Types/TGeomPointSeqSet.g.cs index 963b109..7ba7d77 100644 --- a/MEOS.NET/Types/TGeomPointSeqSet.g.cs +++ b/MEOS.NET/Types/TGeomPointSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeometry.g.cs b/MEOS.NET/Types/TGeometry.g.cs index f76d612..52e799d 100644 --- a/MEOS.NET/Types/TGeometry.g.cs +++ b/MEOS.NET/Types/TGeometry.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeometryInst.g.cs b/MEOS.NET/Types/TGeometryInst.g.cs index cfddf5e..35dc952 100644 --- a/MEOS.NET/Types/TGeometryInst.g.cs +++ b/MEOS.NET/Types/TGeometryInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeometrySeq.g.cs b/MEOS.NET/Types/TGeometrySeq.g.cs index d56fe31..20247ee 100644 --- a/MEOS.NET/Types/TGeometrySeq.g.cs +++ b/MEOS.NET/Types/TGeometrySeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TGeometrySeqSet.g.cs b/MEOS.NET/Types/TGeometrySeqSet.g.cs index 561585e..d0e6245 100644 --- a/MEOS.NET/Types/TGeometrySeqSet.g.cs +++ b/MEOS.NET/Types/TGeometrySeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TInstant.g.cs b/MEOS.NET/Types/TInstant.g.cs index 0fb49ef..1d49aff 100644 --- a/MEOS.NET/Types/TInstant.g.cs +++ b/MEOS.NET/Types/TInstant.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TInt.g.cs b/MEOS.NET/Types/TInt.g.cs index a78e0ed..71b1af9 100644 --- a/MEOS.NET/Types/TInt.g.cs +++ b/MEOS.NET/Types/TInt.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TIntInst.g.cs b/MEOS.NET/Types/TIntInst.g.cs index d734142..273085d 100644 --- a/MEOS.NET/Types/TIntInst.g.cs +++ b/MEOS.NET/Types/TIntInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TIntSeq.g.cs b/MEOS.NET/Types/TIntSeq.g.cs index 1ab09dd..c6bb2d2 100644 --- a/MEOS.NET/Types/TIntSeq.g.cs +++ b/MEOS.NET/Types/TIntSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TIntSeqSet.g.cs b/MEOS.NET/Types/TIntSeqSet.g.cs index 35dfc94..11731a0 100644 --- a/MEOS.NET/Types/TIntSeqSet.g.cs +++ b/MEOS.NET/Types/TIntSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TJsonb.g.cs b/MEOS.NET/Types/TJsonb.g.cs index d5cde93..239c88c 100644 --- a/MEOS.NET/Types/TJsonb.g.cs +++ b/MEOS.NET/Types/TJsonb.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TJsonbInst.g.cs b/MEOS.NET/Types/TJsonbInst.g.cs index 05487af..89399af 100644 --- a/MEOS.NET/Types/TJsonbInst.g.cs +++ b/MEOS.NET/Types/TJsonbInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TJsonbSeq.g.cs b/MEOS.NET/Types/TJsonbSeq.g.cs index 1358209..1e9271b 100644 --- a/MEOS.NET/Types/TJsonbSeq.g.cs +++ b/MEOS.NET/Types/TJsonbSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TJsonbSeqSet.g.cs b/MEOS.NET/Types/TJsonbSeqSet.g.cs index fdbf680..0589ea4 100644 --- a/MEOS.NET/Types/TJsonbSeqSet.g.cs +++ b/MEOS.NET/Types/TJsonbSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TNpoint.g.cs b/MEOS.NET/Types/TNpoint.g.cs index 5581560..c2ed0db 100644 --- a/MEOS.NET/Types/TNpoint.g.cs +++ b/MEOS.NET/Types/TNpoint.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TNpointInst.g.cs b/MEOS.NET/Types/TNpointInst.g.cs index 31ed367..b167a0b 100644 --- a/MEOS.NET/Types/TNpointInst.g.cs +++ b/MEOS.NET/Types/TNpointInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TNpointSeq.g.cs b/MEOS.NET/Types/TNpointSeq.g.cs index e945b60..3b560b0 100644 --- a/MEOS.NET/Types/TNpointSeq.g.cs +++ b/MEOS.NET/Types/TNpointSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TNpointSeqSet.g.cs b/MEOS.NET/Types/TNpointSeqSet.g.cs index 3715e3c..3722161 100644 --- a/MEOS.NET/Types/TNpointSeqSet.g.cs +++ b/MEOS.NET/Types/TNpointSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TNumber.g.cs b/MEOS.NET/Types/TNumber.g.cs index 29f83b1..9e1534a 100644 --- a/MEOS.NET/Types/TNumber.g.cs +++ b/MEOS.NET/Types/TNumber.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TPoint.g.cs b/MEOS.NET/Types/TPoint.g.cs index b9a6118..0fca9d9 100644 --- a/MEOS.NET/Types/TPoint.g.cs +++ b/MEOS.NET/Types/TPoint.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TPose.g.cs b/MEOS.NET/Types/TPose.g.cs index 076af2e..ae53a5e 100644 --- a/MEOS.NET/Types/TPose.g.cs +++ b/MEOS.NET/Types/TPose.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TPoseInst.g.cs b/MEOS.NET/Types/TPoseInst.g.cs index 8d5e5e3..3c7213e 100644 --- a/MEOS.NET/Types/TPoseInst.g.cs +++ b/MEOS.NET/Types/TPoseInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TPoseSeq.g.cs b/MEOS.NET/Types/TPoseSeq.g.cs index 88aa0bf..1f70f9a 100644 --- a/MEOS.NET/Types/TPoseSeq.g.cs +++ b/MEOS.NET/Types/TPoseSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TPoseSeqSet.g.cs b/MEOS.NET/Types/TPoseSeqSet.g.cs index 79e348e..cb5b373 100644 --- a/MEOS.NET/Types/TPoseSeqSet.g.cs +++ b/MEOS.NET/Types/TPoseSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TRGeometry.g.cs b/MEOS.NET/Types/TRGeometry.g.cs index 0eaa6f5..f4c44fa 100644 --- a/MEOS.NET/Types/TRGeometry.g.cs +++ b/MEOS.NET/Types/TRGeometry.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; @@ -192,5 +194,24 @@ public string Out() public static Temporal? In(string str) => MEOSFactory.WrapTemporal(Meos.TrgeometryIn(str)); + public new static Temporal? MergeArray(Temporal[] temparr) + { + IntPtr[] _temparrValues = new IntPtr[temparr.Length]; + for (int i = 0; i < temparr.Length; i++) + { + _temparrValues[i] = temparr[i].Ptr; + } + + GCHandle _temparr = GCHandle.Alloc(_temparrValues, GCHandleType.Pinned); + try + { + return MEOSFactory.WrapTemporal(Meos.TrgeometryMergeArray(_temparr.AddrOfPinnedObject(), temparr.Length)); + } + finally + { + _temparr.Free(); + } + } + } } diff --git a/MEOS.NET/Types/TRGeometryInst.g.cs b/MEOS.NET/Types/TRGeometryInst.g.cs index 9432f2f..d317814 100644 --- a/MEOS.NET/Types/TRGeometryInst.g.cs +++ b/MEOS.NET/Types/TRGeometryInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TRGeometrySeq.g.cs b/MEOS.NET/Types/TRGeometrySeq.g.cs index 6868e48..864dea3 100644 --- a/MEOS.NET/Types/TRGeometrySeq.g.cs +++ b/MEOS.NET/Types/TRGeometrySeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TRGeometrySeqSet.g.cs b/MEOS.NET/Types/TRGeometrySeqSet.g.cs index 6401afb..7474e78 100644 --- a/MEOS.NET/Types/TRGeometrySeqSet.g.cs +++ b/MEOS.NET/Types/TRGeometrySeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TSequence.g.cs b/MEOS.NET/Types/TSequence.g.cs index 7f774f4..3793c15 100644 --- a/MEOS.NET/Types/TSequence.g.cs +++ b/MEOS.NET/Types/TSequence.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; @@ -11,5 +13,24 @@ public class TSequence : Temporal { internal TSequence(IntPtr ptr) : base(ptr) { } + public static Temporal? Make(Temporal[] instants, bool lower_inc, bool upper_inc, InterpType interp, bool normalize) + { + IntPtr[] _instantsValues = new IntPtr[instants.Length]; + for (int i = 0; i < instants.Length; i++) + { + _instantsValues[i] = instants[i].Ptr; + } + + GCHandle _instants = GCHandle.Alloc(_instantsValues, GCHandleType.Pinned); + try + { + return MEOSFactory.WrapTemporal(Meos.TsequenceMake(_instants.AddrOfPinnedObject(), instants.Length, lower_inc, upper_inc, (int) interp, normalize)); + } + finally + { + _instants.Free(); + } + } + } } diff --git a/MEOS.NET/Types/TSequenceSet.g.cs b/MEOS.NET/Types/TSequenceSet.g.cs index df0c491..876cbb4 100644 --- a/MEOS.NET/Types/TSequenceSet.g.cs +++ b/MEOS.NET/Types/TSequenceSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; @@ -11,5 +13,24 @@ public class TSequenceSet : Temporal { internal TSequenceSet(IntPtr ptr) : base(ptr) { } + public static Temporal? Make(Temporal[] sequences, bool normalize) + { + IntPtr[] _sequencesValues = new IntPtr[sequences.Length]; + for (int i = 0; i < sequences.Length; i++) + { + _sequencesValues[i] = sequences[i].Ptr; + } + + GCHandle _sequences = GCHandle.Alloc(_sequencesValues, GCHandleType.Pinned); + try + { + return MEOSFactory.WrapTemporal(Meos.TsequencesetMake(_sequences.AddrOfPinnedObject(), sequences.Length, normalize)); + } + finally + { + _sequences.Free(); + } + } + } } diff --git a/MEOS.NET/Types/TSpatial.g.cs b/MEOS.NET/Types/TSpatial.g.cs index 5a543c1..91dd7d2 100644 --- a/MEOS.NET/Types/TSpatial.g.cs +++ b/MEOS.NET/Types/TSpatial.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TText.g.cs b/MEOS.NET/Types/TText.g.cs index e7cffb2..54f98f9 100644 --- a/MEOS.NET/Types/TText.g.cs +++ b/MEOS.NET/Types/TText.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TTextInst.g.cs b/MEOS.NET/Types/TTextInst.g.cs index 5f819bb..058b79c 100644 --- a/MEOS.NET/Types/TTextInst.g.cs +++ b/MEOS.NET/Types/TTextInst.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TTextSeq.g.cs b/MEOS.NET/Types/TTextSeq.g.cs index 3fbb9d2..3dd14da 100644 --- a/MEOS.NET/Types/TTextSeq.g.cs +++ b/MEOS.NET/Types/TTextSeq.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TTextSeqSet.g.cs b/MEOS.NET/Types/TTextSeqSet.g.cs index 87e1064..546f736 100644 --- a/MEOS.NET/Types/TTextSeqSet.g.cs +++ b/MEOS.NET/Types/TTextSeqSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/Temporal.g.cs b/MEOS.NET/Types/Temporal.g.cs index 0c6e8da..8d5b4b8 100644 --- a/MEOS.NET/Types/Temporal.g.cs +++ b/MEOS.NET/Types/Temporal.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; @@ -245,5 +247,24 @@ public bool UpperInc() public static Temporal? FromHEXWKB(string hexwkb) => MEOSFactory.WrapTemporal(Meos.TemporalFromHexwkb(hexwkb)); + public static Temporal? MergeArray(Temporal[] temparr) + { + IntPtr[] _temparrValues = new IntPtr[temparr.Length]; + for (int i = 0; i < temparr.Length; i++) + { + _temparrValues[i] = temparr[i].Ptr; + } + + GCHandle _temparr = GCHandle.Alloc(_temparrValues, GCHandleType.Pinned); + try + { + return MEOSFactory.WrapTemporal(Meos.TemporalMergeArray(_temparr.AddrOfPinnedObject(), temparr.Length)); + } + finally + { + _temparr.Free(); + } + } + } } diff --git a/MEOS.NET/Types/TextSet.g.cs b/MEOS.NET/Types/TextSet.g.cs index 5343968..e4c6a32 100644 --- a/MEOS.NET/Types/TextSet.g.cs +++ b/MEOS.NET/Types/TextSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TsTzSet.g.cs b/MEOS.NET/Types/TsTzSet.g.cs index e884934..e655640 100644 --- a/MEOS.NET/Types/TsTzSet.g.cs +++ b/MEOS.NET/Types/TsTzSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TsTzSpan.g.cs b/MEOS.NET/Types/TsTzSpan.g.cs index 81d675a..834c3ec 100644 --- a/MEOS.NET/Types/TsTzSpan.g.cs +++ b/MEOS.NET/Types/TsTzSpan.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/MEOS.NET/Types/TsTzSpanSet.g.cs b/MEOS.NET/Types/TsTzSpanSet.g.cs index aa690a6..c54a5e1 100644 --- a/MEOS.NET/Types/TsTzSpanSet.g.cs +++ b/MEOS.NET/Types/TsTzSpanSet.g.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Runtime.InteropServices; + using MEOS.NET.Enums; using MEOS.NET.Functions; diff --git a/tools/objectgen.py b/tools/objectgen.py index 9f4ef40..d807b94 100644 --- a/tools/objectgen.py +++ b/tools/objectgen.py @@ -233,12 +233,14 @@ class Method: """One emitted method: its C# signature and the wrapper call behind it.""" def __init__(self, name: str, ret: str, params: list[tuple[str, str]], - body: str, static: bool): + body: str, static: bool, arrays: list[tuple[str, str]] | None = None): self.name = name self.ret = ret self.params = params self.body = body self.static = static + # (parameter name, element class) for each counted array the method takes. + self.arrays = arrays or [] class Generator: @@ -321,16 +323,22 @@ def method_for(self, cls: str, entry: dict) -> Method | None: # `T *values, int count` is MEOS's counted-array convention: the pointer is # the first element of an array, not one value, so wrapping it as one # object would hand the callee a single element and a length that lies. - raw = [p["name"] for p in f.get("params", [])] + recv_ctype = self.m.ctype.get(cls) + declared = f.get("params", []) + receiver_first = (bool(declared) + and clean(declared[0]["cType"]) == f"{recv_ctype} *") + # `T *values, int count` is MEOS's counted-array convention. The length is + # named `count`; a parameter named `n` is the INDEX of the `*_n` + # accessors, whose pointer is the receiver and no array at all. counted = set() - for i, p in enumerate(f.get("params", [])): - nxt = f["params"][i + 1] if i + 1 < len(f["params"]) else None - if (clean(p["cType"]).endswith("*") and nxt - and nxt["name"] in ("count", "n") + for i, p in enumerate(declared): + nxt = declared[i + 1] if i + 1 < len(declared) else None + if (i == 0 and receiver_first) or not clean(p["cType"]).endswith("*"): + continue + if (nxt and nxt["name"] == "count" and clean(nxt["cType"]) in ("int", "int32", "int32_t")): counted.add(codegen.csharp_param_name(p["name"])) - recv_ctype = self.m.ctype.get(cls) params = list(wrapper_params) static = True args: list[str] = [] @@ -349,12 +357,33 @@ def method_for(self, cls: str, entry: dict) -> Method | None: self.deferred[cls].append(f"{oo}: neither a receiver nor a value to return") return None + # A counted array is one parameter to the caller and two to MEOS: the + # array and its length, which the array itself answers. + declared = f.get("params", []) + count_of = {} + for i, p in enumerate(declared): + if (codegen.csharp_param_name(p["name"]) in counted + and i + 1 < len(declared)): + count_of[codegen.csharp_param_name(declared[i + 1]["name"])] = \ + codegen.csharp_param_name(p["name"]) + sig: list[tuple[str, str]] = [] + arrays: list[tuple[str, str]] = [] for cs_type, pname in params: + if pname in count_of: + args.append(f"{count_of[pname]}.Length") + continue if pname in counted: - self.deferred[cls].append( - f"{oo}: argument {pname} is a counted array") - return None + element = self.m.class_for_ctype(clean(c_by_name[pname])[:-1]) + if element is None: + self.deferred[cls].append( + f"{oo}: argument {pname} is an array of " + f"{clean(c_by_name[pname])[:-1]}, which has no class") + return None + sig.append((f"{element}[]", pname)) + arrays.append((pname, element)) + args.append(f"_{pname}.AddrOfPinnedObject()") + continue mapped = self.map_param(c_by_name.get(pname, ""), cs_type, pname) if mapped is None: self.deferred[cls].append( @@ -365,7 +394,8 @@ def method_for(self, cls: str, entry: dict) -> Method | None: args.append(mapped[1]) call = f"Meos.{codegen.public_name(fname)}({', '.join(args)})" - return Method(pascal(oo), ret_type, sig, ret_expr.replace("$", call), static) + return Method(pascal(oo), ret_type, sig, ret_expr.replace("$", call), static, + arrays) def inherited_names(self, cls: str) -> set[tuple]: names: set[tuple] = set() @@ -393,6 +423,8 @@ def emit_class(self, cls: str) -> str: lines = [ "#nullable enable", "", + "using System.Runtime.InteropServices;", + "", "using MEOS.NET.Enums;", "using MEOS.NET.Functions;", "", @@ -411,11 +443,43 @@ def emit_class(self, cls: str) -> str: new = "new " if (m.name, tuple(t for t, _ in m.params)) in inherited else "" kind = "static " if m.static else "" lines.append(f" public {new}{kind}{m.ret} {m.name}({args})") - lines.append(f" => {m.body};") + if m.arrays: + lines.extend(self.array_body(m)) + else: + lines.append(f" => {m.body};") lines.append("") lines += [" }", "}", ""] return "\n".join(lines) + def array_body(self, method: Method) -> list[str]: + """The body of a method taking a counted array. + + MEOS reads an array of its own values through a pointer to the first + element, so the wrappers' pointers are gathered into one array and pinned + for the call. MEOS copies what it keeps, so the pin lasts exactly as long + as the call does.""" + lines = [" {"] + for name, element in method.arrays: + lines += [ + f" IntPtr[] _{name}Values = new IntPtr[{ident(name)}.Length];", + f" for (int i = 0; i < {ident(name)}.Length; i++)", + " {", + f" _{name}Values[i] = {ident(name)}[i].Ptr;", + " }", + "", + f" GCHandle _{name} = GCHandle.Alloc(_{name}Values, GCHandleType.Pinned);", + ] + lines.append(" try") + lines.append(" {") + lines.append(f" return {method.body};") + lines.append(" }") + lines.append(" finally") + lines.append(" {") + for name, _ in method.arrays: + lines.append(f" _{name}.Free();") + lines += [" }", " }"] + return lines + def to_string(self, cls: str, methods: list) -> list[str]: """`ToString` over the class's own text output, where MEOS publishes one. From 508729f25c8052670f979d233419bffb3b8d345e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Zim=C3=A1nyi?= Date: Wed, 2 Sep 2026 23:48:23 +0200 Subject: [PATCH 2/2] Answer the value MEOS writes through an out-parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MEOS answers some values by writing them through an out-parameter and returning whether the value exists at all — `tbox_xmax(box, double *result)`, `floatset_value_n(set, n, double *result)`, `tfloat_value_at_timestamptz(temp, t, strict, double *result)`. The object layer answers that as a nullable: the buffer is allocated for the call, and a `false` return answers null while a `true` one answers what MEOS wrote. The out-parameter never appears in the C# signature, so a caller cannot pass a buffer of the wrong size or read one MEOS did not fill. The reader comes from the pointee: `double`, `bool`, `int`, `long`, and a `TimestampTz` or `DateADT` through the same conversion the rest of the layer uses. 35 accessors reach the object layer that way — `TBox.Xmin`, `TBox.TminInc`, `FloatSet.ValueN`, `TsTzSet.ValueN`, `TFloat.ValueAtTimestamptz` and their kin — 646 methods against 611. The 19 whose out-parameter is a `GSERIALIZED **`, `text **`, `Cbuffer **`, `Npoint **`, `Pose **` or `Jsonb **` name that pointee as their reason, since the model gives those values no class. Four tests read both answers: a float box answers its bounds and a box without an x dimension answers null for them while still answering its time bounds, a float set answers the value at an index and null past the end, and a temporal float answers its value at a moment inside its span and null outside. --- MEOS.NET.Tests/OutParameterTests.cs | 53 ++++++++ MEOS.NET/Types/BigIntSet.g.cs | 18 +++ MEOS.NET/Types/DateSet.g.cs | 18 +++ MEOS.NET/Types/DateSpanSet.g.cs | 18 +++ MEOS.NET/Types/FloatSet.g.cs | 18 +++ MEOS.NET/Types/IntSet.g.cs | 18 +++ MEOS.NET/Types/STBox.g.cs | 180 ++++++++++++++++++++++++++++ MEOS.NET/Types/TBigint.g.cs | 36 ++++++ MEOS.NET/Types/TBool.g.cs | 36 ++++++ MEOS.NET/Types/TBox.g.cs | 144 ++++++++++++++++++++++ MEOS.NET/Types/TFloat.g.cs | 36 ++++++ MEOS.NET/Types/TInt.g.cs | 36 ++++++ MEOS.NET/Types/TPoint.g.cs | 18 +++ MEOS.NET/Types/Temporal.g.cs | 18 +++ MEOS.NET/Types/TsTzSet.g.cs | 18 +++ MEOS.NET/Types/TsTzSpanSet.g.cs | 18 +++ tools/objectgen.py | 78 +++++++++++- 17 files changed, 758 insertions(+), 3 deletions(-) create mode 100644 MEOS.NET.Tests/OutParameterTests.cs diff --git a/MEOS.NET.Tests/OutParameterTests.cs b/MEOS.NET.Tests/OutParameterTests.cs new file mode 100644 index 0000000..c80285d --- /dev/null +++ b/MEOS.NET.Tests/OutParameterTests.cs @@ -0,0 +1,53 @@ +using MEOS.NET.Types; + +namespace MEOS.NET.Tests +{ + /// + /// MEOS answers some values through an out-parameter and returns whether the + /// value exists at all, so those methods answer the value or null. + /// + [TestClass] + public class OutParameterTests : MeosTest + { + [TestMethod] + public void ABoxAnswersTheBoundsItHas() + { + TBox box = TBox.In("TBOXFLOAT XT([1.0, 3.0],[2024-12-06, 2024-12-08])")!; + + Assert.AreEqual(1.0, box.Xmin()); + Assert.AreEqual(3.0, box.Xmax()); + Assert.AreEqual(true, box.TminInc()); + } + + [TestMethod] + public void ABoxAnswersNullForABoundItDoesNotHave() + { + TBox box = TBox.In("TBOX T([2024-12-06, 2024-12-08])")!; + + Assert.IsNull(box.Xmin()); + Assert.IsNull(box.Xmax()); + Assert.IsNotNull(box.TminInc()); + } + + [TestMethod] + public void ASetAnswersTheValueAtAnIndex() + { + Set set = FloatSet.In("{1.5, 2.5, 3.5}")!; + + Assert.AreEqual(1.5, ((FloatSet)set).ValueN(1)); + Assert.AreEqual(3.5, ((FloatSet)set).ValueN(3)); + Assert.IsNull(((FloatSet)set).ValueN(4)); + } + + [TestMethod] + public void ATemporalFloatAnswersItsValueAtAMoment() + { + TFloat temp = (TFloat)TFloat.In("[25.0@2024-12-06, 27.0@2024-12-08]")!; + + Assert.AreEqual(25.0, + temp.ValueAtTimestamptz(new DateTime(2024, 12, 6, 0, 0, 0, DateTimeKind.Utc), true)); + Assert.IsNull( + temp.ValueAtTimestamptz(new DateTime(2024, 12, 9, 0, 0, 0, DateTimeKind.Utc), true)); + } + } +} diff --git a/MEOS.NET/Types/BigIntSet.g.cs b/MEOS.NET/Types/BigIntSet.g.cs index 493945d..f797ccb 100644 --- a/MEOS.NET/Types/BigIntSet.g.cs +++ b/MEOS.NET/Types/BigIntSet.g.cs @@ -29,6 +29,24 @@ public string Out() public long StartValue() => Meos.BigintsetStartValue(this.Ptr); + public long? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.BigintsetValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.ReadInt64(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public long[] Values() => Meos.BigintsetValues(this.Ptr); diff --git a/MEOS.NET/Types/DateSet.g.cs b/MEOS.NET/Types/DateSet.g.cs index de8374a..978f4d0 100644 --- a/MEOS.NET/Types/DateSet.g.cs +++ b/MEOS.NET/Types/DateSet.g.cs @@ -32,6 +32,24 @@ public DateOnly StartValue() public Set? ToTstzset() => MEOSFactory.WrapSet(Meos.DatesetToTstzset(this.Ptr)); + public DateOnly? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(4); + try + { + if (!Meos.DatesetValueN(this.Ptr, n, _result)) + { + return null; + } + + return MEOSConvert.ToDateOnly(Marshal.ReadInt32(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public int[] Values() => Meos.DatesetValues(this.Ptr); diff --git a/MEOS.NET/Types/DateSpanSet.g.cs b/MEOS.NET/Types/DateSpanSet.g.cs index 296627d..378f520 100644 --- a/MEOS.NET/Types/DateSpanSet.g.cs +++ b/MEOS.NET/Types/DateSpanSet.g.cs @@ -17,6 +17,24 @@ internal DateSpanSet(IntPtr ptr) : base(ptr) { } public override string ToString() => this.Out(); + public DateOnly? DateN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(4); + try + { + if (!Meos.DatespansetDateN(this.Ptr, n, _result)) + { + return null; + } + + return MEOSConvert.ToDateOnly(Marshal.ReadInt32(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public Set? Dates() => MEOSFactory.WrapSet(Meos.DatespansetDates(this.Ptr)); diff --git a/MEOS.NET/Types/FloatSet.g.cs b/MEOS.NET/Types/FloatSet.g.cs index e2dc05e..33edc9b 100644 --- a/MEOS.NET/Types/FloatSet.g.cs +++ b/MEOS.NET/Types/FloatSet.g.cs @@ -44,6 +44,24 @@ public double StartValue() public Set? ToIntset() => MEOSFactory.WrapSet(Meos.FloatsetToIntset(this.Ptr)); + public double? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.FloatsetValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public double[] Values() => Meos.FloatsetValues(this.Ptr); diff --git a/MEOS.NET/Types/IntSet.g.cs b/MEOS.NET/Types/IntSet.g.cs index eada4ca..9d4248e 100644 --- a/MEOS.NET/Types/IntSet.g.cs +++ b/MEOS.NET/Types/IntSet.g.cs @@ -32,6 +32,24 @@ public int StartValue() public Set? ToFloatset() => MEOSFactory.WrapSet(Meos.IntsetToFloatset(this.Ptr)); + public int? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(4); + try + { + if (!Meos.IntsetValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.ReadInt32(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public int[] Values() => Meos.IntsetValues(this.Ptr); diff --git a/MEOS.NET/Types/STBox.g.cs b/MEOS.NET/Types/STBox.g.cs index fff3d92..115bdc3 100644 --- a/MEOS.NET/Types/STBox.g.cs +++ b/MEOS.NET/Types/STBox.g.cs @@ -89,6 +89,78 @@ public int SRID() public double SpatialDistance(STBox box2) => Meos.StboxSpatialDistance(this.Ptr, box2.Ptr); + public DateTime? Tmax() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxTmax(this.Ptr, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public bool? TmaxInc() + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.StboxTmaxInc(this.Ptr, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public DateTime? Tmin() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxTmin(this.Ptr, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public bool? TminInc() + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.StboxTminInc(this.Ptr, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public Span? ToTstzspan() => MEOSFactory.WrapSpan(Meos.StboxToTstzspan(this.Ptr)); @@ -101,6 +173,114 @@ public double SpatialDistance(STBox box2) public double Volume() => Meos.StboxVolume(this.Ptr); + public double? Xmax() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxXmax(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public double? Xmin() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxXmin(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public double? Ymax() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxYmax(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public double? Ymin() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxYmin(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public double? Zmax() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxZmax(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public double? Zmin() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.StboxZmin(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public static STBox? FromHEXWKB(string hexwkb) => MEOSFactory.WrapSTBox(Meos.StboxFromHexwkb(hexwkb)); diff --git a/MEOS.NET/Types/TBigint.g.cs b/MEOS.NET/Types/TBigint.g.cs index 2018749..70e71d7 100644 --- a/MEOS.NET/Types/TBigint.g.cs +++ b/MEOS.NET/Types/TBigint.g.cs @@ -56,6 +56,42 @@ public long StartValue() public Temporal? ToTs2cell() => MEOSFactory.WrapTemporal(Meos.TbigintToTs2cell(this.Ptr)); + public long? ValueAtTimestamptz(DateTime t, bool strict) + { + IntPtr _value = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TbigintValueAtTimestamptz(this.Ptr, MEOSConvert.ToTimestampTz(t), strict, _value)) + { + return null; + } + + return Marshal.ReadInt64(_value); + } + finally + { + Marshal.FreeHGlobal(_value); + } + } + + public long? ValueN(long n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TbigintValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.ReadInt64(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public static Temporal? FromBaseTemp(long i, Temporal temp) => MEOSFactory.WrapTemporal(Meos.TbigintFromBaseTemp(i, temp.Ptr)); diff --git a/MEOS.NET/Types/TBool.g.cs b/MEOS.NET/Types/TBool.g.cs index fc5bd1d..9777500 100644 --- a/MEOS.NET/Types/TBool.g.cs +++ b/MEOS.NET/Types/TBool.g.cs @@ -35,6 +35,42 @@ public bool StartValue() public Temporal? ToTint() => MEOSFactory.WrapTemporal(Meos.TboolToTint(this.Ptr)); + public bool? ValueAtTimestamptz(DateTime t, bool strict) + { + IntPtr _value = Marshal.AllocHGlobal(1); + try + { + if (!Meos.TboolValueAtTimestamptz(this.Ptr, MEOSConvert.ToTimestampTz(t), strict, _value)) + { + return null; + } + + return Marshal.ReadByte(_value) != 0; + } + finally + { + Marshal.FreeHGlobal(_value); + } + } + + public bool? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.TboolValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public SpanSet? WhenTrue() => MEOSFactory.WrapSpanSet(Meos.TboolWhenTrue(this.Ptr)); diff --git a/MEOS.NET/Types/TBox.g.cs b/MEOS.NET/Types/TBox.g.cs index dd855a3..d8dd6ce 100644 --- a/MEOS.NET/Types/TBox.g.cs +++ b/MEOS.NET/Types/TBox.g.cs @@ -59,6 +59,78 @@ public string Out(int maxdd) public TBox? Round(int maxdd) => MEOSFactory.WrapTBox(Meos.TboxRound(this.Ptr, maxdd)); + public DateTime? Tmax() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TboxTmax(this.Ptr, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public bool? TmaxInc() + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.TboxTmaxInc(this.Ptr, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public DateTime? Tmin() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TboxTmin(this.Ptr, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public bool? TminInc() + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.TboxTminInc(this.Ptr, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public Span? ToBigintspan() => MEOSFactory.WrapSpan(Meos.TboxToBigintspan(this.Ptr)); @@ -71,6 +143,78 @@ public string Out(int maxdd) public Span? ToTstzspan() => MEOSFactory.WrapSpan(Meos.TboxToTstzspan(this.Ptr)); + public double? Xmax() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TboxXmax(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public bool? XmaxInc() + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.TboxXmaxInc(this.Ptr, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public double? Xmin() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TboxXmin(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + + public bool? XminInc() + { + IntPtr _result = Marshal.AllocHGlobal(1); + try + { + if (!Meos.TboxXminInc(this.Ptr, _result)) + { + return null; + } + + return Marshal.ReadByte(_result) != 0; + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public static TBox? FromHEXWKB(string hexwkb) => MEOSFactory.WrapTBox(Meos.TboxFromHexwkb(hexwkb)); diff --git a/MEOS.NET/Types/TFloat.g.cs b/MEOS.NET/Types/TFloat.g.cs index 4b2e1a9..14f7e92 100644 --- a/MEOS.NET/Types/TFloat.g.cs +++ b/MEOS.NET/Types/TFloat.g.cs @@ -83,12 +83,48 @@ public double StartValue() public Temporal? ToTint() => MEOSFactory.WrapTemporal(Meos.TfloatToTint(this.Ptr)); + public double? ValueAtTimestamptz(DateTime t, bool strict) + { + IntPtr _value = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TfloatValueAtTimestamptz(this.Ptr, MEOSConvert.ToTimestampTz(t), strict, _value)) + { + return null; + } + + return Marshal.PtrToStructure(_value); + } + finally + { + Marshal.FreeHGlobal(_value); + } + } + public Span?[] ValueBins(double vsize, double vorigin) => MEOSFactory.WrapSpanArray(Meos.TfloatValueBins(this.Ptr, vsize, vorigin)); public TBox?[] ValueBoxes(double vsize, double vorigin) => MEOSFactory.WrapTBoxArray(Meos.TfloatValueBoxes(this.Ptr, vsize, vorigin)); + public double? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TfloatValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public double[] Values() => Meos.TfloatValues(this.Ptr); diff --git a/MEOS.NET/Types/TInt.g.cs b/MEOS.NET/Types/TInt.g.cs index 71b1af9..3c2cc5a 100644 --- a/MEOS.NET/Types/TInt.g.cs +++ b/MEOS.NET/Types/TInt.g.cs @@ -53,12 +53,48 @@ public int StartValue() public Temporal? ToTfloat() => MEOSFactory.WrapTemporal(Meos.TintToTfloat(this.Ptr)); + public int? ValueAtTimestamptz(DateTime t, bool strict) + { + IntPtr _value = Marshal.AllocHGlobal(4); + try + { + if (!Meos.TintValueAtTimestamptz(this.Ptr, MEOSConvert.ToTimestampTz(t), strict, _value)) + { + return null; + } + + return Marshal.ReadInt32(_value); + } + finally + { + Marshal.FreeHGlobal(_value); + } + } + public Span?[] ValueBins(int vsize, int vorigin) => MEOSFactory.WrapSpanArray(Meos.TintValueBins(this.Ptr, vsize, vorigin)); public TBox?[] ValueBoxes(int vsize, int vorigin) => MEOSFactory.WrapTBoxArray(Meos.TintValueBoxes(this.Ptr, vsize, vorigin)); + public int? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(4); + try + { + if (!Meos.TintValueN(this.Ptr, n, _result)) + { + return null; + } + + return Marshal.ReadInt32(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public int[] Values() => Meos.TintValues(this.Ptr); diff --git a/MEOS.NET/Types/TPoint.g.cs b/MEOS.NET/Types/TPoint.g.cs index 0fca9d9..035955c 100644 --- a/MEOS.NET/Types/TPoint.g.cs +++ b/MEOS.NET/Types/TPoint.g.cs @@ -25,6 +25,24 @@ internal TPoint(IntPtr ptr) : base(ptr) { } public Temporal? CumulativeLength() => MEOSFactory.WrapTemporal(Meos.TpointCumulativeLength(this.Ptr)); + public double? Direction() + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TpointDirection(this.Ptr, _result)) + { + return null; + } + + return Marshal.PtrToStructure(_result); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public Temporal? GetX() => MEOSFactory.WrapTemporal(Meos.TpointGetX(this.Ptr)); diff --git a/MEOS.NET/Types/Temporal.g.cs b/MEOS.NET/Types/Temporal.g.cs index 8d5b4b8..351abe4 100644 --- a/MEOS.NET/Types/Temporal.g.cs +++ b/MEOS.NET/Types/Temporal.g.cs @@ -235,6 +235,24 @@ public DateTime StartTimestamptz() public long[] Timestamps() => Meos.TemporalTimestamps(this.Ptr); + public DateTime? TimestamptzN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TemporalTimestamptzN(this.Ptr, n, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public Span? ToTstzspan() => MEOSFactory.WrapSpan(Meos.TemporalToTstzspan(this.Ptr)); diff --git a/MEOS.NET/Types/TsTzSet.g.cs b/MEOS.NET/Types/TsTzSet.g.cs index e655640..a10036b 100644 --- a/MEOS.NET/Types/TsTzSet.g.cs +++ b/MEOS.NET/Types/TsTzSet.g.cs @@ -32,6 +32,24 @@ public DateTime StartValue() public STBox? ToStbox() => MEOSFactory.WrapSTBox(Meos.TstzsetToStbox(this.Ptr)); + public DateTime? ValueN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TstzsetValueN(this.Ptr, n, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public long[] Values() => Meos.TstzsetValues(this.Ptr); diff --git a/MEOS.NET/Types/TsTzSpanSet.g.cs b/MEOS.NET/Types/TsTzSpanSet.g.cs index c54a5e1..bfa2938 100644 --- a/MEOS.NET/Types/TsTzSpanSet.g.cs +++ b/MEOS.NET/Types/TsTzSpanSet.g.cs @@ -35,6 +35,24 @@ public DateTime StartTimestamptz() public Set? Timestamps() => MEOSFactory.WrapSet(Meos.TstzspansetTimestamps(this.Ptr)); + public DateTime? TimestamptzN(int n) + { + IntPtr _result = Marshal.AllocHGlobal(8); + try + { + if (!Meos.TstzspansetTimestamptzN(this.Ptr, n, _result)) + { + return null; + } + + return MEOSConvert.ToDateTime(Marshal.ReadInt64(_result)); + } + finally + { + Marshal.FreeHGlobal(_result); + } + } + public SpanSet? ToDatespanset() => MEOSFactory.WrapSpanSet(Meos.TstzspansetToDatespanset(this.Ptr)); diff --git a/tools/objectgen.py b/tools/objectgen.py index d807b94..889a7ed 100644 --- a/tools/objectgen.py +++ b/tools/objectgen.py @@ -61,6 +61,19 @@ # The template axis: a concrete class is the product ``. SUBTYPE_SUFFIX = {"TInstant": "Inst", "TSequence": "Seq", "TSequenceSet": "SeqSet"} +# What a value out-parameter of each pointee type reads back as: the C# type, the +# bytes to allocate for it, and how to read the value MEOS wrote there. +OUT_PARAM_READERS = { + "double *": ("double", 8, "Marshal.PtrToStructure({0})"), + "float8 *": ("double", 8, "Marshal.PtrToStructure({0})"), + "bool *": ("bool", 1, "Marshal.ReadByte({0}) != 0"), + "int *": ("int", 4, "Marshal.ReadInt32({0})"), + "int32_t *": ("int", 4, "Marshal.ReadInt32({0})"), + "int64_t *": ("long", 8, "Marshal.ReadInt64({0})"), + "TimestampTz *": ("DateTime", 8, "MEOSConvert.ToDateTime(Marshal.ReadInt64({0}))"), + "DateADT *": ("DateOnly", 4, "MEOSConvert.ToDateOnly(Marshal.ReadInt32({0}))"), +} + # C types the object layer passes and returns as C# scalars, keyed by the cleaned # C spelling. Everything else is either a wrapped class pointer or deferred. PASSTHROUGH_C = { @@ -233,7 +246,8 @@ class Method: """One emitted method: its C# signature and the wrapper call behind it.""" def __init__(self, name: str, ret: str, params: list[tuple[str, str]], - body: str, static: bool, arrays: list[tuple[str, str]] | None = None): + body: str, static: bool, arrays: list[tuple[str, str]] | None = None, + out_param: tuple[str, int, str] | None = None): self.name = name self.ret = ret self.params = params @@ -241,6 +255,8 @@ def __init__(self, name: str, ret: str, params: list[tuple[str, str]], self.static = static # (parameter name, element class) for each counted array the method takes. self.arrays = arrays or [] + # (parameter name, bytes, reader expression) for a value out-parameter. + self.out_param = out_param class Generator: @@ -347,6 +363,23 @@ def method_for(self, cls: str, entry: dict) -> Method | None: args.append("this.Ptr") params = params[1:] + # A `bool` return with one value out-parameter is MEOS saying whether the + # value exists: the method answers the value, or nothing. + out_params = (f.get("shape") or {}).get("outParams") or [] + result_out = None + if clean(f["returnType"]["c"]) == "bool" and len(out_params) == 1: + pointee = clean(next( + (p["cType"] for p in f.get("params", []) + if p["name"] == out_params[0]), "")) + reader = OUT_PARAM_READERS.get(pointee) + if reader: + result_out = (codegen.csharp_param_name(out_params[0]), reader) + else: + self.deferred[cls].append( + f"{oo}: the value out-parameter {out_params[0]} is a " + f"{pointee}, which has no reader") + return None + ret = self.map_return(f, wrapper_ret) if ret is None: self.deferred[cls].append( @@ -367,9 +400,16 @@ def method_for(self, cls: str, entry: dict) -> Method | None: count_of[codegen.csharp_param_name(declared[i + 1]["name"])] = \ codegen.csharp_param_name(p["name"]) + if result_out is not None: + ret_type = f"{result_out[1][0]}?" + ret_expr = "$" + sig: list[tuple[str, str]] = [] arrays: list[tuple[str, str]] = [] for cs_type, pname in params: + if result_out is not None and pname == result_out[0]: + args.append(f"_{pname}") + continue if pname in count_of: args.append(f"{count_of[pname]}.Length") continue @@ -394,8 +434,12 @@ def method_for(self, cls: str, entry: dict) -> Method | None: args.append(mapped[1]) call = f"Meos.{codegen.public_name(fname)}({', '.join(args)})" + out = None + if result_out is not None: + name, (_, size, reader) = result_out + out = (name, size, reader.format(f"_{name}")) return Method(pascal(oo), ret_type, sig, ret_expr.replace("$", call), static, - arrays) + arrays, out) def inherited_names(self, cls: str) -> set[tuple]: names: set[tuple] = set() @@ -443,7 +487,9 @@ def emit_class(self, cls: str) -> str: new = "new " if (m.name, tuple(t for t, _ in m.params)) in inherited else "" kind = "static " if m.static else "" lines.append(f" public {new}{kind}{m.ret} {m.name}({args})") - if m.arrays: + if m.out_param: + lines.extend(self.out_param_body(m)) + elif m.arrays: lines.extend(self.array_body(m)) else: lines.append(f" => {m.body};") @@ -451,6 +497,32 @@ def emit_class(self, cls: str) -> str: lines += [" }", "}", ""] return "\n".join(lines) + def out_param_body(self, method: Method) -> list[str]: + """The body of a method whose value MEOS writes through an out-parameter. + + MEOS answers `false` when the value does not exist and leaves the + out-parameter untouched, so the method answers null there and the value + otherwise.""" + name, size, reader = method.out_param + return [ + " {", + f" IntPtr _{name} = Marshal.AllocHGlobal({size});", + " try", + " {", + f" if (!{method.body})", + " {", + " return null;", + " }", + "", + f" return {reader};", + " }", + " finally", + " {", + f" Marshal.FreeHGlobal(_{name});", + " }", + " }", + ] + def array_body(self, method: Method) -> list[str]: """The body of a method taking a counted array.