Skip to content

Commit

Permalink
Add any() and all() methods to Array
Browse files Browse the repository at this point in the history
These can be used as faster, more convenient shorthands to
using `filter()` + `size()`.
  • Loading branch information
Calinou committed May 25, 2022
1 parent 2ec379e commit a98e31a
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
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

0 comments on commit a98e31a

Please sign in to comment.