You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by cu...@apache.org on 2023/11/19 17:01:12 UTC
(arrow) branch main updated: GH-38348: [C#] Make PrimitiveArray support IReadOnlyList (#38680)
This is an automated email from the ASF dual-hosted git repository.
curth pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 96e62d86ab GH-38348: [C#] Make PrimitiveArray<T> support IReadOnlyList<T?> (#38680)
96e62d86ab is described below
commit 96e62d86abe8a39a7fc20af7236bd43a9fd7f2da
Author: Gavin Murrison <21...@users.noreply.github.com>
AuthorDate: Sun Nov 19 17:01:05 2023 +0000
GH-38348: [C#] Make PrimitiveArray<T> support IReadOnlyList<T?> (#38680)
### What changes are included in this PR?
Make Arrow arrays of scalar type T implement the same semantic contract as IReadOnlyList<T?>.
Note that this PR does not include similar support for ICollection<T?>. I could add that support in this PR or a future PR.
### Are these changes tested?
This PR includes unit tests of the implemented IReadOnlyList<T?> methods.
* Closes: #38348
Authored-by: voidstar69 <vo...@gmail.com>
Signed-off-by: Curt Hagenlocher <cu...@hagenlocher.org>
---
csharp/src/Apache.Arrow/Arrays/BinaryArray.cs | 16 +++++++++++-
csharp/src/Apache.Arrow/Arrays/BooleanArray.cs | 17 +++++++++++-
csharp/src/Apache.Arrow/Arrays/Date32Array.cs | 30 ++++++++++++++++++++-
csharp/src/Apache.Arrow/Arrays/Date64Array.cs | 32 +++++++++++++++++++++--
csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs | 22 +++++++++++++++-
csharp/src/Apache.Arrow/Arrays/StringArray.cs | 17 +++++++++++-
csharp/src/Apache.Arrow/Arrays/Time32Array.cs | 16 ++++++++++++
csharp/src/Apache.Arrow/Arrays/Time64Array.cs | 16 ++++++++++++
csharp/src/Apache.Arrow/Arrays/TimestampArray.cs | 14 +++++++++-
csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs | 29 ++++++++++++++++++++
10 files changed, 201 insertions(+), 8 deletions(-)
diff --git a/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs b/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
index a7ddb14af6..1bd4035d5b 100644
--- a/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
@@ -18,10 +18,11 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Apache.Arrow.Memory;
+using System.Collections;
namespace Apache.Arrow
{
- public class BinaryArray : Array
+ public class BinaryArray : Array, IReadOnlyList<byte[]>
{
public class Builder : BuilderBase<BinaryArray, Builder>
{
@@ -366,5 +367,18 @@ namespace Apache.Arrow
return ValueBuffer.Span.Slice(ValueOffsets[index], GetValueLength(index));
}
+
+ int IReadOnlyCollection<byte[]>.Count => Length;
+ byte[] IReadOnlyList<byte[]>.this[int index] => GetBytes(index).ToArray();
+
+ IEnumerator<byte[]> IEnumerable<byte[]>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetBytes(index).ToArray();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<byte[]>)this).GetEnumerator();
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs b/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
index 0915338fe6..e9c5f8979e 100644
--- a/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
@@ -16,11 +16,12 @@
using Apache.Arrow.Memory;
using Apache.Arrow.Types;
using System;
+using System.Collections;
using System.Collections.Generic;
namespace Apache.Arrow
{
- public class BooleanArray: Array
+ public class BooleanArray: Array, IReadOnlyList<bool?>
{
public class Builder : IArrowArrayBuilder<bool, BooleanArray, Builder>
{
@@ -190,5 +191,19 @@ namespace Apache.Arrow
? (bool?)null
: BitUtility.GetBit(ValueBuffer.Span, index + Offset);
}
+
+ int IReadOnlyCollection<bool?>.Count => Length;
+
+ bool? IReadOnlyList<bool?>.this[int index] => GetValue(index);
+
+ IEnumerator<bool?> IEnumerable<bool?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetValue(index);
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<bool?>)this).GetEnumerator();
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/Date32Array.cs b/csharp/src/Apache.Arrow/Arrays/Date32Array.cs
index 23ad7356eb..6ab4986f57 100644
--- a/csharp/src/Apache.Arrow/Arrays/Date32Array.cs
+++ b/csharp/src/Apache.Arrow/Arrays/Date32Array.cs
@@ -15,6 +15,7 @@
using Apache.Arrow.Types;
using System;
+using System.Collections.Generic;
namespace Apache.Arrow
{
@@ -22,7 +23,10 @@ namespace Apache.Arrow
/// The <see cref="Date32Array"/> class holds an array of dates in the <c>Date32</c> format, where each date is
/// stored as the number of days since the dawn of (UNIX) time.
/// </summary>
- public class Date32Array : PrimitiveArray<int>
+ public class Date32Array : PrimitiveArray<int>, IReadOnlyList<DateTime?>
+#if NET6_0_OR_GREATER
+ , IReadOnlyList<DateOnly?>
+#endif
{
private static readonly DateTime _epochDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
#if NET6_0_OR_GREATER
@@ -133,6 +137,30 @@ namespace Apache.Arrow
? DateOnly.FromDayNumber(_epochDayNumber + value.Value)
: default(DateOnly?);
}
+
+ int IReadOnlyCollection<DateOnly?>.Count => Length;
+
+ DateOnly? IReadOnlyList<DateOnly?>.this[int index] => GetDateOnly(index);
+
+ IEnumerator<DateOnly?> IEnumerable<DateOnly?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetDateOnly(index);
+ };
+ }
#endif
+
+ int IReadOnlyCollection<DateTime?>.Count => Length;
+
+ DateTime? IReadOnlyList<DateTime?>.this[int index] => GetDateTime(index);
+
+ IEnumerator<DateTime?> IEnumerable<DateTime?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetDateTime(index);
+ };
+ }
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/Date64Array.cs b/csharp/src/Apache.Arrow/Arrays/Date64Array.cs
index b0d42e27bb..43e698e10b 100644
--- a/csharp/src/Apache.Arrow/Arrays/Date64Array.cs
+++ b/csharp/src/Apache.Arrow/Arrays/Date64Array.cs
@@ -15,6 +15,7 @@
using Apache.Arrow.Types;
using System;
+using System.Collections.Generic;
namespace Apache.Arrow
{
@@ -23,7 +24,10 @@ namespace Apache.Arrow
/// stored as the number of milliseconds since the dawn of (UNIX) time, excluding leap seconds, in multiples of
/// 86400000.
/// </summary>
- public class Date64Array: PrimitiveArray<long>
+ public class Date64Array : PrimitiveArray<long>, IReadOnlyList<DateTime?>
+#if NET6_0_OR_GREATER
+ , IReadOnlyList<DateOnly?>
+#endif
{
private const long MillisecondsPerDay = 86400000;
@@ -39,7 +43,7 @@ namespace Apache.Arrow
/// </summary>
public class Builder : DateArrayBuilder<long, Date64Array, Builder>
{
- private class DateBuilder: PrimitiveArrayBuilder<long, Date64Array, DateBuilder>
+ private class DateBuilder : PrimitiveArrayBuilder<long, Date64Array, DateBuilder>
{
protected override Date64Array Build(
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
@@ -135,6 +139,30 @@ namespace Apache.Arrow
? DateOnly.FromDateTime(DateTimeOffset.FromUnixTimeMilliseconds(value.Value).UtcDateTime)
: default(DateOnly?);
}
+
+ int IReadOnlyCollection<DateOnly?>.Count => Length;
+
+ DateOnly? IReadOnlyList<DateOnly?>.this[int index] => GetDateOnly(index);
+
+ IEnumerator<DateOnly?> IEnumerable<DateOnly?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetDateOnly(index);
+ };
+ }
#endif
+
+ int IReadOnlyCollection<DateTime?>.Count => Length;
+
+ DateTime? IReadOnlyList<DateTime?>.this[int index] => GetDateTime(index);
+
+ IEnumerator<DateTime?> IEnumerable<DateTime?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetDateTime(index);
+ };
+ }
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs b/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
index 7365a77b63..0456c5cc65 100644
--- a/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
@@ -14,12 +14,13 @@
// limitations under the License.
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Apache.Arrow
{
- public abstract class PrimitiveArray<T> : Array
+ public abstract class PrimitiveArray<T> : Array, IReadOnlyList<T?>
where T : struct
{
protected PrimitiveArray(ArrayData data)
@@ -66,5 +67,24 @@ namespace Apache.Arrow
return list;
}
+
+ int IReadOnlyCollection<T?>.Count => Length;
+ T? IReadOnlyList<T?>.this[int index] => GetValue(index);
+
+ IEnumerator<T?> IEnumerable<T?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return IsValid(index) ? Values[index] : null;
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return IsValid(index) ? Values[index] : null;
+ }
+ }
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/StringArray.cs b/csharp/src/Apache.Arrow/Arrays/StringArray.cs
index 42104b2717..af77fe1b1a 100644
--- a/csharp/src/Apache.Arrow/Arrays/StringArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/StringArray.cs
@@ -15,13 +15,14 @@
using Apache.Arrow.Types;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apache.Arrow
{
- public class StringArray: BinaryArray
+ public class StringArray: BinaryArray, IReadOnlyList<string>
{
public static readonly Encoding DefaultEncoding = Encoding.UTF8;
@@ -91,5 +92,19 @@ namespace Apache.Arrow
return encoding.GetString(data, bytes.Length);
}
}
+
+ int IReadOnlyCollection<string>.Count => Length;
+
+ string IReadOnlyList<string>.this[int index] => GetString(index);
+
+ IEnumerator<string> IEnumerable<string>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetString(index);
+ };
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<string>)this).GetEnumerator();
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/Time32Array.cs b/csharp/src/Apache.Arrow/Arrays/Time32Array.cs
index 824694cd6d..e9c2d7a4d9 100644
--- a/csharp/src/Apache.Arrow/Arrays/Time32Array.cs
+++ b/csharp/src/Apache.Arrow/Arrays/Time32Array.cs
@@ -15,6 +15,7 @@
using Apache.Arrow.Types;
using System;
+using System.Collections.Generic;
using System.IO;
namespace Apache.Arrow
@@ -24,6 +25,9 @@ namespace Apache.Arrow
/// stored as the number of seconds/ milliseconds (depending on the Time32Type) since midnight.
/// </summary>
public class Time32Array : PrimitiveArray<int>
+#if NET6_0_OR_GREATER
+ , IReadOnlyList<TimeOnly?>
+#endif
{
/// <summary>
/// The <see cref="Builder"/> class can be used to fluently build <see cref="Time32Array"/> objects.
@@ -155,6 +159,18 @@ namespace Apache.Arrow
_ => throw new InvalidDataException($"Unsupported time unit for Time32Type: {unit}")
};
}
+
+ int IReadOnlyCollection<TimeOnly?>.Count => Length;
+
+ TimeOnly? IReadOnlyList<TimeOnly?>.this[int index] => GetTime(index);
+
+ IEnumerator<TimeOnly?> IEnumerable<TimeOnly?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetTime(index);
+ };
+ }
#endif
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/Time64Array.cs b/csharp/src/Apache.Arrow/Arrays/Time64Array.cs
index 3369893304..fc18dfb8bf 100644
--- a/csharp/src/Apache.Arrow/Arrays/Time64Array.cs
+++ b/csharp/src/Apache.Arrow/Arrays/Time64Array.cs
@@ -15,6 +15,7 @@
using Apache.Arrow.Types;
using System;
+using System.Collections.Generic;
using System.IO;
namespace Apache.Arrow
@@ -24,6 +25,9 @@ namespace Apache.Arrow
/// stored as the number of microseconds/nanoseconds (depending on the Time64Type) since midnight.
/// </summary>
public class Time64Array : PrimitiveArray<long>
+#if NET6_0_OR_GREATER
+ , IReadOnlyList<TimeOnly?>
+#endif
{
/// <summary>
/// The <see cref="Builder"/> class can be used to fluently build <see cref="Time64Array"/> objects.
@@ -146,6 +150,18 @@ namespace Apache.Arrow
return new TimeOnly(((Time64Type)Data.DataType).Unit.ConvertToTicks(value.Value));
}
+
+ int IReadOnlyCollection<TimeOnly?>.Count => Length;
+
+ TimeOnly? IReadOnlyList<TimeOnly?>.this[int index] => GetTime(index);
+
+ IEnumerator<TimeOnly?> IEnumerable<TimeOnly?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetTime(index);
+ };
+ }
#endif
}
}
diff --git a/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs b/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs
index 0dc5726d01..ccb656854a 100644
--- a/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs
+++ b/csharp/src/Apache.Arrow/Arrays/TimestampArray.cs
@@ -15,12 +15,13 @@
using Apache.Arrow.Types;
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace Apache.Arrow
{
- public class TimestampArray: PrimitiveArray<long>
+ public class TimestampArray : PrimitiveArray<long>, IReadOnlyList<DateTimeOffset?>
{
private static readonly DateTimeOffset s_epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
@@ -145,5 +146,16 @@ namespace Apache.Arrow
return GetTimestampUnchecked(index);
}
+ int IReadOnlyCollection<DateTimeOffset?>.Count => Length;
+
+ DateTimeOffset? IReadOnlyList<DateTimeOffset?>.this[int index] => GetTimestamp(index);
+
+ IEnumerator<DateTimeOffset?> IEnumerable<DateTimeOffset?>.GetEnumerator()
+ {
+ for (int index = 0; index < Length; index++)
+ {
+ yield return GetTimestamp(index);
+ };
+ }
}
}
diff --git a/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs b/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs
index 96918ff091..269c2390a7 100644
--- a/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs
+++ b/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs
@@ -14,6 +14,8 @@
// limitations under the License.
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Numerics;
using Xunit;
@@ -93,6 +95,33 @@ namespace Apache.Arrow.Tests
}
}
+ [Fact]
+ public void EnumerateArray()
+ {
+ var array = new Int64Array.Builder().Append(1).Append(2).Build();
+
+ foreach(long? foo in (IEnumerable<long?>)array)
+ {
+ Assert.InRange(foo.Value, 1, 2);
+ }
+
+ foreach (object foo in (IEnumerable)array)
+ {
+ Assert.InRange((long)foo, 1, 2);
+ }
+ }
+
+ [Fact]
+ public void ArrayAsReadOnlyList()
+ {
+ Int64Array array = new Int64Array.Builder().Append(1).Append(2).Build();
+ var readOnlyList = (IReadOnlyList<long?>)array;
+
+ Assert.Equal(array.Length, readOnlyList.Count);
+ Assert.Equal(readOnlyList[0], 1);
+ Assert.Equal(readOnlyList[1], 2);
+ }
+
#if NET5_0_OR_GREATER
[Fact]
public void SliceArray()