Browse Source

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)
aaronp64 11 months ago
parent
commit
d176ba045f
1 changed files with 15 additions and 8 deletions
  1. 15 8
      core/variant/array.cpp

+ 15 - 8
core/variant/array.cpp

@@ -287,9 +287,15 @@ void Array::push_back(const Variant &p_value) {
 void Array::append_array(const Array &p_array) {
 void Array::append_array(const Array &p_array) {
 	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
 	ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
 
 
+	if (!is_typed() || _p->typed.can_reference(p_array._p->typed)) {
+		_p->array.append_array(p_array._p->array);
+		return;
+	}
+
 	Vector<Variant> validated_array = p_array._p->array;
 	Vector<Variant> validated_array = p_array._p->array;
+	Variant *write = validated_array.ptrw();
 	for (int i = 0; i < validated_array.size(); ++i) {
 	for (int i = 0; i < validated_array.size(); ++i) {
-		ERR_FAIL_COND(!_p->typed.validate(validated_array.write[i], "append_array"));
+		ERR_FAIL_COND(!_p->typed.validate(write[i], "append_array"));
 	}
 	}
 
 
 	_p->array.append_array(validated_array);
 	_p->array.append_array(validated_array);
@@ -529,8 +535,9 @@ Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {
 		recursion_count++;
 		recursion_count++;
 		int element_count = size();
 		int element_count = size();
 		new_arr.resize(element_count);
 		new_arr.resize(element_count);
+		Variant *write = new_arr._p->array.ptrw();
 		for (int i = 0; i < element_count; i++) {
 		for (int i = 0; i < element_count; i++) {
-			new_arr[i] = get(i).recursive_duplicate(true, recursion_count);
+			write[i] = get(i).recursive_duplicate(true, recursion_count);
 		}
 		}
 	} else {
 	} else {
 		new_arr._p->array = _p->array;
 		new_arr._p->array = _p->array;
@@ -566,8 +573,9 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
 	int result_size = (end - begin) / p_step + (((end - begin) % p_step != 0) ? 1 : 0);
 	int result_size = (end - begin) / p_step + (((end - begin) % p_step != 0) ? 1 : 0);
 	result.resize(result_size);
 	result.resize(result_size);
 
 
+	Variant *write = result._p->array.ptrw();
 	for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
 	for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
-		result[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
+		write[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
 		src_idx += p_step;
 		src_idx += p_step;
 	}
 	}
 
 
@@ -581,6 +589,7 @@ Array Array::filter(const Callable &p_callable) const {
 	int accepted_count = 0;
 	int accepted_count = 0;
 
 
 	const Variant *argptrs[1];
 	const Variant *argptrs[1];
+	Variant *write = new_arr._p->array.ptrw();
 	for (int i = 0; i < size(); i++) {
 	for (int i = 0; i < size(); i++) {
 		argptrs[0] = &get(i);
 		argptrs[0] = &get(i);
 
 
@@ -592,7 +601,7 @@ Array Array::filter(const Callable &p_callable) const {
 		}
 		}
 
 
 		if (result.operator bool()) {
 		if (result.operator bool()) {
-			new_arr[accepted_count] = get(i);
+			write[accepted_count] = get(i);
 			accepted_count++;
 			accepted_count++;
 		}
 		}
 	}
 	}
@@ -607,17 +616,15 @@ Array Array::map(const Callable &p_callable) const {
 	new_arr.resize(size());
 	new_arr.resize(size());
 
 
 	const Variant *argptrs[1];
 	const Variant *argptrs[1];
+	Variant *write = new_arr._p->array.ptrw();
 	for (int i = 0; i < size(); i++) {
 	for (int i = 0; i < size(); i++) {
 		argptrs[0] = &get(i);
 		argptrs[0] = &get(i);
 
 
-		Variant result;
 		Callable::CallError ce;
 		Callable::CallError ce;
-		p_callable.callp(argptrs, 1, result, ce);
+		p_callable.callp(argptrs, 1, write[i], ce);
 		if (ce.error != Callable::CallError::CALL_OK) {
 		if (ce.error != Callable::CallError::CALL_OK) {
 			ERR_FAIL_V_MSG(Array(), vformat("Error calling method from 'map': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
 			ERR_FAIL_V_MSG(Array(), vformat("Error calling method from 'map': %s.", Variant::get_callable_error_text(p_callable, argptrs, 1, ce)));
 		}
 		}
-
-		new_arr[i] = result;
 	}
 	}
 
 
 	return new_arr;
 	return new_arr;