2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* array.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2022-01-03 20:27:34 +00:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "array.h"
2017-01-16 07:04:19 +00:00
2020-04-20 22:06:00 +00:00
# include "container_type_validate.h"
2020-11-07 22:33:38 +00:00
# include "core/object/class_db.h"
# include "core/object/script_language.h"
# include "core/templates/hashfuncs.h"
2021-09-19 18:13:09 +00:00
# include "core/templates/search_array.h"
2020-11-07 22:33:38 +00:00
# include "core/templates/vector.h"
2021-02-04 01:02:06 +00:00
# include "core/variant/callable.h"
2020-11-07 22:33:38 +00:00
# include "core/variant/variant.h"
2014-02-10 01:10:30 +00:00
2018-03-09 19:16:08 +00:00
class ArrayPrivate {
public :
2014-02-10 01:10:30 +00:00
SafeRefCount refcount ;
Vector < Variant > array ;
2022-05-17 17:14:42 +00:00
Variant * read_only = nullptr ; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
2020-04-20 22:06:00 +00:00
ContainerTypeValidate typed ;
2014-02-10 01:10:30 +00:00
} ;
2017-03-05 15:44:50 +00:00
void Array : : _ref ( const Array & p_from ) const {
2014-02-10 01:10:30 +00:00
ArrayPrivate * _fp = p_from . _p ;
ERR_FAIL_COND ( ! _fp ) ; // should NOT happen.
2022-05-17 17:14:42 +00:00
if ( unlikely ( _fp - > read_only ! = nullptr ) ) {
// If p_from is a read-only array, just copy the contents to avoid further modification.
_unref ( ) ;
_p = memnew ( ArrayPrivate ) ;
_p - > refcount . init ( ) ;
_p - > array = _fp - > array ;
_p - > typed = _fp - > typed ;
return ;
}
2020-05-14 14:41:43 +00:00
if ( _fp = = _p ) {
2017-09-22 03:58:29 +00:00
return ; // whatever it is, nothing to do here move along
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
bool success = _fp - > refcount . ref ( ) ;
2017-09-22 03:58:29 +00:00
ERR_FAIL_COND ( ! success ) ; // should really not happen either
2014-02-10 01:10:30 +00:00
_unref ( ) ;
2017-01-11 11:53:31 +00:00
_p = p_from . _p ;
2014-02-10 01:10:30 +00:00
}
void Array : : _unref ( ) const {
2020-05-14 14:41:43 +00:00
if ( ! _p ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
if ( _p - > refcount . unref ( ) ) {
2022-05-17 17:14:42 +00:00
if ( _p - > read_only ) {
memdelete ( _p - > read_only ) ;
}
2014-02-10 01:10:30 +00:00
memdelete ( _p ) ;
}
2020-04-01 23:20:12 +00:00
_p = nullptr ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant & Array : : operator [ ] ( int p_idx ) {
2022-05-17 17:14:42 +00:00
if ( unlikely ( _p - > read_only ) ) {
* _p - > read_only = _p - > array [ p_idx ] ;
return * _p - > read_only ;
}
2018-07-25 01:11:03 +00:00
return _p - > array . write [ p_idx ] ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
const Variant & Array : : operator [ ] ( int p_idx ) const {
2022-05-17 17:14:42 +00:00
if ( unlikely ( _p - > read_only ) ) {
* _p - > read_only = _p - > array [ p_idx ] ;
return * _p - > read_only ;
}
2014-02-10 01:10:30 +00:00
return _p - > array [ p_idx ] ;
}
int Array : : size ( ) const {
return _p - > array . size ( ) ;
}
2020-05-14 12:29:06 +00:00
2020-12-15 12:04:21 +00:00
bool Array : : is_empty ( ) const {
return _p - > array . is_empty ( ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
void Array : : clear ( ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2014-02-10 01:10:30 +00:00
_p - > array . clear ( ) ;
}
2017-03-05 15:44:50 +00:00
bool Array : : operator = = ( const Array & p_array ) const {
2020-02-01 06:04:14 +00:00
return recursive_equal ( p_array , 0 ) ;
2014-02-10 01:10:30 +00:00
}
2020-11-05 02:01:55 +00:00
bool Array : : operator ! = ( const Array & p_array ) const {
2020-02-01 06:04:14 +00:00
return ! recursive_equal ( p_array , 0 ) ;
}
bool Array : : recursive_equal ( const Array & p_array , int recursion_count ) const {
// Cheap checks
if ( _p = = p_array . _p ) {
return true ;
}
const Vector < Variant > & a1 = _p - > array ;
const Vector < Variant > & a2 = p_array . _p - > array ;
const int size = a1 . size ( ) ;
if ( size ! = a2 . size ( ) ) {
return false ;
}
// Heavy O(n) check
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return true ;
}
recursion_count + + ;
for ( int i = 0 ; i < size ; i + + ) {
if ( ! a1 [ i ] . hash_compare ( a2 [ i ] , recursion_count ) ) {
return false ;
}
}
return true ;
2020-11-05 02:01:55 +00:00
}
bool Array : : operator < ( const Array & p_array ) const {
int a_len = size ( ) ;
int b_len = p_array . size ( ) ;
int min_cmp = MIN ( a_len , b_len ) ;
for ( int i = 0 ; i < min_cmp ; i + + ) {
if ( operator [ ] ( i ) < p_array [ i ] ) {
return true ;
} else if ( p_array [ i ] < operator [ ] ( i ) ) {
return false ;
}
}
return a_len < b_len ;
}
bool Array : : operator < = ( const Array & p_array ) const {
return ! operator > ( p_array ) ;
}
bool Array : : operator > ( const Array & p_array ) const {
return p_array < * this ;
}
bool Array : : operator > = ( const Array & p_array ) const {
return ! operator < ( p_array ) ;
}
2014-02-10 01:10:30 +00:00
uint32_t Array : : hash ( ) const {
2020-02-01 06:04:14 +00:00
return recursive_hash ( 0 ) ;
}
2014-02-10 01:10:30 +00:00
2020-02-01 06:04:14 +00:00
uint32_t Array : : recursive_hash ( int recursion_count ) const {
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return 0 ;
}
2022-06-18 14:20:55 +00:00
uint32_t h = hash_murmur3_one_32 ( Variant : : ARRAY ) ;
2020-02-01 06:04:14 +00:00
recursion_count + + ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < _p - > array . size ( ) ; i + + ) {
2022-06-18 14:20:55 +00:00
h = hash_murmur3_one_32 ( _p - > array [ i ] . recursive_hash ( recursion_count ) , h ) ;
2014-02-10 01:10:30 +00:00
}
2022-06-18 14:20:55 +00:00
return hash_fmix32 ( h ) ;
2014-02-10 01:10:30 +00:00
}
2021-03-15 13:07:34 +00:00
bool Array : : _assign ( const Array & p_array ) {
2020-04-20 22:06:00 +00:00
if ( _p - > typed . type ! = Variant : : OBJECT & & _p - > typed . type = = p_array . _p - > typed . type ) {
2021-03-12 13:35:16 +00:00
//same type or untyped, just reference, should be fine
2020-04-20 22:06:00 +00:00
_ref ( p_array ) ;
} else if ( _p - > typed . type = = Variant : : NIL ) { //from typed to untyped, must copy, but this is cheap anyway
_p - > array = p_array . _p - > array ;
} else if ( p_array . _p - > typed . type = = Variant : : NIL ) { //from untyped to typed, must try to check if they are all valid
2020-04-21 15:16:45 +00:00
if ( _p - > typed . type = = Variant : : OBJECT ) {
//for objects, it needs full validation, either can be converted or fail
for ( int i = 0 ; i < p_array . _p - > array . size ( ) ; i + + ) {
if ( ! _p - > typed . validate ( p_array . _p - > array [ i ] , " assign " ) ) {
2021-03-15 13:07:34 +00:00
return false ;
2020-04-21 15:16:45 +00:00
}
2020-04-20 22:06:00 +00:00
}
2020-04-21 15:16:45 +00:00
_p - > array = p_array . _p - > array ; //then just copy, which is cheap anyway
} else {
//for non objects, we need to check if there is a valid conversion, which needs to happen one by one, so this is the worst case.
Vector < Variant > new_array ;
new_array . resize ( p_array . _p - > array . size ( ) ) ;
for ( int i = 0 ; i < p_array . _p - > array . size ( ) ; i + + ) {
Variant src_val = p_array . _p - > array [ i ] ;
if ( src_val . get_type ( ) = = _p - > typed . type ) {
new_array . write [ i ] = src_val ;
} else if ( Variant : : can_convert_strict ( src_val . get_type ( ) , _p - > typed . type ) ) {
Variant * ptr = & src_val ;
Callable : : CallError ce ;
2020-11-09 03:19:09 +00:00
Variant : : construct ( _p - > typed . type , new_array . write [ i ] , ( const Variant * * ) & ptr , 1 , ce ) ;
2020-04-21 15:16:45 +00:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2021-03-15 13:07:34 +00:00
ERR_FAIL_V_MSG ( false , " Unable to convert array index " + itos ( i ) + " from ' " + Variant : : get_type_name ( src_val . get_type ( ) ) + " ' to ' " + Variant : : get_type_name ( _p - > typed . type ) + " '. " ) ;
2020-04-21 15:16:45 +00:00
}
} else {
2021-03-15 13:07:34 +00:00
ERR_FAIL_V_MSG ( false , " Unable to convert array index " + itos ( i ) + " from ' " + Variant : : get_type_name ( src_val . get_type ( ) ) + " ' to ' " + Variant : : get_type_name ( _p - > typed . type ) + " '. " ) ;
2020-04-21 15:16:45 +00:00
}
}
_p - > array = new_array ;
2020-04-20 22:06:00 +00:00
}
} else if ( _p - > typed . can_reference ( p_array . _p - > typed ) ) { //same type or compatible
_ref ( p_array ) ;
} else {
2021-03-15 13:07:34 +00:00
ERR_FAIL_V_MSG ( false , " Assignment of arrays of incompatible types. " ) ;
2020-04-20 22:06:00 +00:00
}
2021-03-15 13:07:34 +00:00
return true ;
2020-04-20 22:06:00 +00:00
}
void Array : : operator = ( const Array & p_array ) {
2022-05-17 17:14:42 +00:00
if ( this = = & p_array ) {
return ;
}
2021-03-15 13:07:34 +00:00
_ref ( p_array ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void Array : : push_back ( const Variant & p_value ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND ( ! _p - > typed . validate ( p_value , " push_back " ) ) ;
2014-02-10 01:10:30 +00:00
_p - > array . push_back ( p_value ) ;
}
2020-11-08 20:09:45 +00:00
void Array : : append_array ( const Array & p_array ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-06-15 18:32:48 +00:00
for ( int i = 0 ; i < p_array . size ( ) ; + + i ) {
ERR_FAIL_COND ( ! _p - > typed . validate ( p_array [ i ] , " append_array " ) ) ;
}
2020-11-08 20:09:45 +00:00
_p - > array . append_array ( p_array . _p - > array ) ;
}
2014-02-10 01:10:30 +00:00
Error Array : : resize ( int p_new_size ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , ERR_LOCKED , " Array is in read-only state. " ) ;
2014-02-10 01:10:30 +00:00
return _p - > array . resize ( p_new_size ) ;
}
2021-03-27 04:49:39 +00:00
Error Array : : insert ( int p_pos , const Variant & p_value ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , ERR_LOCKED , " Array is in read-only state. " ) ;
2021-03-27 04:49:39 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " insert " ) , ERR_INVALID_PARAMETER ) ;
return _p - > array . insert ( p_pos , p_value ) ;
2014-02-10 01:10:30 +00:00
}
2021-02-25 14:10:39 +00:00
void Array : : fill ( const Variant & p_value ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2021-02-25 14:10:39 +00:00
ERR_FAIL_COND ( ! _p - > typed . validate ( p_value , " fill " ) ) ;
_p - > array . fill ( p_value ) ;
}
2017-03-05 15:44:50 +00:00
void Array : : erase ( const Variant & p_value ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND ( ! _p - > typed . validate ( p_value , " erase " ) ) ;
2014-02-10 01:10:30 +00:00
_p - > array . erase ( p_value ) ;
}
2016-11-18 20:30:16 +00:00
Variant Array : : front ( ) const {
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( _p - > array . size ( ) = = 0 , Variant ( ) , " Can't take value from empty array. " ) ;
2016-11-18 20:30:16 +00:00
return operator [ ] ( 0 ) ;
}
Variant Array : : back ( ) const {
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( _p - > array . size ( ) = = 0 , Variant ( ) , " Can't take value from empty array. " ) ;
2016-11-18 20:30:16 +00:00
return operator [ ] ( _p - > array . size ( ) - 1 ) ;
}
2017-03-05 15:44:50 +00:00
int Array : : find ( const Variant & p_value , int p_from ) const {
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " find " ) , - 1 ) ;
2016-06-10 17:57:56 +00:00
return _p - > array . find ( p_value , p_from ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
int Array : : rfind ( const Variant & p_value , int p_from ) const {
2020-05-14 14:41:43 +00:00
if ( _p - > array . size ( ) = = 0 ) {
2016-06-03 21:10:43 +00:00
return - 1 ;
2020-05-14 14:41:43 +00:00
}
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " rfind " ) , - 1 ) ;
2016-06-03 21:10:43 +00:00
2016-06-10 20:28:09 +00:00
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 ;
}
2017-03-05 15:44:50 +00:00
for ( int i = p_from ; i > = 0 ; i - - ) {
if ( _p - > array [ i ] = = p_value ) {
2016-06-03 21:10:43 +00:00
return i ;
2019-07-01 10:59:42 +00:00
}
}
2016-06-03 21:10:43 +00:00
return - 1 ;
}
2017-03-05 15:44:50 +00:00
int Array : : find_last ( const Variant & p_value ) const {
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " find_last " ) , - 1 ) ;
2016-06-10 20:28:09 +00:00
return rfind ( p_value ) ;
}
2017-03-05 15:44:50 +00:00
int Array : : count ( const Variant & p_value ) const {
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " count " ) , 0 ) ;
2020-05-14 14:41:43 +00:00
if ( _p - > array . size ( ) = = 0 ) {
2016-06-03 21:10:43 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2016-06-03 21:10:43 +00:00
2017-03-05 15:44:50 +00:00
int amount = 0 ;
for ( int i = 0 ; i < _p - > array . size ( ) ; i + + ) {
if ( _p - > array [ i ] = = p_value ) {
2016-06-03 21:10:43 +00:00
amount + + ;
2019-07-01 10:59:42 +00:00
}
}
2016-06-03 21:10:43 +00:00
return amount ;
}
2017-03-05 15:44:50 +00:00
bool Array : : has ( const Variant & p_value ) const {
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " use 'has' " ) , false ) ;
2016-07-02 17:03:35 +00:00
return _p - > array . find ( p_value , 0 ) ! = - 1 ;
}
2021-07-03 22:17:03 +00:00
void Array : : remove_at ( int p_pos ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2021-07-03 22:17:03 +00:00
_p - > array . remove_at ( p_pos ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Array : : set ( int p_idx , const Variant & p_value ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND ( ! _p - > typed . validate ( p_value , " set " ) ) ;
2017-03-05 15:44:50 +00:00
operator [ ] ( p_idx ) = p_value ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
const Variant & Array : : get ( int p_idx ) const {
2014-02-10 01:10:30 +00:00
return operator [ ] ( p_idx ) ;
}
2018-03-09 19:16:08 +00:00
Array Array : : duplicate ( bool p_deep ) const {
2020-02-01 06:04:14 +00:00
return recursive_duplicate ( p_deep , 0 ) ;
}
Array Array : : recursive_duplicate ( bool p_deep , int recursion_count ) const {
2017-09-06 21:13:05 +00:00
Array new_arr ;
2020-02-01 06:04:14 +00:00
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return new_arr ;
}
2017-09-06 21:13:05 +00:00
int element_count = size ( ) ;
new_arr . resize ( element_count ) ;
2020-04-20 22:06:00 +00:00
new_arr . _p - > typed = _p - > typed ;
2020-02-01 06:04:14 +00:00
if ( p_deep ) {
recursion_count + + ;
for ( int i = 0 ; i < element_count ; i + + ) {
new_arr [ i ] = get ( i ) . recursive_duplicate ( true , recursion_count ) ;
}
} else {
for ( int i = 0 ; i < element_count ; i + + ) {
new_arr [ i ] = get ( i ) ;
}
2017-09-06 21:13:05 +00:00
}
return new_arr ;
}
2019-07-17 01:31:58 +00:00
2021-11-27 01:18:26 +00:00
Array Array : : slice ( int p_begin , int p_end , int p_step , bool p_deep ) const {
Array result ;
2019-07-17 01:31:58 +00:00
2021-11-27 01:18:26 +00:00
ERR_FAIL_COND_V_MSG ( p_step = = 0 , result , " Slice step cannot be zero. " ) ;
2019-07-17 01:31:58 +00:00
2022-01-10 12:56:55 +00:00
const int s = size ( ) ;
2019-07-17 01:31:58 +00:00
2022-01-10 12:56:55 +00:00
int begin = CLAMP ( p_begin , - s , s ) ;
if ( begin < 0 ) {
begin + = s ;
}
int end = CLAMP ( p_end , - s , s ) ;
if ( end < 0 ) {
end + = s ;
}
2020-05-01 16:06:36 +00:00
2022-01-10 12:56:55 +00:00
ERR_FAIL_COND_V_MSG ( p_step > 0 & & begin > end , result , " Slice is positive, but bounds is decreasing. " ) ;
ERR_FAIL_COND_V_MSG ( p_step < 0 & & begin < end , result , " Slice is negative, but bounds is increasing. " ) ;
2020-05-01 16:06:36 +00:00
2022-01-10 12:56:55 +00:00
int result_size = ( end - begin ) / p_step ;
2021-11-27 01:18:26 +00:00
result . resize ( result_size ) ;
2022-01-10 12:56:55 +00:00
for ( int src_idx = begin , dest_idx = 0 ; dest_idx < result_size ; + + dest_idx ) {
2021-11-27 01:18:26 +00:00
result [ dest_idx ] = p_deep ? get ( src_idx ) . duplicate ( true ) : get ( src_idx ) ;
src_idx + = p_step ;
2019-07-17 01:31:58 +00:00
}
2021-11-27 01:18:26 +00:00
return result ;
2019-07-17 01:31:58 +00:00
}
2020-10-19 19:21:16 +00:00
Array Array : : filter ( const Callable & p_callable ) const {
Array new_arr ;
new_arr . resize ( size ( ) ) ;
int accepted_count = 0 ;
2021-05-21 12:04:55 +00:00
const Variant * argptrs [ 1 ] ;
2020-10-19 19:21:16 +00:00
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 ( Array ( ) , " Error calling method from 'filter': " + Variant : : get_callable_error_text ( p_callable , argptrs , 1 , ce ) ) ;
}
if ( result . operator bool ( ) ) {
new_arr [ accepted_count ] = get ( i ) ;
accepted_count + + ;
}
}
new_arr . resize ( accepted_count ) ;
return new_arr ;
}
Array Array : : map ( const Callable & p_callable ) const {
Array new_arr ;
new_arr . resize ( size ( ) ) ;
2021-05-21 12:04:55 +00:00
const Variant * argptrs [ 1 ] ;
2020-10-19 19:21:16 +00:00
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 ( Array ( ) , " Error calling method from 'map': " + Variant : : get_callable_error_text ( p_callable , argptrs , 1 , ce ) ) ;
}
new_arr [ i ] = result ;
}
return new_arr ;
}
Variant Array : : reduce ( const Callable & p_callable , const Variant & p_accum ) const {
int start = 0 ;
Variant ret = p_accum ;
if ( ret = = Variant ( ) & & size ( ) > 0 ) {
ret = front ( ) ;
start = 1 ;
}
2021-05-21 12:04:55 +00:00
const Variant * argptrs [ 2 ] ;
2020-10-19 19:21:16 +00:00
for ( int i = start ; i < size ( ) ; i + + ) {
argptrs [ 0 ] = & ret ;
argptrs [ 1 ] = & get ( i ) ;
Variant result ;
Callable : : CallError ce ;
p_callable . call ( argptrs , 2 , result , ce ) ;
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_FAIL_V_MSG ( Variant ( ) , " Error calling method from 'reduce': " + Variant : : get_callable_error_text ( p_callable , argptrs , 2 , ce ) ) ;
}
ret = result ;
}
return ret ;
}
2021-07-10 18:19:47 +00:00
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 ;
}
2014-02-10 01:10:30 +00:00
struct _ArrayVariantSort {
2017-03-05 15:44:50 +00:00
_FORCE_INLINE_ bool operator ( ) ( const Variant & p_l , const Variant & p_r ) const {
bool valid = false ;
2014-02-10 01:10:30 +00:00
Variant res ;
2017-03-05 15:44:50 +00:00
Variant : : evaluate ( Variant : : OP_LESS , p_l , p_r , res , valid ) ;
2020-05-14 14:41:43 +00:00
if ( ! valid ) {
2017-03-05 15:44:50 +00:00
res = false ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
return res ;
}
} ;
2020-10-13 18:59:37 +00:00
void Array : : sort ( ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2014-02-10 01:10:30 +00:00
_p - > array . sort_custom < _ArrayVariantSort > ( ) ;
}
2022-03-28 01:57:20 +00:00
void Array : : sort_custom ( const Callable & p_callable ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-03-28 01:57:20 +00:00
_p - > array . sort_custom < CallableComparator , true > ( p_callable ) ;
2014-02-10 01:10:30 +00:00
}
2018-01-10 18:36:53 +00:00
void Array : : shuffle ( ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2018-01-10 18:36:53 +00:00
const int n = _p - > array . size ( ) ;
2020-05-14 14:41:43 +00:00
if ( n < 2 ) {
2018-01-10 18:36:53 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2018-01-10 18:36:53 +00:00
Variant * data = _p - > array . ptrw ( ) ;
for ( int i = n - 1 ; i > = 1 ; i - - ) {
const int j = Math : : rand ( ) % ( i + 1 ) ;
const Variant tmp = data [ j ] ;
data [ j ] = data [ i ] ;
data [ i ] = tmp ;
}
}
2017-11-02 18:04:38 +00:00
int Array : : bsearch ( const Variant & p_value , bool p_before ) {
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " binary search " ) , - 1 ) ;
2021-09-19 18:13:09 +00:00
SearchArray < Variant , _ArrayVariantSort > avs ;
return avs . bisect ( _p - > array . ptrw ( ) , _p - > array . size ( ) , p_value , p_before ) ;
2017-11-02 18:04:38 +00:00
}
2022-03-28 01:57:20 +00:00
int Array : : bsearch_custom ( const Variant & p_value , const Callable & p_callable , bool p_before ) {
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_V ( ! _p - > typed . validate ( p_value , " custom binary search " ) , - 1 ) ;
2017-11-02 18:04:38 +00:00
2022-03-28 01:57:20 +00:00
return _p - > array . bsearch_custom < CallableComparator > ( p_value , p_before , p_callable ) ;
2017-11-02 18:04:38 +00:00
}
2021-03-14 07:21:32 +00:00
void Array : : reverse ( ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2021-03-14 07:21:32 +00:00
_p - > array . reverse ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Array : : push_front ( const Variant & p_value ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND ( ! _p - > typed . validate ( p_value , " push_front " ) ) ;
2017-03-05 15:44:50 +00:00
_p - > array . insert ( 0 , p_value ) ;
2015-12-12 11:27:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Array : : pop_back ( ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , Variant ( ) , " Array is in read-only state. " ) ;
2020-12-15 12:04:21 +00:00
if ( ! _p - > array . is_empty ( ) ) {
2021-08-26 22:51:17 +00:00
const int n = _p - > array . size ( ) - 1 ;
const Variant ret = _p - > array . get ( n ) ;
2016-08-27 15:33:45 +00:00
_p - > array . resize ( n ) ;
return ret ;
}
return Variant ( ) ;
2015-12-12 11:27:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Array : : pop_front ( ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , Variant ( ) , " Array is in read-only state. " ) ;
2020-12-15 12:04:21 +00:00
if ( ! _p - > array . is_empty ( ) ) {
2021-08-26 22:51:17 +00:00
const Variant ret = _p - > array . get ( 0 ) ;
2021-07-03 22:17:03 +00:00
_p - > array . remove_at ( 0 ) ;
2016-08-27 15:33:45 +00:00
return ret ;
}
return Variant ( ) ;
2015-12-12 11:27:30 +00:00
}
2021-08-26 22:51:17 +00:00
Variant Array : : pop_at ( int p_pos ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , Variant ( ) , " Array is in read-only state. " ) ;
2021-08-26 22:51:17 +00:00
if ( _p - > array . is_empty ( ) ) {
// Return `null` without printing an error to mimic `pop_back()` and `pop_front()` behavior.
return Variant ( ) ;
}
if ( p_pos < 0 ) {
// Relative offset from the end
p_pos = _p - > array . size ( ) + p_pos ;
}
ERR_FAIL_INDEX_V_MSG (
p_pos ,
_p - > array . size ( ) ,
Variant ( ) ,
vformat (
" The calculated index %s is out of bounds (the array has %s elements). Leaving the array untouched and returning `null`. " ,
p_pos ,
_p - > array . size ( ) ) ) ;
const Variant ret = _p - > array . get ( p_pos ) ;
2021-07-03 22:17:03 +00:00
_p - > array . remove_at ( p_pos ) ;
2021-08-26 22:51:17 +00:00
return ret ;
}
2018-08-23 18:31:02 +00:00
Variant Array : : min ( ) const {
Variant minval ;
for ( int i = 0 ; i < size ( ) ; i + + ) {
if ( i = = 0 ) {
minval = get ( i ) ;
} else {
bool valid ;
Variant ret ;
Variant test = get ( i ) ;
Variant : : evaluate ( Variant : : OP_LESS , test , minval , ret , valid ) ;
if ( ! valid ) {
return Variant ( ) ; //not a valid comparison
}
if ( bool ( ret ) ) {
//is less
minval = test ;
}
}
}
return minval ;
}
Variant Array : : max ( ) const {
Variant maxval ;
for ( int i = 0 ; i < size ( ) ; i + + ) {
if ( i = = 0 ) {
maxval = get ( i ) ;
} else {
bool valid ;
Variant ret ;
Variant test = get ( i ) ;
Variant : : evaluate ( Variant : : OP_GREATER , test , maxval , ret , valid ) ;
if ( ! valid ) {
return Variant ( ) ; //not a valid comparison
}
if ( bool ( ret ) ) {
//is less
maxval = test ;
}
}
}
return maxval ;
}
2019-04-19 23:57:29 +00:00
const void * Array : : id ( ) const {
2021-12-30 05:14:09 +00:00
return _p ;
2019-04-19 23:57:29 +00:00
}
2020-04-20 22:06:00 +00:00
Array : : Array ( const Array & p_from , uint32_t p_type , const StringName & p_class_name , const Variant & p_script ) {
_p = memnew ( ArrayPrivate ) ;
_p - > refcount . init ( ) ;
set_typed ( p_type , p_class_name , p_script ) ;
_assign ( p_from ) ;
}
2021-03-15 13:07:34 +00:00
bool Array : : typed_assign ( const Array & p_other ) {
return _assign ( p_other ) ;
}
2020-04-20 22:06:00 +00:00
void Array : : set_typed ( uint32_t p_type , const StringName & p_class_name , const Variant & p_script ) {
2022-05-17 17:14:42 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2020-04-20 22:06:00 +00:00
ERR_FAIL_COND_MSG ( _p - > array . size ( ) > 0 , " Type can only be set when array is empty. " ) ;
ERR_FAIL_COND_MSG ( _p - > refcount . get ( ) > 1 , " Type can only be set when array has no more than one user. " ) ;
ERR_FAIL_COND_MSG ( _p - > typed . type ! = Variant : : NIL , " Type can only be set once. " ) ;
ERR_FAIL_COND_MSG ( p_class_name ! = StringName ( ) & & p_type ! = Variant : : OBJECT , " Class names can only be set for type OBJECT " ) ;
Ref < Script > script = p_script ;
ERR_FAIL_COND_MSG ( script . is_valid ( ) & & p_class_name = = StringName ( ) , " Script class can only be set together with base class name " ) ;
_p - > typed . type = Variant : : Type ( p_type ) ;
_p - > typed . class_name = p_class_name ;
_p - > typed . script = script ;
_p - > typed . where = " TypedArray " ;
}
2021-03-09 15:30:06 +00:00
bool Array : : is_typed ( ) const {
return _p - > typed . type ! = Variant : : NIL ;
}
uint32_t Array : : get_typed_builtin ( ) const {
return _p - > typed . type ;
}
StringName Array : : get_typed_class_name ( ) const {
return _p - > typed . class_name ;
}
Variant Array : : get_typed_script ( ) const {
return _p - > typed . script ;
}
2022-05-17 17:14:42 +00:00
void Array : : set_read_only ( bool p_enable ) {
if ( p_enable = = bool ( _p - > read_only ! = nullptr ) ) {
return ;
}
if ( p_enable ) {
_p - > read_only = memnew ( Variant ) ;
} else {
memdelete ( _p - > read_only ) ;
_p - > read_only = nullptr ;
}
}
bool Array : : is_read_only ( ) const {
return _p - > read_only ! = nullptr ;
}
2017-03-05 15:44:50 +00:00
Array : : Array ( const Array & p_from ) {
2020-04-01 23:20:12 +00:00
_p = nullptr ;
2014-02-10 01:10:30 +00:00
_ref ( p_from ) ;
}
2018-08-23 18:31:02 +00:00
2017-01-11 11:53:31 +00:00
Array : : Array ( ) {
2017-03-05 15:44:50 +00:00
_p = memnew ( ArrayPrivate ) ;
2014-02-10 01:10:30 +00:00
_p - > refcount . init ( ) ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
Array : : ~ Array ( ) {
_unref ( ) ;
}