From d584188675c6c56c5dea392cfbc24fdcd8bddbba Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Wed, 18 Sep 2024 14:05:59 +0200 Subject: [PATCH] Use function pointers interface of static interfaces --- src/CSnakes.Runtime/Python/Pack.cs | 46 +++++++----------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/src/CSnakes.Runtime/Python/Pack.cs b/src/CSnakes.Runtime/Python/Pack.cs index 8800d7d3..d4bffa32 100644 --- a/src/CSnakes.Runtime/Python/Pack.cs +++ b/src/CSnakes.Runtime/Python/Pack.cs @@ -5,47 +5,21 @@ namespace CSnakes.Runtime.Python; /// -/// These methods are used internally to create a PyObject where the Dispose() call will dispose all items in +/// These methods are used internally to create a PyObject where the Dispose() call will dispose all items in /// the collection inside the same call stack. This avoids the .NET GC Finalizer thread from disposing the items /// that were created and creating a GIL contention issue when other code is running. /// internal static class Pack { - internal static PyObject CreateTuple(Span items) => - PyObject.Create(CreateListOrTuple(items)); + internal static unsafe PyObject CreateTuple(Span items) => + PyObject.Create(CreateListOrTuple(items, &CPythonAPI.PyTuple_New, &CPythonAPI.PyTuple_SetItemRaw)); - internal static PyObject CreateList(Span items) => - PyObject.Create(CreateListOrTuple(items)); + internal static unsafe PyObject CreateList(Span items) => + PyObject.Create(CreateListOrTuple(items, &CPythonAPI.PyList_New, &CPythonAPI.PyList_SetItemRaw)); - public interface IListOrTupleBuilder - { - static abstract nint New(nint size); - static abstract int SetItemRaw(nint ob, nint pos, nint o); - } - - public sealed class ListBuilder : IListOrTupleBuilder - { - // As per Python/C API docs for `PyList_New`: - // - // > If len is greater than zero, the returned list object's items are set to `NULL`. Thus - // > you cannot use abstract API functions such as `PySequence_SetItem()` or expose the - // > object to Python code before setting all items to a real object with - // > `PyList_SetItem()`. - // - // Source: https://docs.python.org/3/c-api/list.html#c.PyList_New - - public static IntPtr New(IntPtr size) => CPythonAPI.PyList_New(size); - public static int SetItemRaw(IntPtr ob, IntPtr pos, IntPtr o) => CPythonAPI.PyList_SetItemRaw(ob, pos, o); - } - - public sealed class TupleBuilder : IListOrTupleBuilder - { - public static IntPtr New(IntPtr size) => size == 0 ? CPythonAPI.GetPyEmptyTuple() : CPythonAPI.PyTuple_New(size); - public static int SetItemRaw(IntPtr ob, IntPtr pos, IntPtr o) => CPythonAPI.PyTuple_SetItemRaw(ob, pos, o); - } - - public static nint CreateListOrTuple(Span items) - where TBuilder : IListOrTupleBuilder + public static unsafe nint CreateListOrTuple(Span items, + delegate* newObject, + delegate* setItemRaw) { nint obj = 0; @@ -70,12 +44,12 @@ public static nint CreateListOrTuple(Span items) Debug.Assert(uninitializedHandles.Length == 0); - obj = TBuilder.New(items.Length); + obj = newObject(items.Length); var i = 0; foreach (var handle in handles) { - int result = TBuilder.SetItemRaw(obj, i++, handle); + int result = setItemRaw(obj, i++, handle); if (result == -1) { throw PyObject.ThrowPythonExceptionAsClrException();