Add ability to bind typed arrays to script API

Note: Only replaced 2 instances to test, Node.get_children and TileMap.get_used_cells
Note: Will do a mass replace on later PRs of whathever I can find, but probably need
a tool to grep through doc.
Warning: Mono will break, needs to be fixed (and so do TypeScript and NativeScript, need to ask respective maintainers)
This commit is contained in:
Juan Linietsky 2020-04-20 19:06:00 -03:00
parent 7343ec13d9
commit 5d4dc2d45c
24 changed files with 452 additions and 10 deletions

View file

@ -30,8 +30,10 @@
#include "array.h"
#include "container_type_validate.h"
#include "core/hashfuncs.h"
#include "core/object.h"
#include "core/script_language.h"
#include "core/variant.h"
#include "core/vector.h"
@ -39,6 +41,8 @@ class ArrayPrivate {
public:
SafeRefCount refcount;
Vector<Variant> array;
ContainerTypeValidate typed;
};
void Array::_ref(const Array &p_from) const {
@ -108,12 +112,34 @@ uint32_t Array::hash() const {
}
return h;
}
void Array::operator=(const Array &p_array) {
_ref(p_array);
void Array::_assign(const Array &p_array) {
if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {
//same type or untyped, just reference, shuold be fine
_ref(p_array);
} else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway
_p->array = p_array._p->array;
} else if (p_array._p->typed.type == Variant::NIL) { //from untyped to typed, must try to check if they are all valid
for (int i = 0; i < p_array._p->array.size(); i++) {
if (!_p->typed.validate(p_array._p->array[i], "assign")) {
return;
}
}
_p->array = p_array._p->array; //then just copy, which is cheap anyway
} else if (_p->typed.can_reference(p_array._p->typed)) { //same type or compatible
_ref(p_array);
} else {
ERR_FAIL_MSG("Assignment of arrays of incompatible types.");
}
}
void Array::operator=(const Array &p_array) {
_assign(p_array);
}
void Array::push_back(const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "push_back"));
_p->array.push_back(p_value);
}
@ -124,11 +150,13 @@ Error Array::resize(int p_new_size) {
void Array::insert(int p_pos, const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "insert"));
_p->array.insert(p_pos, p_value);
}
void Array::erase(const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "erase"));
_p->array.erase(p_value);
}
@ -144,6 +172,7 @@ Variant Array::back() const {
int Array::find(const Variant &p_value, int p_from) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);
return _p->array.find(p_value, p_from);
}
@ -151,6 +180,7 @@ int Array::rfind(const Variant &p_value, int p_from) const {
if (_p->array.size() == 0)
return -1;
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "rfind"), -1);
if (p_from < 0) {
// Relative offset from the end
@ -173,11 +203,13 @@ int Array::rfind(const Variant &p_value, int p_from) const {
int Array::find_last(const Variant &p_value) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find_last"), -1);
return rfind(p_value);
}
int Array::count(const Variant &p_value) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "count"), 0);
if (_p->array.size() == 0)
return 0;
@ -193,6 +225,8 @@ int Array::count(const Variant &p_value) const {
}
bool Array::has(const Variant &p_value) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "use 'has'"), false);
return _p->array.find(p_value, 0) != -1;
}
@ -203,6 +237,8 @@ void Array::remove(int p_pos) {
void Array::set(int p_idx, const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "set"));
operator[](p_idx) = p_value;
}
@ -216,6 +252,7 @@ Array Array::duplicate(bool p_deep) const {
Array new_arr;
int element_count = size();
new_arr.resize(element_count);
new_arr._p->typed = _p->typed;
for (int i = 0; i < element_count; i++) {
new_arr[i] = p_deep ? get(i).duplicate(p_deep) : get(i);
}
@ -369,11 +406,13 @@ _FORCE_INLINE_ int bisect(const Vector<Variant> &p_array, const Variant &p_value
int Array::bsearch(const Variant &p_value, bool p_before) {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "binary search"), -1);
return bisect(_p->array, p_value, p_before, _ArrayVariantSort());
}
int Array::bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before) {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1);
ERR_FAIL_NULL_V(p_obj, 0);
_ArrayVariantSortCustom less;
@ -391,6 +430,7 @@ Array &Array::invert() {
void Array::push_front(const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "push_front"));
_p->array.insert(0, p_value);
}
@ -465,6 +505,27 @@ const void *Array::id() const {
return _p->array.ptr();
}
Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
_p = memnew(ArrayPrivate);
_p->refcount.init();
set_typed(p_type, p_class_name, p_script);
_assign(p_from);
}
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
ERR_FAIL_COND_MSG(_p->typed.type != Variant::NIL, "Type can only be set once.");
ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");
Ref<Script> script = p_script;
ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");
_p->typed.type = Variant::Type(p_type);
_p->typed.class_name = p_class_name;
_p->typed.script = script;
_p->typed.where = "TypedArray";
}
Array::Array(const Array &p_from) {
_p = nullptr;