-
Notifications
You must be signed in to change notification settings - Fork 775
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
Changes from 1 commit
21528ee
b4d60c6
3f02abf
9c3e1c5
b9db0f6
4b0a1ad
8bed1bb
a4599d9
96fd896
c6fd768
e63d11e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| 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); | ||
| } | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| using System.Runtime.InteropServices; | ||
| using System.Security; | ||
| using System.ComponentModel; | ||
| using System.Linq; | ||
|
|
||
| namespace Python.Runtime | ||
| { | ||
|
|
@@ -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. | ||
|
|
@@ -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; | ||
| } | ||
|
|
||
|
|
@@ -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; | ||
|
|
||
|
|
@@ -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); | ||
| }; | ||
|
Comment on lines
+948
to
+962
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The object pointed to by
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had forgotten to push the latest change set, please check again |
||
|
|
||
| var x = Runtime.Refcount(value); | ||
| Runtime.XIncref(value); | ||
| result = action; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't use
XDecrefdirectly in destructor, seeRuntime.PyObject's destructor, you can just refer aPyObject, it can let you have no need concern about about the release.