Add callable support for `find` and `rfind` `Array` methods
This commit is contained in:
parent
88f3b5f9d5
commit
89491f4403
|
@ -369,6 +369,34 @@ int Array::find(const Variant &p_value, int p_from) const {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int Array::find_custom(const Callable &p_callable, int p_from) const {
|
||||
int ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const Variant *argptrs[1];
|
||||
|
||||
for (int i = p_from; i < size(); i++) {
|
||||
const Variant &val = _p->array[i];
|
||||
argptrs[0] = &val;
|
||||
Variant res;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, res, ce);
|
||||
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
|
||||
ERR_FAIL_V_MSG(ret, "Error calling method from 'find_custom': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, ret, "Error on method from 'find_custom': Return type of callable must be boolean.");
|
||||
if (res.operator bool()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Array::rfind(const Variant &p_value, int p_from) const {
|
||||
if (_p->array.size() == 0) {
|
||||
return -1;
|
||||
|
@ -394,6 +422,41 @@ int Array::rfind(const Variant &p_value, int p_from) const {
|
|||
return -1;
|
||||
}
|
||||
|
||||
int Array::rfind_custom(const Callable &p_callable, int p_from) const {
|
||||
if (_p->array.size() == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p_from < 0) {
|
||||
// Relative offset from the end.
|
||||
p_from = _p->array.size() + p_from;
|
||||
}
|
||||
if (p_from < 0 || p_from >= _p->array.size()) {
|
||||
// Limit to array boundaries.
|
||||
p_from = _p->array.size() - 1;
|
||||
}
|
||||
|
||||
const Variant *argptrs[1];
|
||||
|
||||
for (int i = p_from; i >= 0; i--) {
|
||||
const Variant &val = _p->array[i];
|
||||
argptrs[0] = &val;
|
||||
Variant res;
|
||||
Callable::CallError ce;
|
||||
p_callable.callp(argptrs, 1, res, ce);
|
||||
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
|
||||
ERR_FAIL_V_MSG(-1, "Error calling method from 'rfind_custom': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(res.get_type() != Variant::Type::BOOL, -1, "Error on method from 'rfind_custom': Return type of callable must be boolean.");
|
||||
if (res.operator bool()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Array::count(const Variant &p_value) const {
|
||||
Variant value = p_value;
|
||||
ERR_FAIL_COND_V(!_p->typed.validate(value, "count"), 0);
|
||||
|
@ -761,7 +824,7 @@ Variant Array::max() const {
|
|||
return Variant(); //not a valid comparison
|
||||
}
|
||||
if (bool(ret)) {
|
||||
//is less
|
||||
//is greater
|
||||
maxval = test;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,9 @@ public:
|
|||
void reverse();
|
||||
|
||||
int find(const Variant &p_value, int p_from = 0) const;
|
||||
int find_custom(const Callable &p_callable, int p_from = 0) const;
|
||||
int rfind(const Variant &p_value, int p_from = -1) const;
|
||||
int rfind_custom(const Callable &p_callable, int p_from = -1) const;
|
||||
int count(const Variant &p_value) const;
|
||||
bool has(const Variant &p_value) const;
|
||||
|
||||
|
|
|
@ -2289,7 +2289,9 @@ static void _register_variant_builtin_methods_array() {
|
|||
bind_method(Array, back, sarray(), varray());
|
||||
bind_method(Array, pick_random, sarray(), varray());
|
||||
bind_method(Array, find, sarray("what", "from"), varray(0));
|
||||
bind_method(Array, find_custom, sarray("method", "from"), varray(0));
|
||||
bind_method(Array, rfind, sarray("what", "from"), varray(-1));
|
||||
bind_method(Array, rfind_custom, sarray("method", "from"), varray(-1));
|
||||
bind_method(Array, count, sarray("value"), varray());
|
||||
bind_method(Array, has, sarray("value"), varray());
|
||||
bind_method(Array, pop_back, sarray(), varray());
|
||||
|
|
|
@ -325,6 +325,7 @@
|
|||
<param index="0" name="value" type="Variant" />
|
||||
<description>
|
||||
Returns the number of times an element is in the array.
|
||||
To count how many elements in an array satisfy a condition, see [method reduce].
|
||||
</description>
|
||||
</method>
|
||||
<method name="duplicate" qualifiers="const">
|
||||
|
@ -396,6 +397,25 @@
|
|||
[b]Note:[/b] For performance reasons, the search is affected by [param what]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_custom" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="method" type="Callable" />
|
||||
<param index="1" name="from" type="int" default="0" />
|
||||
<description>
|
||||
Returns the index of the [b]first[/b] element in the array that causes [param method] to return [code]true[/code], or [code]-1[/code] if there are none. The search's start can be specified with [param from], continuing to the end of the array.
|
||||
[param method] is a callable that takes an element of the array, and returns a [bool].
|
||||
[b]Note:[/b] If you just want to know whether the array contains [i]anything[/i] that satisfies [param method], use [method any].
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
func is_even(number):
|
||||
return number % 2 == 0
|
||||
|
||||
func _ready():
|
||||
print([1, 3, 4, 7].find_custom(is_even.bind())) # prints 2
|
||||
[/gdscript]
|
||||
[/codeblocks]
|
||||
</description>
|
||||
</method>
|
||||
<method name="front" qualifiers="const">
|
||||
<return type="Variant" />
|
||||
<description>
|
||||
|
@ -619,6 +639,17 @@
|
|||
func is_length_greater(a, b):
|
||||
return a.length() > b.length()
|
||||
[/codeblock]
|
||||
This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]:
|
||||
[codeblock]
|
||||
func is_even(number):
|
||||
return number % 2 == 0
|
||||
|
||||
func _ready():
|
||||
var arr = [1, 2, 3, 4, 5]
|
||||
# Increment count if it's even, else leaves count the same.
|
||||
var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0)
|
||||
print(even_count) # Prints 2
|
||||
[/codeblock]
|
||||
See also [method map], [method filter], [method any] and [method all].
|
||||
</description>
|
||||
</method>
|
||||
|
@ -655,6 +686,14 @@
|
|||
Returns the index of the [b]last[/b] occurrence of [param what] in this array, or [code]-1[/code] if there are none. The search's start can be specified with [param from], continuing to the beginning of the array. This method is the reverse of [method find].
|
||||
</description>
|
||||
</method>
|
||||
<method name="rfind_custom" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="method" type="Callable" />
|
||||
<param index="1" name="from" type="int" default="-1" />
|
||||
<description>
|
||||
Returns the index of the [b]last[/b] element of the array that causes [param method] to return [code]true[/code], or [code]-1[/code] if there are none. The search's start can be specified with [param from], continuing to the beginning of the array. This method is the reverse of [method find_custom].
|
||||
</description>
|
||||
</method>
|
||||
<method name="shuffle">
|
||||
<return type="void" />
|
||||
<description>
|
||||
|
|
|
@ -634,6 +634,24 @@ TEST_CASE("[Array] Typed copying") {
|
|||
a6.clear();
|
||||
}
|
||||
|
||||
static bool _find_custom_callable(const Variant &p_val) {
|
||||
return (int)p_val % 2 == 0;
|
||||
}
|
||||
|
||||
TEST_CASE("[Array] Test find_custom") {
|
||||
Array a1 = build_array(1, 3, 4, 5, 8, 9);
|
||||
// Find first even number.
|
||||
int index = a1.find_custom(callable_mp_static(_find_custom_callable));
|
||||
CHECK_EQ(index, 2);
|
||||
}
|
||||
|
||||
TEST_CASE("[Array] Test rfind_custom") {
|
||||
Array a1 = build_array(1, 3, 4, 5, 8, 9);
|
||||
// Find last even number.
|
||||
int index = a1.rfind_custom(callable_mp_static(_find_custom_callable));
|
||||
CHECK_EQ(index, 4);
|
||||
}
|
||||
|
||||
} // namespace TestArray
|
||||
|
||||
#endif // TEST_ARRAY_H
|
||||
|
|
Loading…
Reference in New Issue