Skip to content

Commit 0ac2cf2

Browse files
committed
Array performance improvements to reduce copying/copy_on_write calls
- Avoid temporary copy of p_array in Array::append_array when types match - Call ptrw() once before looping in methods that return new Arrays, to avoid copy_on_write call for each item (recursive_duplicate, slice, filter, map)
1 parent 514c564 commit 0ac2cf2

File tree

1 file changed

+20
-12
lines changed

1 file changed

+20
-12
lines changed

core/variant/array.cpp

+20-12
Original file line numberDiff line numberDiff line change
@@ -288,13 +288,20 @@ void Array::push_back(const Variant &p_value) {
288288

289289
void Array::append_array(const Array &p_array) {
290290
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
291+
const ContainerTypeValidate &typed = _p->typed;
292+
const ContainerTypeValidate &other_typed = p_array._p->typed;
291293

292-
Vector<Variant> validated_array = p_array._p->array;
293-
for (int i = 0; i < validated_array.size(); ++i) {
294-
ERR_FAIL_COND(!_p->typed.validate(validated_array.write[i], "append_array"));
295-
}
294+
if (typed == other_typed || typed.type == Variant::NIL || (other_typed.type == Variant::OBJECT && typed.can_reference(other_typed))) {
295+
_p->array.append_array(p_array._p->array);
296+
} else {
297+
Vector<Variant> validated_array = p_array._p->array;
298+
Variant *write = validated_array.ptrw();
299+
for (int i = 0; i < validated_array.size(); ++i) {
300+
ERR_FAIL_COND(!_p->typed.validate(write[i], "append_array"));
301+
}
296302

297-
_p->array.append_array(validated_array);
303+
_p->array.append_array(validated_array);
304+
}
298305
}
299306

300307
Error Array::resize(int p_new_size) {
@@ -452,8 +459,9 @@ Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {
452459
recursion_count++;
453460
int element_count = size();
454461
new_arr.resize(element_count);
462+
Variant *write = new_arr._p->array.ptrw();
455463
for (int i = 0; i < element_count; i++) {
456-
new_arr[i] = get(i).recursive_duplicate(true, recursion_count);
464+
write[i] = get(i).recursive_duplicate(true, recursion_count);
457465
}
458466
} else {
459467
new_arr._p->array = _p->array;
@@ -489,8 +497,9 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
489497
int result_size = (end - begin) / p_step + (((end - begin) % p_step != 0) ? 1 : 0);
490498
result.resize(result_size);
491499

500+
Variant *write = result._p->array.ptrw();
492501
for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
493-
result[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
502+
write[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
494503
src_idx += p_step;
495504
}
496505

@@ -504,6 +513,7 @@ Array Array::filter(const Callable &p_callable) const {
504513
int accepted_count = 0;
505514

506515
const Variant *argptrs[1];
516+
Variant *write = new_arr._p->array.ptrw();
507517
for (int i = 0; i < size(); i++) {
508518
argptrs[0] = &get(i);
509519

@@ -515,7 +525,7 @@ Array Array::filter(const Callable &p_callable) const {
515525
}
516526

517527
if (result.operator bool()) {
518-
new_arr[accepted_count] = get(i);
528+
write[accepted_count] = get(i);
519529
accepted_count++;
520530
}
521531
}
@@ -530,17 +540,15 @@ Array Array::map(const Callable &p_callable) const {
530540
new_arr.resize(size());
531541

532542
const Variant *argptrs[1];
543+
Variant *write = new_arr._p->array.ptrw();
533544
for (int i = 0; i < size(); i++) {
534545
argptrs[0] = &get(i);
535546

536-
Variant result;
537547
Callable::CallError ce;
538-
p_callable.callp(argptrs, 1, result, ce);
548+
p_callable.callp(argptrs, 1, write[i], ce);
539549
if (ce.error != Callable::CallError::CALL_OK) {
540550
ERR_FAIL_V_MSG(Array(), "Error calling method from 'map': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
541551
}
542-
543-
new_arr[i] = result;
544552
}
545553

546554
return new_arr;

0 commit comments

Comments
 (0)