collections_glue.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*************************************************************************/
  2. /* collections_glue.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #ifdef MONO_GLUE_ENABLED
  31. #include <mono/metadata/exception.h>
  32. #include "core/variant/array.h"
  33. #include "../mono_gd/gd_mono_cache.h"
  34. #include "../mono_gd/gd_mono_class.h"
  35. #include "../mono_gd/gd_mono_marshal.h"
  36. #include "../mono_gd/gd_mono_utils.h"
  37. Array *godot_icall_Array_Ctor() {
  38. return memnew(Array);
  39. }
  40. void godot_icall_Array_Dtor(Array *ptr) {
  41. memdelete(ptr);
  42. }
  43. MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
  44. if (index < 0 || index >= ptr->size()) {
  45. GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
  46. return nullptr;
  47. }
  48. return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
  49. }
  50. MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
  51. if (index < 0 || index >= ptr->size()) {
  52. GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
  53. return nullptr;
  54. }
  55. return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
  56. }
  57. void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) {
  58. if (index < 0 || index >= ptr->size()) {
  59. GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
  60. return;
  61. }
  62. ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
  63. }
  64. int32_t godot_icall_Array_Count(Array *ptr) {
  65. return ptr->size();
  66. }
  67. int32_t godot_icall_Array_Add(Array *ptr, MonoObject *item) {
  68. ptr->append(GDMonoMarshal::mono_object_to_variant(item));
  69. return ptr->size();
  70. }
  71. void godot_icall_Array_Clear(Array *ptr) {
  72. ptr->clear();
  73. }
  74. MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
  75. return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
  76. }
  77. void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index) {
  78. unsigned int count = ptr->size();
  79. if (mono_array_length(array) < (array_index + count)) {
  80. MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
  81. GDMonoUtils::set_pending_exception(exc);
  82. return;
  83. }
  84. for (unsigned int i = 0; i < count; i++) {
  85. MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i));
  86. mono_array_setref(array, array_index, boxed);
  87. array_index++;
  88. }
  89. }
  90. Array *godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array) {
  91. Array *godot_array = memnew(Array);
  92. unsigned int count = mono_array_length(mono_array);
  93. godot_array->resize(count);
  94. for (unsigned int i = 0; i < count; i++) {
  95. MonoObject *item = mono_array_get(mono_array, MonoObject *, i);
  96. godot_icall_Array_SetAt(godot_array, i, item);
  97. }
  98. return godot_array;
  99. }
  100. Array *godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep) {
  101. return memnew(Array(ptr->duplicate(deep)));
  102. }
  103. Array *godot_icall_Array_Concatenate(Array *left, Array *right) {
  104. int count = left->size() + right->size();
  105. Array *new_array = memnew(Array(left->duplicate(false)));
  106. new_array->resize(count);
  107. for (unsigned int i = 0; i < (unsigned int)right->size(); i++) {
  108. new_array->operator[](i + left->size()) = right->operator[](i);
  109. }
  110. return new_array;
  111. }
  112. int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
  113. return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
  114. }
  115. void godot_icall_Array_Insert(Array *ptr, int32_t index, MonoObject *item) {
  116. if (index < 0 || index > ptr->size()) {
  117. GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
  118. return;
  119. }
  120. ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
  121. }
  122. MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
  123. int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
  124. if (idx >= 0) {
  125. ptr->remove(idx);
  126. return true;
  127. }
  128. return false;
  129. }
  130. void godot_icall_Array_RemoveAt(Array *ptr, int32_t index) {
  131. if (index < 0 || index >= ptr->size()) {
  132. GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
  133. return;
  134. }
  135. ptr->remove(index);
  136. }
  137. int32_t godot_icall_Array_Resize(Array *ptr, int32_t new_size) {
  138. return (int32_t)ptr->resize(new_size);
  139. }
  140. void godot_icall_Array_Shuffle(Array *ptr) {
  141. ptr->shuffle();
  142. }
  143. void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
  144. MonoType *elem_type = mono_reflection_type_get_type(refltype);
  145. *type_encoding = mono_type_get_type(elem_type);
  146. MonoClass *type_class_raw = mono_class_from_mono_type(elem_type);
  147. *type_class = GDMono::get_singleton()->get_class(type_class_raw);
  148. }
  149. MonoString *godot_icall_Array_ToString(Array *ptr) {
  150. return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
  151. }
  152. Dictionary *godot_icall_Dictionary_Ctor() {
  153. return memnew(Dictionary);
  154. }
  155. void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
  156. memdelete(ptr);
  157. }
  158. MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
  159. Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
  160. if (ret == nullptr) {
  161. MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
  162. #ifdef DEBUG_ENABLED
  163. CRASH_COND(!exc);
  164. #endif
  165. GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
  166. GDMonoUtils::set_pending_exception((MonoException *)exc);
  167. return nullptr;
  168. }
  169. return GDMonoMarshal::variant_to_mono_object(ret);
  170. }
  171. MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) {
  172. Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
  173. if (ret == nullptr) {
  174. MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
  175. #ifdef DEBUG_ENABLED
  176. CRASH_COND(!exc);
  177. #endif
  178. GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
  179. GDMonoUtils::set_pending_exception((MonoException *)exc);
  180. return nullptr;
  181. }
  182. return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
  183. }
  184. void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) {
  185. ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value);
  186. }
  187. Array *godot_icall_Dictionary_Keys(Dictionary *ptr) {
  188. return memnew(Array(ptr->keys()));
  189. }
  190. Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
  191. return memnew(Array(ptr->values()));
  192. }
  193. int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
  194. return ptr->size();
  195. }
  196. void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
  197. Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
  198. Variant *ret = ptr->getptr(varKey);
  199. if (ret != nullptr) {
  200. GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists"));
  201. return;
  202. }
  203. ptr->operator[](varKey) = GDMonoMarshal::mono_object_to_variant(value);
  204. }
  205. void godot_icall_Dictionary_Clear(Dictionary *ptr) {
  206. ptr->clear();
  207. }
  208. MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
  209. // no dupes
  210. Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
  211. return ret != nullptr && *ret == GDMonoMarshal::mono_object_to_variant(value);
  212. }
  213. MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
  214. return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
  215. }
  216. Dictionary *godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep) {
  217. return memnew(Dictionary(ptr->duplicate(deep)));
  218. }
  219. MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
  220. return ptr->erase(GDMonoMarshal::mono_object_to_variant(key));
  221. }
  222. MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
  223. Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
  224. // no dupes
  225. Variant *ret = ptr->getptr(varKey);
  226. if (ret != nullptr && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
  227. ptr->erase(varKey);
  228. return true;
  229. }
  230. return false;
  231. }
  232. MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
  233. Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
  234. if (ret == nullptr) {
  235. *value = nullptr;
  236. return false;
  237. }
  238. *value = GDMonoMarshal::variant_to_mono_object(ret);
  239. return true;
  240. }
  241. MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
  242. Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
  243. if (ret == nullptr) {
  244. *value = nullptr;
  245. return false;
  246. }
  247. *value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
  248. return true;
  249. }
  250. void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
  251. MonoType *value_type = mono_reflection_type_get_type(refltype);
  252. *type_encoding = mono_type_get_type(value_type);
  253. MonoClass *type_class_raw = mono_class_from_mono_type(value_type);
  254. *type_class = GDMono::get_singleton()->get_class(type_class_raw);
  255. }
  256. MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
  257. return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
  258. }
  259. void godot_register_collections_icalls() {
  260. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor);
  261. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray);
  262. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor);
  263. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At);
  264. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic);
  265. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt);
  266. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count);
  267. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add);
  268. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", godot_icall_Array_Clear);
  269. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", godot_icall_Array_Concatenate);
  270. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", godot_icall_Array_Contains);
  271. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", godot_icall_Array_CopyTo);
  272. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", godot_icall_Array_Duplicate);
  273. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", godot_icall_Array_IndexOf);
  274. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", godot_icall_Array_Insert);
  275. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", godot_icall_Array_Remove);
  276. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt);
  277. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize);
  278. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle);
  279. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo);
  280. GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString);
  281. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor);
  282. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor);
  283. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue);
  284. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic);
  285. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue);
  286. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
  287. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
  288. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
  289. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
  290. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
  291. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
  292. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", godot_icall_Dictionary_ContainsKey);
  293. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", godot_icall_Dictionary_Duplicate);
  294. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey);
  295. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove);
  296. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue);
  297. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic);
  298. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo);
  299. GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString);
  300. }
  301. #endif // MONO_GLUE_ENABLED