Array.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. namespace Godot.Collections
  7. {
  8. class ArraySafeHandle : SafeHandle
  9. {
  10. public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
  11. {
  12. this.handle = handle;
  13. }
  14. public override bool IsInvalid
  15. {
  16. get
  17. {
  18. return handle == IntPtr.Zero;
  19. }
  20. }
  21. protected override bool ReleaseHandle()
  22. {
  23. Array.godot_icall_Array_Dtor(handle);
  24. return true;
  25. }
  26. }
  27. public class Array : IList, IDisposable
  28. {
  29. ArraySafeHandle safeHandle;
  30. bool disposed = false;
  31. public Array()
  32. {
  33. safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
  34. }
  35. public Array(IEnumerable collection) : this()
  36. {
  37. if (collection == null)
  38. throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
  39. MarshalUtils.EnumerableToArray(collection, GetPtr());
  40. }
  41. internal Array(ArraySafeHandle handle)
  42. {
  43. safeHandle = handle;
  44. }
  45. internal Array(IntPtr handle)
  46. {
  47. safeHandle = new ArraySafeHandle(handle);
  48. }
  49. internal IntPtr GetPtr()
  50. {
  51. if (disposed)
  52. throw new ObjectDisposedException(GetType().FullName);
  53. return safeHandle.DangerousGetHandle();
  54. }
  55. public Error Resize(int newSize)
  56. {
  57. return godot_icall_Array_Resize(GetPtr(), newSize);
  58. }
  59. // IDisposable
  60. public void Dispose()
  61. {
  62. if (disposed)
  63. return;
  64. if (safeHandle != null)
  65. {
  66. safeHandle.Dispose();
  67. safeHandle = null;
  68. }
  69. disposed = true;
  70. }
  71. // IList
  72. public bool IsReadOnly => false;
  73. public bool IsFixedSize => false;
  74. public object this[int index]
  75. {
  76. get => godot_icall_Array_At(GetPtr(), index);
  77. set => godot_icall_Array_SetAt(GetPtr(), index, value);
  78. }
  79. public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
  80. public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
  81. public void Clear() => godot_icall_Array_Clear(GetPtr());
  82. public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
  83. public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
  84. public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
  85. public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
  86. // ICollection
  87. public int Count => godot_icall_Array_Count(GetPtr());
  88. public object SyncRoot => this;
  89. public bool IsSynchronized => false;
  90. public void CopyTo(System.Array array, int index)
  91. {
  92. if (array == null)
  93. throw new ArgumentNullException(nameof(array), "Value cannot be null.");
  94. if (index < 0)
  95. throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
  96. // Internal call may throw ArgumentException
  97. godot_icall_Array_CopyTo(GetPtr(), array, index);
  98. }
  99. // IEnumerable
  100. public IEnumerator GetEnumerator()
  101. {
  102. int count = Count;
  103. for (int i = 0; i < count; i++)
  104. {
  105. yield return this[i];
  106. }
  107. }
  108. [MethodImpl(MethodImplOptions.InternalCall)]
  109. internal extern static IntPtr godot_icall_Array_Ctor();
  110. [MethodImpl(MethodImplOptions.InternalCall)]
  111. internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
  112. [MethodImpl(MethodImplOptions.InternalCall)]
  113. internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
  114. [MethodImpl(MethodImplOptions.InternalCall)]
  115. internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass);
  116. [MethodImpl(MethodImplOptions.InternalCall)]
  117. internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
  118. [MethodImpl(MethodImplOptions.InternalCall)]
  119. internal extern static int godot_icall_Array_Count(IntPtr ptr);
  120. [MethodImpl(MethodImplOptions.InternalCall)]
  121. internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
  122. [MethodImpl(MethodImplOptions.InternalCall)]
  123. internal extern static void godot_icall_Array_Clear(IntPtr ptr);
  124. [MethodImpl(MethodImplOptions.InternalCall)]
  125. internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
  126. [MethodImpl(MethodImplOptions.InternalCall)]
  127. internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
  128. [MethodImpl(MethodImplOptions.InternalCall)]
  129. internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
  130. [MethodImpl(MethodImplOptions.InternalCall)]
  131. internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
  132. [MethodImpl(MethodImplOptions.InternalCall)]
  133. internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
  134. [MethodImpl(MethodImplOptions.InternalCall)]
  135. internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
  136. [MethodImpl(MethodImplOptions.InternalCall)]
  137. internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
  138. [MethodImpl(MethodImplOptions.InternalCall)]
  139. internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
  140. }
  141. public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
  142. {
  143. Array objectArray;
  144. internal static int elemTypeEncoding;
  145. internal static IntPtr elemTypeClass;
  146. static Array()
  147. {
  148. Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass);
  149. }
  150. public Array()
  151. {
  152. objectArray = new Array();
  153. }
  154. public Array(IEnumerable<T> collection)
  155. {
  156. if (collection == null)
  157. throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
  158. objectArray = new Array(collection);
  159. }
  160. public Array(Array array)
  161. {
  162. objectArray = array;
  163. }
  164. internal Array(IntPtr handle)
  165. {
  166. objectArray = new Array(handle);
  167. }
  168. internal Array(ArraySafeHandle handle)
  169. {
  170. objectArray = new Array(handle);
  171. }
  172. internal IntPtr GetPtr()
  173. {
  174. return objectArray.GetPtr();
  175. }
  176. public static explicit operator Array(Array<T> from)
  177. {
  178. return from.objectArray;
  179. }
  180. public Error Resize(int newSize)
  181. {
  182. return objectArray.Resize(newSize);
  183. }
  184. // IList<T>
  185. public T this[int index]
  186. {
  187. get
  188. {
  189. return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass);
  190. }
  191. set
  192. {
  193. objectArray[index] = value;
  194. }
  195. }
  196. public int IndexOf(T item)
  197. {
  198. return objectArray.IndexOf(item);
  199. }
  200. public void Insert(int index, T item)
  201. {
  202. objectArray.Insert(index, item);
  203. }
  204. public void RemoveAt(int index)
  205. {
  206. objectArray.RemoveAt(index);
  207. }
  208. // ICollection<T>
  209. public int Count
  210. {
  211. get
  212. {
  213. return objectArray.Count;
  214. }
  215. }
  216. public bool IsReadOnly
  217. {
  218. get
  219. {
  220. return objectArray.IsReadOnly;
  221. }
  222. }
  223. public void Add(T item)
  224. {
  225. objectArray.Add(item);
  226. }
  227. public void Clear()
  228. {
  229. objectArray.Clear();
  230. }
  231. public bool Contains(T item)
  232. {
  233. return objectArray.Contains(item);
  234. }
  235. public void CopyTo(T[] array, int arrayIndex)
  236. {
  237. if (array == null)
  238. throw new ArgumentNullException(nameof(array), "Value cannot be null.");
  239. if (arrayIndex < 0)
  240. throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
  241. // TODO This may be quite slow because every element access is an internal call.
  242. // It could be moved entirely to an internal call if we find out how to do the cast there.
  243. int count = objectArray.Count;
  244. if (array.Length < (arrayIndex + count))
  245. throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
  246. for (int i = 0; i < count; i++)
  247. {
  248. array[arrayIndex] = (T)this[i];
  249. arrayIndex++;
  250. }
  251. }
  252. public bool Remove(T item)
  253. {
  254. return Array.godot_icall_Array_Remove(GetPtr(), item);
  255. }
  256. // IEnumerable<T>
  257. public IEnumerator<T> GetEnumerator()
  258. {
  259. int count = objectArray.Count;
  260. for (int i = 0; i < count; i++)
  261. {
  262. yield return (T)this[i];
  263. }
  264. }
  265. IEnumerator IEnumerable.GetEnumerator()
  266. {
  267. return GetEnumerator();
  268. }
  269. }
  270. }