Merge pull request #208 from SaxxonPike/Enumerable-SdlArrays

Allow `foreach` enumeration over `SDLArray`
This commit is contained in:
Dan Balasescu 2025-06-06 20:03:05 +09:00 committed by GitHub
commit 23a162db1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 189 additions and 0 deletions

View File

@ -0,0 +1,117 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Runtime.InteropServices;
using NUnit.Framework;
namespace SDL.Tests
{
[TestFixture]
public class TestSDLArray
{
private static unsafe T* CopyToSdl<T>(T[] array)
where T : unmanaged
{
UIntPtr size = (UIntPtr)(Marshal.SizeOf<T>() * array.Length);
IntPtr target = SDL3.SDL_malloc(size);
fixed (T* source = array)
{
SDL3.SDL_memcpy(target, (IntPtr)source, size);
}
return (T*)target;
}
private static unsafe T** CopyToSdl<T>(T*[] array)
where T : unmanaged
{
UIntPtr size = (UIntPtr)(sizeof(IntPtr) * array.Length);
IntPtr target = SDL3.SDL_malloc(size);
fixed (T** source = array)
{
SDL3.SDL_memcpy(target, (IntPtr)source, size);
}
return (T**)target;
}
[Test]
public unsafe void TestArrayEnumerator()
{
int[] values = [10, 20, 30, 40];
int* sdlMemory = CopyToSdl(values);
using var array = new SDLArray<int>(sdlMemory, values.Length);
int index = 0;
foreach (int i in array)
{
Assert.AreEqual(values[index++], i);
}
}
[Test]
public unsafe void TestConstOpaquePointerArrayEnumerator()
{
int a = 10, b = 20, c = 30, d = 40;
int*[] values = [&a, &b, &c, &d];
int** sdlMemory = null;
// Const pointer arrays are not freed automatically. Since the
// unit test owns the memory, this must be done at the end of the
// test.
try
{
sdlMemory = CopyToSdl(values);
var array = new SDLConstOpaquePointerArray<int>(sdlMemory, values.Length);
int index = 0;
foreach (int* i in array)
{
Assert.AreEqual((IntPtr)values[index++], (IntPtr)i);
}
}
finally
{
if (sdlMemory != null)
SDL3.SDL_free(sdlMemory);
}
}
[Test]
public unsafe void TestOpaquePointerArrayEnumerator()
{
int a = 10, b = 20, c = 30, d = 40;
int*[] values = [&a, &b, &c, &d];
int** sdlMemory = CopyToSdl(values);
using var array = new SDLOpaquePointerArray<int>(sdlMemory, values.Length);
int index = 0;
foreach (int* i in array)
{
Assert.AreEqual((IntPtr)values[index++], (IntPtr)i);
}
}
[Test]
public unsafe void TestPointerArrayEnumerator()
{
int a = 10, b = 20, c = 30, d = 40;
int*[] values = [&a, &b, &c, &d];
int** memory = CopyToSdl(values);
using var array = new SDLPointerArray<int>(memory, values.Length);
int index = 0;
foreach (int i in array)
{
Assert.AreEqual(*values[index++], i);
}
}
}
}

View File

@ -40,6 +40,24 @@ namespace SDL
SDL3.SDL_free(array); SDL3.SDL_free(array);
} }
public Enumerator GetEnumerator() => new Enumerator(this);
public ref struct Enumerator
{
private readonly SDLArray<T> array;
private int index;
internal Enumerator(SDLArray<T> array)
{
this.array = array;
index = -1;
}
public bool MoveNext() => ++index < array.Count;
public T Current => array[index];
}
} }
internal static unsafe class SDLArray internal static unsafe class SDLArray

View File

@ -28,5 +28,23 @@ namespace SDL
return array[index]; return array[index];
} }
} }
public Enumerator GetEnumerator() => new Enumerator(this);
public ref struct Enumerator
{
private readonly SDLConstOpaquePointerArray<T> array;
private int index;
internal Enumerator(SDLConstOpaquePointerArray<T> array)
{
this.array = array;
index = -1;
}
public bool MoveNext() => ++index < array.Count;
public T* Current => array[index];
}
} }
} }

View File

@ -42,5 +42,23 @@ namespace SDL
SDL3.SDL_free(array); SDL3.SDL_free(array);
} }
public Enumerator GetEnumerator() => new Enumerator(this);
public ref struct Enumerator
{
private readonly SDLOpaquePointerArray<T> array;
private int index;
internal Enumerator(SDLOpaquePointerArray<T> array)
{
this.array = array;
index = -1;
}
public bool MoveNext() => ++index < array.Count;
public T* Current => array[index];
}
} }
} }

View File

@ -43,5 +43,23 @@ namespace SDL
SDL3.SDL_free(array); SDL3.SDL_free(array);
} }
public Enumerator GetEnumerator() => new Enumerator(this);
public ref struct Enumerator
{
private readonly SDLPointerArray<T> array;
private int index;
internal Enumerator(SDLPointerArray<T> array)
{
this.array = array;
index = -1;
}
public bool MoveNext() => ++index < array.Count;
public T Current => array[index];
}
} }
} }