Skip to content

Commit

Permalink
apacheGH-38692: [C#] Implement ICollection<T?> on scalar arrays (apac…
Browse files Browse the repository at this point in the history
…he#41539)

### What changes are included in this PR?

This PR makes the following array types support ICollection<T?> :
- PrimitiveArray
- BooleanArray
- Date32Array
- Date64Array
- Time32Array
- Time64Array
- BinaryArray
- TimestampArray
- StringArray

### Are these changes tested?

Yes

### Are there any user-facing changes?

No

Closes apache#38692
* GitHub Issue: apache#38692

Authored-by: voidstar69 <[email protected]>
Signed-off-by: Curt Hagenlocher <[email protected]>
  • Loading branch information
voidstar69 authored May 13, 2024
1 parent 875e4df commit a715ea0
Show file tree
Hide file tree
Showing 17 changed files with 450 additions and 40 deletions.
27 changes: 26 additions & 1 deletion csharp/src/Apache.Arrow/Arrays/BinaryArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

namespace Apache.Arrow
{
public class BinaryArray : Array, IReadOnlyList<byte[]>
public class BinaryArray : Array, IReadOnlyList<byte[]>, ICollection<byte[]>
{
public class Builder : BuilderBase<BinaryArray, Builder>
{
Expand Down Expand Up @@ -380,5 +380,30 @@ IEnumerator<byte[]> IEnumerable<byte[]>.GetEnumerator()
}

IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<byte[]>)this).GetEnumerator();

int ICollection<byte[]>.Count => Length;
bool ICollection<byte[]>.IsReadOnly => true;
void ICollection<byte[]>.Add(byte[]? item) => throw new NotSupportedException("Collection is read-only.");

Check warning on line 386 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / ARM64 macOS 14 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 386 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / ARM64 macOS 14 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 386 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Ubuntu 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 386 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Ubuntu 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 386 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Windows 2019 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 386 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Windows 2019 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
bool ICollection<byte[]>.Remove(byte[]? item) => throw new NotSupportedException("Collection is read-only.");

Check warning on line 387 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / ARM64 macOS 14 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 387 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / ARM64 macOS 14 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 387 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Ubuntu 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 387 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Ubuntu 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 387 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Windows 2019 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 387 in csharp/src/Apache.Arrow/Arrays/BinaryArray.cs

View workflow job for this annotation

GitHub Actions / AMD64 Windows 2019 18.04 C# 8.0.x

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
void ICollection<byte[]>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<byte[]>.Contains(byte[] item)
{
for (int index = 0; index < Length; index++)
{
if (GetBytes(index).SequenceEqual(item))
return true;
}

return false;
}

void ICollection<byte[]>.CopyTo(byte[][] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetBytes(srcIndex).ToArray();
}
}
}
}
29 changes: 27 additions & 2 deletions csharp/src/Apache.Arrow/Arrays/BooleanArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

namespace Apache.Arrow
{
public class BooleanArray: Array, IReadOnlyList<bool?>
public class BooleanArray: Array, IReadOnlyList<bool?>, ICollection<bool?>
{
public class Builder : IArrowArrayBuilder<bool, BooleanArray, Builder>
{
Expand Down Expand Up @@ -188,7 +188,7 @@ public bool GetBoolean(int index)
public bool? GetValue(int index)
{
return IsNull(index)
? (bool?)null
? null
: BitUtility.GetBit(ValueBuffer.Span, index + Offset);
}

Expand All @@ -205,5 +205,30 @@ public bool GetBoolean(int index)
}

IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<bool?>)this).GetEnumerator();

