Skip to content

Commit 5909f9f

Browse files
committed
GDScript: Fix issues with typed arrays
1 parent e9de988 commit 5909f9f

File tree

50 files changed

+943
-539
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+943
-539
lines changed

core/core_bind.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ TypedArray<PackedVector2Array> Geometry2D::decompose_polygon_in_convex(const Vec
717717
TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
718718
Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b);
719719

720-
Array ret;
720+
TypedArray<PackedVector2Array> ret;
721721

722722
for (int i = 0; i < polys.size(); ++i) {
723723
ret.push_back(polys[i]);
@@ -739,7 +739,7 @@ TypedArray<PackedVector2Array> Geometry2D::clip_polygons(const Vector<Vector2> &
739739
TypedArray<PackedVector2Array> Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
740740
Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polygons(p_polygon_a, p_polygon_b);
741741

742-
Array ret;
742+
TypedArray<PackedVector2Array> ret;
743743

744744
for (int i = 0; i < polys.size(); ++i) {
745745
ret.push_back(polys[i]);
@@ -750,7 +750,7 @@ TypedArray<PackedVector2Array> Geometry2D::intersect_polygons(const Vector<Vecto
750750
TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
751751
Vector<Vector<Point2>> polys = ::Geometry2D::exclude_polygons(p_polygon_a, p_polygon_b);
752752

753-
Array ret;
753+
TypedArray<PackedVector2Array> ret;
754754

755755
for (int i = 0; i < polys.size(); ++i) {
756756
ret.push_back(polys[i]);
@@ -761,7 +761,7 @@ TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2
761761
TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
762762
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon);
763763

764-
Array ret;
764+
TypedArray<PackedVector2Array> ret;
765765

766766
for (int i = 0; i < polys.size(); ++i) {
767767
ret.push_back(polys[i]);
@@ -772,7 +772,7 @@ TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vect
772772
TypedArray<PackedVector2Array> Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
773773
Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polyline_with_polygon(p_polyline, p_polygon);
774774

775-
Array ret;
775+
TypedArray<PackedVector2Array> ret;
776776

777777
for (int i = 0; i < polys.size(); ++i) {
778778
ret.push_back(polys[i]);
@@ -783,7 +783,7 @@ TypedArray<PackedVector2Array> Geometry2D::intersect_polyline_with_polygon(const
783783
TypedArray<PackedVector2Array> Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
784784
Vector<Vector<Point2>> polys = ::Geometry2D::offset_polygon(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type));
785785

786-
Array ret;
786+
TypedArray<PackedVector2Array> ret;
787787

788788
for (int i = 0; i < polys.size(); ++i) {
789789
ret.push_back(polys[i]);
@@ -794,7 +794,7 @@ TypedArray<PackedVector2Array> Geometry2D::offset_polygon(const Vector<Vector2>
794794
TypedArray<PackedVector2Array> Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
795795
Vector<Vector<Point2>> polys = ::Geometry2D::offset_polyline(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type), ::Geometry2D::PolyEndType(p_end_type));
796796

797-
Array ret;
797+
TypedArray<PackedVector2Array> ret;
798798

799799
for (int i = 0; i < polys.size(); ++i) {
800800
ret.push_back(polys[i]);

core/doc_data.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030

3131
#include "doc_data.h"
3232

33+
String DocData::get_default_value_string(const Variant &p_value) {
34+
if (p_value.get_type() == Variant::ARRAY) {
35+
return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
36+
} else {
37+
return p_value.get_construct_string().replace("\n", " ");
38+
}
39+
}
40+
3341
void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) {
3442
if (p_retinfo.type == Variant::INT && p_retinfo.hint == PROPERTY_HINT_INT_IS_POINTER) {
3543
p_method.return_type = p_retinfo.hint_string;
@@ -105,7 +113,7 @@ void DocData::property_doc_from_scriptmemberinfo(DocData::PropertyDoc &p_propert
105113
p_property.getter = p_memberinfo.getter;
106114

107115
if (p_memberinfo.has_default_value && p_memberinfo.default_value.get_type() != Variant::OBJECT) {
108-
p_property.default_value = p_memberinfo.default_value.get_construct_string().replace("\n", "");
116+
p_property.default_value = get_default_value_string(p_memberinfo.default_value);
109117
}
110118

111119
p_property.overridden = false;
@@ -148,7 +156,7 @@ void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const Met
148156
int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size());
149157
if (default_arg_index >= 0) {
150158
Variant default_arg = p_methodinfo.default_arguments[default_arg_index];
151-
argument.default_value = default_arg.get_construct_string().replace("\n", "");
159+
argument.default_value = get_default_value_string(default_arg);
152160
}
153161
p_method.arguments.push_back(argument);
154162
}

core/doc_data.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,8 @@ class DocData {
516516
}
517517
};
518518

519+
static String get_default_value_string(const Variant &p_value);
520+
519521
static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
520522
static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo);
521523
static void property_doc_from_scriptmemberinfo(DocData::PropertyDoc &p_property, const ScriptMemberInfo &p_memberinfo);

core/extension/gdextension_interface.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,12 @@ static GDExtensionVariantPtr gdextension_array_operator_index_const(GDExtensionC
856856
return (GDExtensionVariantPtr)&self->operator[](p_index);
857857
}
858858

859+
void gdextension_array_ref(GDExtensionTypePtr p_self, GDExtensionConstTypePtr p_from) {
860+
Array *self = (Array *)p_self;
861+
const Array *from = (const Array *)p_from;
862+
self->_ref(*from);
863+
}
864+
859865
void gdextension_array_set_typed(GDExtensionTypePtr p_self, uint32_t p_type, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstVariantPtr p_script) {
860866
Array *self = reinterpret_cast<Array *>(p_self);
861867
const StringName *class_name = reinterpret_cast<const StringName *>(p_class_name);
@@ -1136,6 +1142,7 @@ void gdextension_setup_interface(GDExtensionInterface *p_interface) {
11361142

11371143
gde_interface.array_operator_index = gdextension_array_operator_index;
11381144
gde_interface.array_operator_index_const = gdextension_array_operator_index_const;
1145+
gde_interface.array_ref = gdextension_array_ref;
11391146
gde_interface.array_set_typed = gdextension_array_set_typed;
11401147

11411148
/* Dictionary functions */

core/extension/gdextension_interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ typedef struct {
551551

552552
GDExtensionVariantPtr (*array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be an Array ptr
553553
GDExtensionVariantPtr (*array_operator_index_const)(GDExtensionConstTypePtr p_self, GDExtensionInt p_index); // p_self should be an Array ptr
554+
void (*array_ref)(GDExtensionTypePtr p_self, GDExtensionConstTypePtr p_from); // p_self should be an Array ptr
554555
void (*array_set_typed)(GDExtensionTypePtr p_self, uint32_t p_type, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstVariantPtr p_script); // p_self should be an Array ptr
555556

556557
/* Dictionary functions */

core/variant/array.cpp

Lines changed: 77 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void Array::_ref(const Array &p_from) const {
6464

6565
_unref();
6666

67-
_p = p_from._p;
67+
_p = _fp;
6868
}
6969

7070
void Array::_unref() const {
@@ -191,62 +191,73 @@ uint32_t Array::recursive_hash(int recursion_count) const {
191191
return hash_fmix32(h);
192192
}
193193

194-
bool Array::_assign(const Array &p_array) {
195-
bool can_convert = p_array._p->typed.type == Variant::NIL;
196-
can_convert |= _p->typed.type == Variant::STRING && p_array._p->typed.type == Variant::STRING_NAME;
197-
can_convert |= _p->typed.type == Variant::STRING_NAME && p_array._p->typed.type == Variant::STRING;
194+
void Array::operator=(const Array &p_array) {
195+
if (this == &p_array) {
196+
return;
197+
}
198+
_ref(p_array);
199+
}
200+
201+
void Array::assign(const Array &p_array) {
202+
const ContainerTypeValidate &typed = _p->typed;
203+
const ContainerTypeValidate &source_typed = p_array._p->typed;
198204

199-
if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {
200-
//same type or untyped, just reference, should be fine
201-
_ref(p_array);
202-
} else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway
205+
if (typed == source_typed || typed.type == Variant::NIL || (source_typed.type == Variant::OBJECT && typed.can_reference(source_typed))) {
206+
// from same to same or
207+
// from anything to variants or
208+
// from subclasses to base classes
203209
_p->array = p_array._p->array;
204-
} else if (can_convert) { //from untyped to typed, must try to check if they are all valid
205-
if (_p->typed.type == Variant::OBJECT) {
206-
//for objects, it needs full validation, either can be converted or fail
207-
for (int i = 0; i < p_array._p->array.size(); i++) {
208-
const Variant &element = p_array._p->array[i];
209-
if (element.get_type() != Variant::OBJECT || !_p->typed.validate_object(element, "assign")) {
210-
return false;
211-
}
212-
}
213-
_p->array = p_array._p->array; //then just copy, which is cheap anyway
210+
return;
211+
}
214212

215-
} else {
216-
//for non objects, we need to check if there is a valid conversion, which needs to happen one by one, so this is the worst case.
217-
Vector<Variant> new_array;
218-
new_array.resize(p_array._p->array.size());
219-
for (int i = 0; i < p_array._p->array.size(); i++) {
220-
Variant src_val = p_array._p->array[i];
221-
if (src_val.get_type() == _p->typed.type) {
222-
new_array.write[i] = src_val;
223-
} else if (Variant::can_convert_strict(src_val.get_type(), _p->typed.type)) {
224-
Variant *ptr = &src_val;
225-
Callable::CallError ce;
226-
Variant::construct(_p->typed.type, new_array.write[i], (const Variant **)&ptr, 1, ce);
227-
if (ce.error != Callable::CallError::CALL_OK) {
228-
ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
229-
}
230-
} else {
231-
ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
232-
}
213+
const Variant *source = p_array._p->array.ptr();
214+
int size = p_array._p->array.size();
215+
216+
if ((source_typed.type == Variant::NIL && typed.type == Variant::OBJECT) || (source_typed.type == Variant::OBJECT && source_typed.can_reference(typed))) {
217+
// from variants to objects or
218+
// from base classes to subclasses
219+
for (int i = 0; i < size; i++) {
220+
const Variant &element = source[i];
221+
if (element.get_type() != Variant::NIL && (element.get_type() != Variant::OBJECT || !typed.validate_object(element, "assign"))) {
222+
ERR_FAIL_MSG(vformat(R"(Unable to convert array index %i from "%s" to "%s".)", i, Variant::get_type_name(element.get_type()), Variant::get_type_name(typed.type)));
233223
}
224+
}
225+
_p->array = p_array._p->array;
226+
return;
227+
}
234228

235-
_p->array = new_array;
229+
Vector<Variant> array;
230+
array.resize(size);
231+
Variant *data = array.ptrw();
232+
233+
if (source_typed.type == Variant::NIL && typed.type != Variant::OBJECT) {
234+
// from variants to primitives
235+
for (int i = 0; i < size; i++) {
236+
const Variant *value = source + i;
237+
if (value->get_type() == typed.type) {
238+
data[i] = *value;
239+
continue;
240+
}
241+
if (!Variant::can_convert_strict(value->get_type(), typed.type)) {
242+
ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(value->get_type()) + "' to '" + Variant::get_type_name(typed.type) + "'.");
243+
}
244+
Callable::CallError ce;
245+
Variant::construct(typed.type, data[i], &value, 1, ce);
246+
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %i from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
247+
}
248+
} else if (Variant::can_convert_strict(source_typed.type, typed.type)) {
249+
// from primitives to different convertable primitives
250+
for (int i = 0; i < size; i++) {
251+
const Variant *value = source + i;
252+
Callable::CallError ce;
253+
Variant::construct(typed.type, data[i], &value, 1, ce);
254+
ERR_FAIL_COND_MSG(ce.error, vformat(R"(Unable to convert array index %i from "%s" to "%s".)", i, Variant::get_type_name(value->get_type()), Variant::get_type_name(typed.type)));
236255
}
237-
} else if (_p->typed.can_reference(p_array._p->typed)) { //same type or compatible
238-
_ref(p_array);
239256
} else {
240-
ERR_FAIL_V_MSG(false, "Assignment of arrays of incompatible types.");
257+
ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type)));
241258
}
242-
return true;
243-
}
244259

245-
void Array::operator=(const Array &p_array) {
246-
if (this == &p_array) {
247-
return;
248-
}
249-
_ref(p_array);
260+
_p->array = array;
250261
}
251262

252263
void Array::push_back(const Variant &p_value) {
@@ -269,7 +280,15 @@ void Array::append_array(const Array &p_array) {
269280

270281
Error Array::resize(int p_new_size) {
271282
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
272-
return _p->array.resize(p_new_size);
283+
Variant::Type &variant_type = _p->typed.type;
284+
int old_size = _p->array.size();
285+
Error err = _p->array.resize_zeroed(p_new_size);
286+
if (!err && variant_type != Variant::NIL && variant_type != Variant::OBJECT) {
287+
for (int i = old_size; i < p_new_size; i++) {
288+
VariantInternal::initialize(&_p->array.write[i], variant_type);
289+
}
290+
}
291+
return err;
273292
}
274293

275294
Error Array::insert(int p_pos, const Variant &p_value) {
@@ -403,24 +422,22 @@ Array Array::duplicate(bool p_deep) const {
403422

404423
Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {
405424
Array new_arr;
425+
new_arr._p->typed = _p->typed;
406426

407427
if (recursion_count > MAX_RECURSION) {
408428
ERR_PRINT("Max recursion reached");
409429
return new_arr;
410430
}
411431

412-
int element_count = size();
413-
new_arr.resize(element_count);
414-
new_arr._p->typed = _p->typed;
415432
if (p_deep) {
416433
recursion_count++;
434+
int element_count = size();
435+
new_arr.resize(element_count);
417436
for (int i = 0; i < element_count; i++) {
418437
new_arr[i] = get(i).recursive_duplicate(true, recursion_count);
419438
}
420439
} else {
421-
for (int i = 0; i < element_count; i++) {
422-
new_arr[i] = get(i);
423-
}
440+
new_arr._p->array = _p->array;
424441
}
425442

426443
return new_arr;
@@ -737,11 +754,7 @@ Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_nam
737754
_p = memnew(ArrayPrivate);
738755
_p->refcount.init();
739756
set_typed(p_type, p_class_name, p_script);
740-
_assign(p_from);
741-
}
742-
743-
bool Array::typed_assign(const Array &p_other) {
744-
return _assign(p_other);
757+
assign(p_from);
745758
}
746759

747760
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
@@ -763,6 +776,10 @@ bool Array::is_typed() const {
763776
return _p->typed.type != Variant::NIL;
764777
}
765778

779+
bool Array::is_same_typed(const Array &p_other) const {
780+
return _p->typed == p_other._p->typed;
781+
}
782+
766783
uint32_t Array::get_typed_builtin() const {
767784
return _p->typed.type;
768785
}

core/variant/array.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,11 @@ class Callable;
4343

4444
class Array {
4545
mutable ArrayPrivate *_p;
46-
void _ref(const Array &p_from) const;
4746
void _unref() const;
4847

49-
protected:
50-
bool _assign(const Array &p_array);
51-
5248
public:
49+
void _ref(const Array &p_from) const;
50+
5351
Variant &operator[](int p_idx);
5452
const Variant &operator[](int p_idx) const;
5553

@@ -68,6 +66,7 @@ class Array {
6866
uint32_t recursive_hash(int recursion_count) const;
6967
void operator=(const Array &p_array);
7068

69+
void assign(const Array &p_array);
7170
void push_back(const Variant &p_value);
7271
_FORCE_INLINE_ void append(const Variant &p_value) { push_back(p_value); } //for python compatibility
7372
void append_array(const Array &p_array);
@@ -120,9 +119,9 @@ class Array {
120119

121120
const void *id() const;
122121

123-
bool typed_assign(const Array &p_other);
124122
void set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
125123
bool is_typed() const;
124+
bool is_same_typed(const Array &p_other) const;
126125
uint32_t get_typed_builtin() const;
127126
StringName get_typed_class_name() const;
128127
Variant get_typed_script() const;

core/variant/container_type_validate.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,15 @@ struct ContainerTypeValidate {
7474
return true;
7575
}
7676

77+
_FORCE_INLINE_ bool operator==(const ContainerTypeValidate &p_type) const {
78+
return type == p_type.type && class_name == p_type.class_name && script == p_type.script;
79+
}
80+
_FORCE_INLINE_ bool operator!=(const ContainerTypeValidate &p_type) const {
81+
return type != p_type.type || class_name != p_type.class_name || script != p_type.script;
82+
}
83+
7784
// Coerces String and StringName into each other when needed.
78-
_FORCE_INLINE_ bool validate(Variant &inout_variant, const char *p_operation = "use") {
85+
_FORCE_INLINE_ bool validate(Variant &inout_variant, const char *p_operation = "use") const {
7986
if (type == Variant::NIL) {
8087
return true;
8188
}
@@ -102,7 +109,7 @@ struct ContainerTypeValidate {
102109
return validate_object(inout_variant, p_operation);
103110
}
104111

105-
_FORCE_INLINE_ bool validate_object(const Variant &p_variant, const char *p_operation = "use") {
112+
_FORCE_INLINE_ bool validate_object(const Variant &p_variant, const char *p_operation = "use") const {
106113
ERR_FAIL_COND_V(p_variant.get_type() != Variant::OBJECT, false);
107114

108115
#ifdef DEBUG_ENABLED

0 commit comments

Comments
 (0)