Skip to content

Improve method binding #974

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

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
list wrapper
  • Loading branch information
koubaa committed Dec 8, 2019
commit e63d11edc73f7fa197e76681e0316124d53b77c2
201 changes: 201 additions & 0 deletions src/runtime/ListWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Python.Runtime {
/// <summary>
/// Implements IEnumerable<typeparamref name="T"/> for any python iterable.
/// </summary>
internal class IterableWrapper<T> : IEnumerable<T> {
private IntPtr iterObject;

public IterableWrapper(IntPtr value) {
iterObject = Runtime.PyObject_GetIter(value);
if (iterObject == IntPtr.Zero)
Exceptions.RaiseTypeError("not an iterator");
Runtime.XIncref(iterObject);
}
~IterableWrapper() {
Runtime.XDecref(iterObject);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't use XDecref directly in destructor, see Runtime.PyObject's destructor, you can just refer a PyObject, it can let you have no need concern about about the release.

}

public IEnumerator<T> GetEnumerator() {
return GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator() {
IntPtr item;
while ((item = Runtime.PyIter_Next(iterObject)) != IntPtr.Zero) {
object obj = null;
if (!Converter.ToManaged(item, typeof(T), out obj, true)) {
Runtime.XDecref(item);
Runtime.XDecref(iterObject);
Exceptions.RaiseTypeError("wrong type in sequence");
}

Runtime.XDecref(item);
yield return obj;
}
}
}

/// <summary>
/// Implements IList<typeparamref name="T"/> for any python sequence.
/// Some methods/properties are only available on certaintypes of sequences, like list
/// </summary>
internal class ListWrapper<T> : IterableWrapper<T>, IList<T>
{
private IntPtr seq;
public ListWrapper(IntPtr value) : base(value)
{
this.seq = value;
Runtime.XIncref(value);
bool IsSeqObj = Runtime.PySequence_Check(value);
if (!IsSeqObj)
Exceptions.RaiseTypeError("not a sequence");

}
~ListWrapper()
{
Runtime.XDecref(seq);
}
public T this[int index]
{
get
{
IntPtr item = Runtime.PySequence_GetItem(seq, index);
object obj;

if (!Converter.ToManaged(item, typeof(T), out obj, true)) {
Runtime.XDecref(item);
Exceptions.RaiseTypeError("wrong type in sequence");
}

return (T)obj;
}
set
{
IntPtr pyItem = Converter.ToPython(value, typeof(T));
if (pyItem == IntPtr.Zero)
throw new Exception("failed to set item");

var result = Runtime.PySequence_SetItem(seq, index, pyItem);
Runtime.XDecref(pyItem);
if (result == -1)
throw new Exception("failed to set item");
}
}

public int Count
{
get
{
var len = Runtime.PySequence_Size(seq);
return (int)len;
}
}

public bool IsReadOnly
{
get
{
return Runtime.PyTuple_Check(seq); //python tuples are immutable
}

}

public void Add(T item) {
if (IsReadOnly)
throw new NotImplementedException();

//only implemented if this is a list!
if (!Runtime.PyList_Check(seq))
throw new NotImplementedException();

IntPtr pyItem = Converter.ToPython(item, typeof(T));
if (pyItem == IntPtr.Zero)
throw new Exception("failed to add item");

var result = Runtime.PyList_Append(seq, pyItem);
Runtime.XDecref(pyItem);
if (result == -1)
throw new Exception("failed to add item");
}

public void Clear() {
if (IsReadOnly)
throw new NotImplementedException();
var result = Runtime.PySequence_DelSlice(seq, 0, Count);
if (result == -1)
throw new Exception("failed to clear sequence");
}

public bool Contains(T item)
{
//not sure if IEquatable is implemented and this will work!
foreach (var element in this)
if (element.Equals(item)) return true;

return false;
}

public void CopyTo(T[] array, int arrayIndex)
{
for (int index = 0; index < Count; index++)
{
array[index + arrayIndex] = this[index];
}
}

public int IndexOf(T item) {
var index = 0;
foreach (var element in this) {
if (element.Equals(item)) return index;
index++;
}

return -1;
}

public void Insert(int index, T item)
{
if (IsReadOnly)
throw new NotImplementedException();

//only implemented if this is a list!
if (!Runtime.PyList_Check(seq))
throw new NotImplementedException();

IntPtr pyItem = Converter.ToPython(item, typeof(T));
if (pyItem == IntPtr.Zero)
throw new Exception("failed to insert item");

var result = Runtime.PyList_Insert(seq, index, pyItem);
Runtime.XDecref(pyItem);
if (result == -1)
throw new Exception("failed to insert item");
}

public bool InternalRemoveAt(int index)
{
if (IsReadOnly)
throw new NotImplementedException();
if (index >= Count || index < 0)
throw new IndexOutOfRangeException();

return Runtime.PySequence_DelItem(seq, index) != 0;
}

public bool Remove(T item)
{
return InternalRemoveAt(IndexOf(item));
}

public void RemoveAt(int index)
{
InternalRemoveAt(index);
}
}
}
63 changes: 36 additions & 27 deletions src/runtime/converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Runtime.InteropServices;
using System.Security;
using System.ComponentModel;
using System.Linq;

namespace Python.Runtime
{
Expand Down Expand Up @@ -268,7 +269,6 @@ internal static IntPtr ToPythonImplicit(object value)
return ToPython(value, objectType);
}


/// <summary>
/// Return a managed object for the given Python object, taking funny
/// byref types into account.
Expand Down Expand Up @@ -868,35 +868,34 @@ private static bool ToListOfT(IntPtr value, Type elementType, out object result)
{
result = null;

bool IsSeqObj = Runtime.PySequence_Check(value);
var len = IsSeqObj ? Runtime.PySequence_Size(value) : -1;

IntPtr IterObject = Runtime.PyObject_GetIter(value);

if (IterObject == IntPtr.Zero)
IntPtr iterObject = Runtime.PyObject_GetIter(value);
if (iterObject == IntPtr.Zero)
return false;

var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(elementType);
IList list = IsSeqObj ? (IList) Activator.CreateInstance(constructedListType, new Object[] { (int)len }) :
(IList) Activator.CreateInstance(constructedListType);
IntPtr item;

while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero)
{
object obj = null;
bool IsSeqObj = Runtime.PySequence_Check(value);

if (!Converter.ToManaged(item, elementType, out obj, true))
{
Runtime.XDecref(item);
return false;
try {
Type[] typeArgs = { elementType };
if (IsSeqObj) {
var listType = typeof(ListWrapper<>);
object listObj = Activator.CreateInstance(listType.MakeGenericType(typeArgs), new Object[] { value });
//IList list = (IList)Activator.CreateInstance(fullListType, new Object[] { value });

result = listObj;
}
else {
var listType = typeof(IterableWrapper<>);
IEnumerable list = (IEnumerable)Activator.CreateInstance(listType.MakeGenericType(typeArgs), new Object[] { value });
result = list;
}
}
catch (Exception) {
return false;

list.Add(obj);
Runtime.XDecref(item);
}
Runtime.XDecref(IterObject);
result = list;
finally {
Runtime.XDecref(iterObject);
}
return true;
}

Expand All @@ -917,10 +916,18 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s
return false;
}

IList list = (IList)result;
IList list = result as IList;
if (list == null) {
IEnumerable enumerable = (IEnumerable)result;
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(elementType);
list = (IList)Activator.CreateInstance(constructedListType);
foreach (var item in enumerable) {
list.Add(item);
}
}
Array items = Array.CreateInstance(elementType, list.Count);
list.CopyTo(items, 0);

result = items;
return true;

Expand All @@ -947,14 +954,16 @@ private static bool ToAction(IntPtr value, Type obType, out object result, bool
}

Action action = () => {
var y = Runtime.Refcount(value);
PyObject py_action = new PyObject(value);
var py_args = new PyObject[0];
var py_result = py_action.Invoke(py_args);
Runtime.XDecref(value);
};

var x = Runtime.Refcount(value);
Runtime.XIncref(value);
result = action;

return true;
}

Expand Down