int ICollection<bool?>.Count => Length;
bool ICollection<bool?>.IsReadOnly => true;
void ICollection<bool?>.Add(bool? item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<bool?>.Remove(bool? item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<bool?>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<bool?>.Contains(bool? item)
{
for (int index = 0; index < Length; index++)
{
if (GetValue(index).Equals(item))
return true;
}

return false;
}

void ICollection<bool?>.CopyTo(bool?[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetValue(srcIndex);
}
}
}
}
63 changes: 56 additions & 7 deletions csharp/src/Apache.Arrow/Arrays/Date32Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ 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>, IReadOnlyList<DateTime?>
public class Date32Array : PrimitiveArray<int>, IReadOnlyList<DateTime?>, ICollection<DateTime?>
#if NET6_0_OR_GREATER
, IReadOnlyList<DateOnly?>
, IReadOnlyList<DateOnly?>, ICollection<DateOnly?>
#endif
{
private static readonly DateTime _epochDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
Expand All @@ -40,10 +40,9 @@ public class Builder : DateArrayBuilder<int, Date32Array, Builder>
{
private class DateBuilder : PrimitiveArrayBuilder<int, Date32Array, DateBuilder>
{
protected override Date32Array Build(
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
int length, int nullCount, int offset) =>
new Date32Array(valueBuffer, nullBitmapBuffer, length, nullCount, offset);
protected override Date32Array Build(ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer, int length,
int nullCount, int offset) =>
new(valueBuffer, nullBitmapBuffer, length, nullCount, offset);
}

/// <summary>
Expand Down Expand Up @@ -149,6 +148,31 @@ public Date32Array(ArrayData data)
yield return GetDateOnly(index);
};
}

int ICollection<DateOnly?>.Count => Length;
bool ICollection<DateOnly?>.IsReadOnly => true;
void ICollection<DateOnly?>.Add(DateOnly? item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<DateOnly?>.Remove(DateOnly? item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<DateOnly?>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<DateOnly?>.Contains(DateOnly? item)
{
for (int index = 0; index < Length; index++)
{
if (GetDateOnly(index).Equals(item))
return true;
}

return false;
}

void ICollection<DateOnly?>.CopyTo(DateOnly?[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetDateOnly(srcIndex);
}
}
#endif

int IReadOnlyCollection<DateTime?>.Count => Length;
Expand All @@ -160,7 +184,32 @@ public Date32Array(ArrayData data)
for (int index = 0; index < Length; index++)
{
yield return GetDateTime(index);
};
}
}

int ICollection<DateTime?>.Count => Length;
bool ICollection<DateTime?>.IsReadOnly => true;
void ICollection<DateTime?>.Add(DateTime? item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<DateTime?>.Remove(DateTime? item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<DateTime?>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<DateTime?>.Contains(DateTime? item)
{
for (int index = 0; index < Length; index++)
{
if (GetDateTime(index).Equals(item))
return true;
}

return false;
}

void ICollection<DateTime?>.CopyTo(DateTime?[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetDateTime(srcIndex);
}
}
}
}
63 changes: 56 additions & 7 deletions csharp/src/Apache.Arrow/Arrays/Date64Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ 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>, IReadOnlyList<DateTime?>
public class Date64Array : PrimitiveArray<long>, IReadOnlyList<DateTime?>, ICollection<DateTime?>
#if NET6_0_OR_GREATER
, IReadOnlyList<DateOnly?>
, IReadOnlyList<DateOnly?>, ICollection<DateOnly?>
#endif
{
private const long MillisecondsPerDay = 86400000;
Expand All @@ -45,10 +45,9 @@ public class Builder : DateArrayBuilder<long, Date64Array, Builder>
{
private class DateBuilder : PrimitiveArrayBuilder<long, Date64Array, DateBuilder>
{
protected override Date64Array Build(
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
int length, int nullCount, int offset) =>
new Date64Array(valueBuffer, nullBitmapBuffer, length, nullCount, offset);
protected override Date64Array Build(ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer, int length,
int nullCount, int offset) =>
new(valueBuffer, nullBitmapBuffer, length, nullCount, offset);
}

/// <summary>
Expand Down Expand Up @@ -151,6 +150,31 @@ public Date64Array(ArrayData data)
yield return GetDateOnly(index);
};
}

int ICollection<DateOnly?>.Count => Length;
bool ICollection<DateOnly?>.IsReadOnly => true;
void ICollection<DateOnly?>.Add(DateOnly? item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<DateOnly?>.Remove(DateOnly? item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<DateOnly?>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<DateOnly?>.Contains(DateOnly? item)
{
for (int index = 0; index < Length; index++)
{
if (GetDateOnly(index).Equals(item))
return true;
}

return false;
}

void ICollection<DateOnly?>.CopyTo(DateOnly?[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetDateOnly(srcIndex);
}
}
#endif

int IReadOnlyCollection<DateTime?>.Count => Length;
Expand All @@ -162,7 +186,32 @@ public Date64Array(ArrayData data)
for (int index = 0; index < Length; index++)
{
yield return GetDateTime(index);
};
}
}

int ICollection<DateTime?>.Count => Length;
bool ICollection<DateTime?>.IsReadOnly => true;
void ICollection<DateTime?>.Add(DateTime? item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<DateTime?>.Remove(DateTime? item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<DateTime?>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<DateTime?>.Contains(DateTime? item)
{
for (int index = 0; index < Length; index++)
{
if (GetDateTime(index).Equals(item))
return true;
}

return false;
}

void ICollection<DateTime?>.CopyTo(DateTime?[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetDateTime(srcIndex);
}
}
}
}
2 changes: 1 addition & 1 deletion csharp/src/Apache.Arrow/Arrays/IntervalArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal static class IntervalArray
}

public abstract class IntervalArray<T> : PrimitiveArray<T>
where T : struct
where T : struct, IEquatable<T>
{
protected IntervalArray(ArrayData data)
: base(data)
Expand Down
37 changes: 34 additions & 3 deletions csharp/src/Apache.Arrow/Arrays/PrimitiveArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

namespace Apache.Arrow
{
public abstract class PrimitiveArray<T> : Array, IReadOnlyList<T?>
where T : struct
public abstract class PrimitiveArray<T> : Array, IReadOnlyList<T?>, ICollection<T?>
where T : struct, IEquatable<T>
{
protected PrimitiveArray(ArrayData data)
: base(data)
Expand All @@ -40,7 +40,7 @@ protected PrimitiveArray(ArrayData data)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
return IsValid(index) ? Values[index] : (T?)null;
return IsValid(index) ? Values[index] : null;
}

public IList<T?> ToList(bool includeNulls = false)
Expand Down Expand Up @@ -86,5 +86,36 @@ IEnumerator IEnumerable.GetEnumerator()
yield return IsValid(index) ? Values[index] : null;
}
}

int ICollection<T?>.Count => Length;
bool ICollection<T?>.IsReadOnly => true;
void ICollection<T?>.Add(T? item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<T?>.Remove(T? item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<T?>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<T?>.Contains(T? item)
{
if (item == null)
{
return NullCount > 0;
}

ReadOnlySpan<T> values = Values;
while (values.Length > 0)
{
int index = Values.IndexOf(item.Value);
if (index < 0 || IsValid(index)) { return index >= 0; }
values = values.Slice(index + 1);
}
return false;
}

void ICollection<T?>.CopyTo(T?[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetValue(srcIndex);
}
}
}
}
2 changes: 1 addition & 1 deletion csharp/src/Apache.Arrow/Arrays/PrimitiveArrayBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

namespace Apache.Arrow
{
public abstract class PrimitiveArrayBuilder<TFrom, TTo, TArray, TBuilder> : IArrowArrayBuilder<TArray, TBuilder>
public abstract class PrimitiveArrayBuilder<TFrom, TTo, TArray, TBuilder> : IArrowArrayBuilder<TFrom, TArray, TBuilder>
where TTo : struct
where TArray : IArrowArray
where TBuilder : class, IArrowArrayBuilder<TArray>
Expand Down
27 changes: 26 additions & 1 deletion csharp/src/Apache.Arrow/Arrays/StringArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

namespace Apache.Arrow
{
public class StringArray: BinaryArray, IReadOnlyList<string>
public class StringArray: BinaryArray, IReadOnlyList<string>, ICollection<string>
{
public static readonly Encoding DefaultEncoding = Encoding.UTF8;

Expand Down Expand Up @@ -164,5 +164,30 @@ IEnumerator<string> IEnumerable<string>.GetEnumerator()
}

IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<string>)this).GetEnumerator();

int ICollection<string>.Count => Length;
bool ICollection<string>.IsReadOnly => true;
void ICollection<string>.Add(string item) => throw new NotSupportedException("Collection is read-only.");
bool ICollection<string>.Remove(string item) => throw new NotSupportedException("Collection is read-only.");
void ICollection<string>.Clear() => throw new NotSupportedException("Collection is read-only.");

bool ICollection<string>.Contains(string item)
{
for (int index = 0; index < Length; index++)
{
if (GetString(index) == item)
return true;
}

return false;
}

void ICollection<string>.CopyTo(string[] array, int arrayIndex)
{
for (int srcIndex = 0, destIndex = arrayIndex; srcIndex < Length; srcIndex++, destIndex++)
{
array[destIndex] = GetString(srcIndex);
}
}
}
}
Loading

0 comments on commit a715ea0

Please sign in to comment.