Array.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. public override string ToString()
  109. {
  110. return godot_icall_Array_ToString(GetPtr());
  111. }
  112. [MethodImpl(MethodImplOptions.InternalCall)]
  113. internal extern static IntPtr godot_icall_Array_Ctor();
  114. [MethodImpl(MethodImplOptions.InternalCall)]
  115. internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
  116. [MethodImpl(MethodImplOptions.InternalCall)]
  117. internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
  118. [MethodImpl(MethodImplOptions.InternalCall)]
  119. internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass);
  120. [MethodImpl(MethodImplOptions.InternalCall)]
  121. internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
  122. [MethodImpl(MethodImplOptions.InternalCall)]
  123. internal extern static int godot_icall_Array_Count(IntPtr ptr);
  124. [MethodImpl(MethodImplOptions.InternalCall)]
  125. internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
  126. [MethodImpl(MethodImplOptions.InternalCall)]
  127. internal extern static void godot_icall_Array_Clear(IntPtr ptr);
  128. [MethodImpl(MethodImplOptions.InternalCall)]
  129. internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
  130. [MethodImpl(MethodImplOptions.InternalCall)]
  131. internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
  132. [MethodImpl(MethodImplOptions.InternalCall)]
  133. internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
  134. [MethodImpl(MethodImplOptions.InternalCall)]
  135. internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
  136. [MethodImpl(MethodImplOptions.InternalCall)]
  137. internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
  138. [MethodImpl(MethodImplOptions.InternalCall)]
  139. internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
  140. [MethodImpl(MethodImplOptions.InternalCall)]
  141. internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
  142. [MethodImpl(MethodImplOptions.InternalCall)]
  143. internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
  144. [MethodImpl(MethodImplOptions.InternalCall)]
  145. internal extern static string godot_icall_Array_ToString(IntPtr ptr);
  146. }
  147. public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
  148. {
  149. Array objectArray;
  150. internal static int elemTypeEncoding;
  151. internal static IntPtr elemTypeClass;
  152. static Array()
  153. {
  154. Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass);
  155. }
  156. public Array()
  157. {
  158. objectArray = new Array();
  159. }
  160. public Array(IEnumerable<T> collection)
  161. {
  162. if (collection == null)
  163. throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
  164. objectArray = new Array(collection);
  165. }
  166. public Array(Array array)
  167. {
  168. objectArray = array;
  169. }
  170. internal Array(IntPtr handle)
  171. {
  172. objectArray = new Array(handle);
  173. }
  174. internal Array(ArraySafeHandle handle)
  175. {
  176. objectArray = new Array(handle);
  177. }
  178. internal IntPtr GetPtr()
  179. {
  180. return objectArray.GetPtr();
  181. }
  182. public static explicit operator Array(Array<T> from)
  183. {
  184. return from.objectArray;
  185. }
  186. public Error Resize(int newSize)
  187. {
  188. return objectArray.Resize(newSize);
  189. }
  190. // IList<T>
  191. public T this[int index]
  192. {
  193. get
  194. {
  195. return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass);
  196. }
  197. set
  198. {
  199. objectArray[index] = value;
  200. }
  201. }
  202. public int IndexOf(T item)
  203. {
  204. return objectArray.IndexOf(item);
  205. }
  206. public void Insert(int index, T item)
  207. {
  208. objectArray.Insert(index, item);
  209. }
  210. public void RemoveAt(int index)
  211. {
  212. objectArray.RemoveAt(index);
  213. }
  214. // ICollection<T>
  215. public int Count
  216. {
  217. get
  218. {
  219. return objectArray.Count;
  220. }
  221. }
  222. public bool IsReadOnly
  223. {
  224. get
  225. {
  226. return objectArray.IsReadOnly;
  227. }
  228. }
  229. public void Add(T item)
  230. {
  231. objectArray.Add(item);
  232. }
  233. public void Clear()
  234. {
  235. objectArray.Clear();
  236. }
  237. public bool Contains(T item)
  238. {
  239. return objectArray.Contains(item);
  240. }
  241. public void CopyTo(T[] array, int arrayIndex)
  242. {
  243. if (array == null)
  244. throw new ArgumentNullException(nameof(array), "Value cannot be null.");
  245. if (arrayIndex < 0)
  246. throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
  247. // TODO This may be quite slow because every element access is an internal call.
  248. // It could be moved entirely to an internal call if we find out how to do the cast there.
  249. int count = objectArray.Count;
  250. if (array.Length < (arrayIndex + count))
  251. throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
  252. for (int i = 0; i < count; i++)
  253. {
  254. array[arrayIndex] = (T)this[i];
  255. arrayIndex++;
  256. }
  257. }
  258. public bool Remove(T item)
  259. {
  260. return Array.godot_icall_Array_Remove(GetPtr(), item);
  261. }
  262. // IEnumerable<T>
  263. public IEnumerator<T> GetEnumerator()
  264. {
  265. int count = objectArray.Count;
  266. for (int i = 0; i < count; i++)
  267. {
  268. yield return (T)this[i];
  269. }
  270. }
  271. IEnumerator IEnumerable.GetEnumerator()
  272. {
  273. return GetEnumerator();
  274. }
  275. public override string ToString() => objectArray.ToString();
  276. }
  277. }