Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

preallocate based on items.Length and use PyList_SetItem #173

Closed
github-actions bot opened this issue Aug 28, 2024 · 1 comment
Closed

preallocate based on items.Length and use PyList_SetItem #173

github-actions bot opened this issue Aug 28, 2024 · 1 comment

Comments

@github-actions
Copy link

PyObject pyList = PyObject.Create(CPythonAPI.PyList_New(0)); // TODO: preallocate based on items.Length and use PyList_SetItem

using CSnakes.Runtime.CPython;
using System.Runtime.InteropServices.Marshalling;

namespace CSnakes.Runtime.Python;

/// <summary>
/// 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.
/// </summary>
internal static class Pack
{
    internal static PyObject CreateTuple(Span<PyObject> items)
    {
        List<SafeHandleMarshaller<PyObject>.ManagedToUnmanagedIn> marshallers = new(items.Length);
        try
        {
            var handles = items.Length < 18 // .NET tuples are max 17 items. This is a performance optimization.
                ? stackalloc IntPtr[items.Length]
                : new IntPtr[items.Length];

            for (int i = 0; i < items.Length; i++)
            {
                SafeHandleMarshaller<PyObject>.ManagedToUnmanagedIn m = default;
                m.FromManaged(items[i]);
                marshallers.Add(m);
                handles[i] = m.ToUnmanaged();
            }
            return PyObject.Create(CPythonAPI.PackTuple(handles));
        }
        finally
        {
            foreach (var m in marshallers)
            {
                m.Free();
            }
        }
    }

    internal static PyObject CreateList(Span<PyObject> items)
    {
        PyObject pyList = PyObject.Create(CPythonAPI.PyList_New(0)); // TODO: preallocate based on items.Length and use PyList_SetItem

        foreach (var item in items)
        {
            int result = CPythonAPI.PyList_Append(pyList, item);
            if (result == -1)
            {
                throw PyObject.ThrowPythonExceptionAsClrException();
            }
        }

        return pyList;
    }

    internal static PyObject CreateDictionary(IEnumerable<PyObject> keys,  IEnumerable<PyObject> values) {
        PyObject pyDict = PyObject.Create(CPythonAPI.PyDict_New());

        IEnumerator<PyObject> keyEnumerator = keys.GetEnumerator();
        IEnumerator<PyObject> valueEnumerator = values.GetEnumerator();

        while (keyEnumerator.MoveNext() && valueEnumerator.MoveNext())
        {
            int result = CPythonAPI.PyDict_SetItem(pyDict, keyEnumerator.Current, valueEnumerator.Current);
            if (result == -1)
            {
                throw PyObject.ThrowPythonExceptionAsClrException();
            }
        }

        return pyDict;
    }
}
Copy link
Author

Closed in 5423d6b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant