Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add any() and all() methods to Array #50349

Merged
merged 1 commit into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions core/variant/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,50 @@ Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const
return ret;
}

bool Array::any(const Callable &p_callable) const {
const Variant *argptrs[1];
for (int i = 0; i < size(); i++) {
argptrs[0] = &get(i);

Variant result;
Callable::CallError ce;
p_callable.call(argptrs, 1, result, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_V_MSG(false, "Error calling method from 'any': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
}

if (result.operator bool()) {
// Return as early as possible when one of the conditions is `true`.
// This improves performance compared to relying on `filter(...).size() >= 1`.
return true;
}
}

return false;
}

bool Array::all(const Callable &p_callable) const {
const Variant *argptrs[1];
for (int i = 0; i < size(); i++) {
argptrs[0] = &get(i);

Variant result;
Callable::CallError ce;
p_callable.call(argptrs, 1, result, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_V_MSG(false, "Error calling method from 'all': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
}

if (!(result.operator bool())) {
// Return as early as possible when one of the inverted conditions is `false`.
// This improves performance compared to relying on `filter(...).size() >= array_size().`.
return false;
}
}

return true;
}

struct _ArrayVariantSort {
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
bool valid = false;
Expand Down
2 changes: 2 additions & 0 deletions core/variant/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class Array {
Array filter(const Callable &p_callable) const;
Array map(const Callable &p_callable) const;
Variant reduce(const Callable &p_callable, const Variant &p_accum) const;
bool any(const Callable &p_callable) const;
bool all(const Callable &p_callable) const;

bool operator<(const Array &p_array) const;
bool operator<=(const Array &p_array) const;
Expand Down
2 changes: 2 additions & 0 deletions core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1853,6 +1853,8 @@ static void _register_variant_builtin_methods() {
bind_method(Array, filter, sarray("method"), varray());
bind_method(Array, map, sarray("method"), varray());
bind_method(Array, reduce, sarray("method", "accum"), varray(Variant()));
bind_method(Array, any, sarray("method"), varray());
bind_method(Array, all, sarray("method"), varray());
bind_method(Array, max, sarray(), varray());
bind_method(Array, min, sarray(), varray());

Expand Down
45 changes: 45 additions & 0 deletions doc/classes/Array.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,48 @@
</constructor>
</constructors>
<methods>
<method name="all" qualifiers="const">
<return type="bool" />
<argument index="0" name="method" type="Callable" />
<description>
Calls the provided [Callable] on each element in the array and returns [code]true[/code] if the [Callable] returns [code]true[/code] for [i]all[/i] elements in the array. If the [Callable] returns [code]false[/code] for one array element or more, this method returns [code]false[/code].
The callable's method should take one [Variant] parameter (the current array element) and return a boolean value.
[codeblock]
func _ready():
print([6, 10, 6].all(greater_than_5)) # Prints True (3 elements evaluate to `true`).
print([4, 10, 4].all(greater_than_5)) # Prints False (1 elements evaluate to `true`).
print([4, 4, 4].all(greater_than_5)) # Prints False (0 elements evaluate to `true`).

print([6, 10, 6].all(func(number): return number &gt; 5)) # Prints True. Same as the first line above, but using lambda function.

func greater_than_5(number):
return number &gt; 5
[/codeblock]
See also [method any], [method filter], [method map] and [method reduce].
[b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays).
</description>
</method>
<method name="any" qualifiers="const">
<return type="bool" />
<argument index="0" name="method" type="Callable" />
<description>
Calls the provided [Callable] on each element in the array and returns [code]true[/code] if the [Callable] returns [code]true[/code] for [i]one or more[/i] elements in the array. If the [Callable] returns [code]false[/code] for all elements in the array, this method returns [code]false[/code].
The callable's method should take one [Variant] parameter (the current array element) and return a boolean value.
[codeblock]
func _ready():
print([6, 10, 6].any(greater_than_5)) # Prints True (3 elements evaluate to `true`).
print([4, 10, 4].any(greater_than_5)) # Prints True (1 elements evaluate to `true`).
print([4, 4, 4].any(greater_than_5)) # Prints False (0 elements evaluate to `true`).

print([6, 10, 6].any(func(number): return number &gt; 5)) # Prints True. Same as the first line above, but using lambda function.

func greater_than_5(number):
return number &gt; 5
[/codeblock]
See also [method all], [method filter], [method map] and [method reduce].
[b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays).
</description>
</method>
<method name="append">
<return type="void" />
<argument index="0" name="value" type="Variant" />
Expand Down Expand Up @@ -232,6 +274,7 @@
func remove_1(number):
return number != 1
[/codeblock]
See also [method any], [method all], [method map] and [method reduce].
</description>
</method>
<method name="find" qualifiers="const">
Expand Down Expand Up @@ -333,6 +376,7 @@
func negate(number):
return -number
[/codeblock]
See also [method filter], [method reduce], [method any] and [method all].
</description>
</method>
<method name="max" qualifiers="const">
Expand Down Expand Up @@ -398,6 +442,7 @@
func sum(accum, number):
return accum + number
[/codeblock]
See also [method map], [method filter], [method any] and [method all].
</description>
</method>
<method name="remove_at">
Expand Down