Add memory safe IDisposable overloads to array-returning functions

This could be done with a source generator, but this is simpler.
This commit is contained in:
Susko3 2024-04-06 14:20:08 +02:00
parent 9a5d2e4dbc
commit 75db9b16c1
13 changed files with 248 additions and 0 deletions

View File

@ -58,5 +58,19 @@ namespace SDL
[Macro]
public static int SDL_AUDIO_FRAMESIZE(SDL_AudioSpec x) => SDL_AUDIO_BYTESIZE((x).format) * (x).channels;
public static unsafe SDLArray<SDL_AudioDeviceID>? SDL_GetAudioOutputDevices()
{
int count;
var array = SDL_GetAudioOutputDevices(&count);
return SDLArray.Create(array, count);
}
public static unsafe SDLArray<SDL_AudioDeviceID>? SDL_GetAudioCaptureDevices()
{
int count;
var array = SDL_GetAudioCaptureDevices(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -7,4 +7,21 @@ namespace SDL
{
[Typedef]
public enum SDL_CameraDeviceID : UInt32;
public static partial class SDL3
{
public static unsafe SDLArray<SDL_CameraDeviceID>? SDL_GetCameraDevices()
{
int count;
var array = SDL_GetCameraDevices(&count);
return SDLArray.Create(array, count);
}
public static unsafe SDLArray<SDL_CameraSpec>? SDL_GetCameraDeviceSupportedFormats(SDL_CameraDeviceID devid)
{
int count;
var array = SDL_GetCameraDeviceSupportedFormats(devid, &count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -0,0 +1,35 @@
// 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;
using System.Runtime.InteropServices;
namespace SDL
{
public static partial class SDL3
{
/// <returns>
/// An array of <see cref="nint"/> that can be passed to <see cref="Marshal.PtrToStringUTF8(System.IntPtr)"/>.
/// </returns>
public static unsafe SDLArray<IntPtr>? SDL_GetGamepadMappings()
{
int count;
IntPtr* array = (IntPtr*)SDL_GetGamepadMappings(&count);
return SDLArray.Create(array, count);
}
public static unsafe SDLArray<SDL_JoystickID>? SDL_GetGamepads()
{
int count;
var array = SDL_GetGamepads(&count);
return SDLArray.Create(array, count);
}
public static unsafe SDLPointerArray<SDL_GamepadBinding>? SDL_GetGamepadBindings(SDL_Gamepad* gamepad)
{
int count;
var array = SDL_GetGamepadBindings(gamepad, &count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -7,4 +7,14 @@ namespace SDL
{
[Typedef]
public enum SDL_HapticID : UInt32;
public static partial class SDL3
{
public static unsafe SDLArray<SDL_HapticID>? SDL_GetHaptics()
{
int count;
var array = SDL_GetHaptics(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -7,4 +7,14 @@ namespace SDL
{
[Typedef]
public enum SDL_JoystickID : UInt32;
public static partial class SDL3
{
public static unsafe SDLArray<SDL_JoystickID>? SDL_GetJoysticks()
{
int count;
var array = SDL_GetJoysticks(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -12,4 +12,14 @@ namespace SDL
{
public SDL_Keymod Mod => (SDL_Keymod)mod;
}
public static partial class SDL3
{
public static unsafe SDLArray<SDL_KeyboardID>? SDL_GetKeyboards()
{
int count;
var array = SDL_GetKeyboards(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -31,5 +31,12 @@ namespace SDL
{
[Macro]
public static SDLButtonMask SDL_BUTTON(SDLButton button) => (SDLButtonMask)(1 << ((int)button - 1));
public static unsafe SDLArray<SDL_MouseID>? SDL_GetMice()
{
int count;
var array = SDL_GetMice(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -33,5 +33,12 @@ namespace SDL
[Macro]
public static SDL_PEN_CAPABILITIES SDL_PEN_AXIS_CAPABILITY(SDL_PenAxis axis) => SDL_PEN_CAPABILITY((int)axis + SDL_PEN_FLAG_AXIS_BIT_OFFSET);
public static unsafe SDLArray<SDL_PenID>? SDL_GetPens()
{
int count;
var array = SDL_GetPens(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -7,4 +7,14 @@ namespace SDL
{
[Typedef]
public enum SDL_SensorID : UInt32;
public static partial class SDL3
{
public static unsafe SDLArray<SDL_SensorID>? SDL_GetSensors()
{
int count;
var array = SDL_GetSensors(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -18,5 +18,12 @@ namespace SDL
[Constant]
public const SDL_TouchID SDL_MOUSE_TOUCHID = unchecked((SDL_TouchID)(-1));
public static unsafe SDLArray<SDL_TouchID>? SDL_GetTouchDevices()
{
int count;
var array = SDL_GetTouchDevices(&count);
return SDLArray.Create(array, count);
}
}
}

View File

@ -53,5 +53,19 @@ namespace SDL
[Macro]
public static bool SDL_WINDOWPOS_ISCENTERED(int X) => (((X) & 0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK);
public static unsafe SDLArray<SDL_DisplayID>? SDL_GetDisplays()
{
int count;
var array = SDL_GetDisplays(&count);
return SDLArray.Create(array, count);
}
public static unsafe SDLPointerArray<SDL_DisplayMode>? SDL_GetFullscreenDisplayModes(SDL_DisplayID displayID)
{
int count;
var array = SDL_GetFullscreenDisplayModes(displayID, &count);
return SDLArray.Create(array, count);
}
}
}

63
SDL3-CS/SDLArray.cs Normal file
View File

@ -0,0 +1,63 @@
// 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;
namespace SDL
{
public sealed unsafe class SDLArray<T> : IDisposable
where T : unmanaged
{
private readonly T* array;
public readonly int Count;
private bool isDisposed;
internal SDLArray(T* array, int count)
{
this.array = array;
Count = count;
}
public T this[int index]
{
get
{
ObjectDisposedException.ThrowIf(isDisposed, this);
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count);
return array[index];
}
}
public void Dispose()
{
if (isDisposed)
return;
isDisposed = true;
SDL3.SDL_free(array);
}
}
internal static unsafe class SDLArray
{
internal static SDLArray<T>? Create<T>(T* array, int count)
where T : unmanaged
{
if (array == null)
return null;
return new SDLArray<T>(array, count);
}
internal static SDLPointerArray<T>? Create<T>(T** array, int count)
where T : unmanaged
{
if (array == null)
return null;
return new SDLPointerArray<T>(array, count);
}
}
}

View File

@ -0,0 +1,44 @@
// 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;
using System.Diagnostics;
namespace SDL
{
// T* can't be used as a type parameter, so this has to be a separate class
public sealed unsafe class SDLPointerArray<T> : IDisposable
where T : unmanaged
{
private readonly T** array;
public readonly int Count;
private bool isDisposed;
internal SDLPointerArray(T** array, int count)
{
this.array = array;
Count = count;
}
public T this[int index]
{
get
{
ObjectDisposedException.ThrowIf(isDisposed, this);
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count);
Debug.Assert(array[index] != null);
return *array[index];
}
}
public void Dispose()
{
if (isDisposed)
return;
isDisposed = true;
SDL3.SDL_free(array);
}
}
}