diff options
author | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2018-07-18 23:07:57 +0200 |
---|---|---|
committer | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2018-07-20 01:44:30 +0200 |
commit | ee3c476c9a8a3be949252468570e75f35fea2697 (patch) | |
tree | 2baeb0d948acb10fc15f15c026ef9af0699d2ce8 /modules/mono/glue/cs_files | |
parent | 2f69e36cef8acca00ec5445f4aa8ec538bb38e3e (diff) |
Add Array and Dictionary wrapper classes to C#
Diffstat (limited to 'modules/mono/glue/cs_files')
-rw-r--r-- | modules/mono/glue/cs_files/Array.cs | 335 | ||||
-rw-r--r-- | modules/mono/glue/cs_files/Dictionary.cs | 401 | ||||
-rw-r--r-- | modules/mono/glue/cs_files/MarshalUtils.cs | 29 |
3 files changed, 741 insertions, 24 deletions
diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs new file mode 100644 index 0000000000..51f57daef4 --- /dev/null +++ b/modules/mono/glue/cs_files/Array.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Godot +{ + class ArraySafeHandle : SafeHandle + { + public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) + { + this.handle = handle; + } + + public override bool IsInvalid + { + get + { + return handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + Array.godot_icall_Array_Dtor(handle); + return true; + } + } + + public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable + { + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Array_Ctor(); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Dtor(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Array_At(IntPtr ptr, int index); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Array_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Add(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Clear(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index); + + ArraySafeHandle safeHandle; + bool disposed = false; + + public Array() + { + safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor()); + } + + internal Array(ArraySafeHandle handle) + { + safeHandle = handle; + } + + internal Array(IntPtr handle) + { + safeHandle = new ArraySafeHandle(handle); + } + + internal IntPtr GetPtr() + { + return safeHandle.DangerousGetHandle(); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (safeHandle != null) + { + safeHandle.Dispose(); + safeHandle = null; + } + + disposed = true; + } + + public object this[int index] + { + get + { + return godot_icall_Array_At(GetPtr(), index); + } + set + { + godot_icall_Array_SetAt(GetPtr(), index, value); + } + } + + public int Count + { + get + { + return godot_icall_Array_Count(GetPtr()); + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public void Add(object item) + { + godot_icall_Array_Add(GetPtr(), item); + } + + public void Clear() + { + godot_icall_Array_Clear(GetPtr()); + } + + public bool Contains(object item) + { + return godot_icall_Array_Contains(GetPtr(), item); + } + + public void CopyTo(object[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "Value cannot be null."); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); + + // Internal call may throw ArgumentException + godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex); + } + + public IEnumerator<object> GetEnumerator() + { + int count = Count; + + for (int i = 0; i < count; i++) + { + yield return godot_icall_Array_At(GetPtr(), i); + } + } + + public int IndexOf(object item) + { + return godot_icall_Array_IndexOf(GetPtr(), item); + } + + public void Insert(int index, object item) + { + godot_icall_Array_Insert(GetPtr(), index, item); + } + + public bool Remove(object item) + { + return godot_icall_Array_Remove(GetPtr(), item); + } + + public void RemoveAt(int index) + { + godot_icall_Array_RemoveAt(GetPtr(), index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> + { + Array objectArray; + + public Array() + { + objectArray = new Array(); + } + + public Array(Array array) + { + objectArray = array; + } + + internal Array(IntPtr handle) + { + objectArray = new Array(handle); + } + + internal Array(ArraySafeHandle handle) + { + objectArray = new Array(handle); + } + + public static explicit operator Array(Array<T> from) + { + return from.objectArray; + } + + public T this[int index] + { + get + { + return (T)objectArray[index]; + } + set + { + objectArray[index] = value; + } + } + + public int Count + { + get + { + return objectArray.Count; + } + } + + public bool IsReadOnly + { + get + { + return objectArray.IsReadOnly; + } + } + + public void Add(T item) + { + objectArray.Add(item); + } + + public void Clear() + { + objectArray.Clear(); + } + + public bool Contains(T item) + { + return objectArray.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "Value cannot be null."); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); + + // TODO This may be quite slow because every element access is an internal call. + // It could be moved entirely to an internal call if we find out how to do the cast there. + + int count = objectArray.Count; + + if (array.Length < (arrayIndex + count)) + throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); + + for (int i = 0; i < count; i++) + { + array[arrayIndex] = (T)objectArray[i]; + arrayIndex++; + } + } + + public IEnumerator<T> GetEnumerator() + { + int count = objectArray.Count; + + for (int i = 0; i < count; i++) + { + yield return (T)objectArray[i]; + } + } + + public int IndexOf(T item) + { + return objectArray.IndexOf(item); + } + + public void Insert(int index, T item) + { + objectArray.Insert(index, item); + } + + public bool Remove(T item) + { + return objectArray.Remove(item); + } + + public void RemoveAt(int index) + { + objectArray.RemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs new file mode 100644 index 0000000000..57a1960ad9 --- /dev/null +++ b/modules/mono/glue/cs_files/Dictionary.cs @@ -0,0 +1,401 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Godot +{ + class DictionarySafeHandle : SafeHandle + { + public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) + { + this.handle = handle; + } + + public override bool IsInvalid + { + get + { + return handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + Dictionary.godot_icall_Dictionary_Dtor(handle); + return true; + } + } + + public class Dictionary : + IDictionary<object, object>, + ICollection<KeyValuePair<object, object>>, + IEnumerable<KeyValuePair<object, object>>, + IDisposable + { + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Ctor(); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Dictionary_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); + + DictionarySafeHandle safeHandle; + bool disposed = false; + + public Dictionary() + { + safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor()); + } + + internal Dictionary(DictionarySafeHandle handle) + { + safeHandle = handle; + } + + internal Dictionary(IntPtr handle) + { + safeHandle = new DictionarySafeHandle(handle); + } + + internal IntPtr GetPtr() + { + return safeHandle.DangerousGetHandle(); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (safeHandle != null) + { + safeHandle.Dispose(); + safeHandle = null; + } + + disposed = true; + } + + public object this[object key] + { + get + { + return godot_icall_Dictionary_GetValue(GetPtr(), key); + } + set + { + godot_icall_Dictionary_SetValue(GetPtr(), key, value); + } + } + + public ICollection<object> Keys + { + get + { + IntPtr handle = godot_icall_Dictionary_Keys(GetPtr()); + return new Array(new ArraySafeHandle(handle)); + } + } + + public ICollection<object> Values + { + get + { + IntPtr handle = godot_icall_Dictionary_Values(GetPtr()); + return new Array(new ArraySafeHandle(handle)); + } + } + + public int Count + { + get + { + return godot_icall_Dictionary_Count(GetPtr()); + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public void Add(object key, object value) + { + godot_icall_Dictionary_Add(GetPtr(), key, value); + } + + public void Add(KeyValuePair<object, object> item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + godot_icall_Dictionary_Clear(GetPtr()); + } + + public bool Contains(KeyValuePair<object, object> item) + { + return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value); + } + + public bool ContainsKey(object key) + { + return godot_icall_Dictionary_ContainsKey(GetPtr(), key); + } + + public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex) + { + // TODO 3 internal calls, can reduce to 1 + Array keys = (Array)Keys; + Array values = (Array)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]); + arrayIndex++; + } + } + + public IEnumerator<KeyValuePair<object, object>> GetEnumerator() + { + // TODO 3 internal calls, can reduce to 1 + Array keys = (Array)Keys; + Array values = (Array)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + yield return new KeyValuePair<object, object>(keys[i], values[i]); + } + } + + public bool Remove(object key) + { + return godot_icall_Dictionary_RemoveKey(GetPtr(), key); + } + + public bool Remove(KeyValuePair<object, object> item) + { + return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); + } + + public bool TryGetValue(object key, out object value) + { + object retValue; + bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue); + value = found ? retValue : default(object); + return found; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + + public class Dictionary<TKey, TValue> : + IDictionary<TKey, TValue>, + ICollection<KeyValuePair<TKey, TValue>>, + IEnumerable<KeyValuePair<TKey, TValue>> + { + Dictionary objectDict; + + public Dictionary() + { + objectDict = new Dictionary(); + } + + public Dictionary(Dictionary dictionary) + { + objectDict = dictionary; + } + + internal Dictionary(IntPtr handle) + { + objectDict = new Dictionary(handle); + } + + internal Dictionary(DictionarySafeHandle handle) + { + objectDict = new Dictionary(handle); + } + + public static explicit operator Dictionary(Dictionary<TKey, TValue> from) + { + return from.objectDict; + } + + public TValue this[TKey key] + { + get + { + return (TValue)objectDict[key]; + } + set + { + objectDict[key] = value; + } + } + + public ICollection<TKey> Keys + { + get + { + IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr()); + return new Array<TKey>(new ArraySafeHandle(handle)); + } + } + + public ICollection<TValue> Values + { + get + { + IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr()); + return new Array<TValue>(new ArraySafeHandle(handle)); + } + } + + public int Count + { + get + { + return objectDict.Count; + } + } + + public bool IsReadOnly + { + get + { + return objectDict.IsReadOnly; + } + } + + public void Add(TKey key, TValue value) + { + objectDict.Add(key, value); + } + + public void Add(KeyValuePair<TKey, TValue> item) + { + objectDict.Add(item.Key, item.Value); + } + + public void Clear() + { + objectDict.Clear(); + } + + public bool Contains(KeyValuePair<TKey, TValue> item) + { + return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); + } + + public bool ContainsKey(TKey key) + { + return objectDict.ContainsKey(key); + } + + public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) + { + // TODO 3 internal calls, can reduce to 1 + Array<TKey> keys = (Array<TKey>)Keys; + Array<TValue> values = (Array<TValue>)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]); + arrayIndex++; + } + } + + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { + // TODO 3 internal calls, can reduce to 1 + Array<TKey> keys = (Array<TKey>)Keys; + Array<TValue> values = (Array<TValue>)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]); + } + } + + public bool Remove(TKey key) + { + return objectDict.Remove(key); + } + + public bool Remove(KeyValuePair<TKey, TValue> item) + { + return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value)); + } + + public bool TryGetValue(TKey key, out TValue value) + { + object retValue; + bool found = objectDict.TryGetValue(key, out retValue); + value = found ? (TValue)retValue : default(TValue); + return found; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/cs_files/MarshalUtils.cs index ff4477cc6c..6ad4b3dcb2 100644 --- a/modules/mono/glue/cs_files/MarshalUtils.cs +++ b/modules/mono/glue/cs_files/MarshalUtils.cs @@ -1,36 +1,17 @@ using System; -using System.Collections.Generic; namespace Godot { - internal static class MarshalUtils + static class MarshalUtils { - private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values) + static bool IsArrayGenericType(Type type) { - var ret = new Dictionary<object, object>(); - - for (int i = 0; i < keys.Length; i++) - { - ret.Add(keys[i], values[i]); - } - - return ret; - } - - private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo) - { - var keys = from.Keys; - keysTo = new object[keys.Count]; - keys.CopyTo(keysTo, 0); - - var values = from.Values; - valuesTo = new object[values.Count]; - values.CopyTo(valuesTo, 0); + return type.GetGenericTypeDefinition() == typeof(Array<>); } - private static Type GetDictionaryType() + static bool IsDictionaryGenericType(Type type) { - return typeof(Dictionary<object, object>); + return type.GetGenericTypeDefinition() == typeof(Dictionary<, >); } } } |