2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* array.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "array.h"
2017-01-16 08:04:19 +01:00
2020-04-21 00:06:00 +02:00
# include "container_type_validate.h"
2022-10-15 14:43:16 +02:00
# include "core/math/math_funcs.h"
2020-11-07 23:33:38 +01:00
# include "core/object/class_db.h"
# include "core/object/script_language.h"
# include "core/templates/hashfuncs.h"
2021-09-19 20:13:09 +02:00
# include "core/templates/search_array.h"
2020-11-07 23:33:38 +01:00
# include "core/templates/vector.h"
2021-02-04 02:02:06 +01:00
# include "core/variant/callable.h"
2022-12-06 03:46:47 +01:00
# include "core/variant/dictionary.h"
2020-11-07 23:33:38 +01:00
# include "core/variant/variant.h"
2014-02-10 02:10:30 +01:00
2018-03-09 20:16:08 +01:00
class ArrayPrivate {
public :
2014-02-10 02:10:30 +01:00
SafeRefCount refcount ;
Vector < Variant > array ;
2022-05-17 19:14:42 +02: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-21 00:06:00 +02:00
ContainerTypeValidate typed ;
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
void Array : : _ref ( const Array & p_from ) const {
2014-02-10 02:10:30 +01:00
ArrayPrivate * _fp = p_from . _p ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( _fp ) ; // Should NOT happen.
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( _fp = = _p ) {
2017-09-22 05:58:29 +02:00
return ; // whatever it is, nothing to do here move along
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
bool success = _fp - > refcount . ref ( ) ;
2017-09-22 05:58:29 +02:00
ERR_FAIL_COND ( ! success ) ; // should really not happen either
2014-02-10 02:10:30 +01:00
_unref ( ) ;
2022-11-27 08:56:53 +01:00
_p = _fp ;
2014-02-10 02:10:30 +01:00
}
void Array : : _unref ( ) const {
2020-05-14 16:41:43 +02:00
if ( ! _p ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( _p - > refcount . unref ( ) ) {
2022-05-17 19:14:42 +02:00
if ( _p - > read_only ) {
memdelete ( _p - > read_only ) ;
}
2014-02-10 02:10:30 +01:00
memdelete ( _p ) ;
}
2020-04-02 01:20:12 +02:00
_p = nullptr ;
2014-02-10 02:10:30 +01:00
}
2023-12-24 13:44:21 +01:00
Array : : Iterator Array : : begin ( ) {
return Iterator ( _p - > array . ptrw ( ) , _p - > read_only ) ;
}
Array : : Iterator Array : : end ( ) {
return Iterator ( _p - > array . ptrw ( ) + _p - > array . size ( ) , _p - > read_only ) ;
}
Array : : ConstIterator Array : : begin ( ) const {
return ConstIterator ( _p - > array . ptr ( ) , _p - > read_only ) ;
}
Array : : ConstIterator Array : : end ( ) const {
return ConstIterator ( _p - > array . ptr ( ) + _p - > array . size ( ) , _p - > read_only ) ;
}
2017-03-05 16:44:50 +01:00
Variant & Array : : operator [ ] ( int p_idx ) {
2022-05-17 19:14:42 +02:00
if ( unlikely ( _p - > read_only ) ) {
* _p - > read_only = _p - > array [ p_idx ] ;
return * _p - > read_only ;
}
2018-07-25 03:11:03 +02:00
return _p - > array . write [ p_idx ] ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Variant & Array : : operator [ ] ( int p_idx ) const {
2022-05-17 19:14:42 +02:00
if ( unlikely ( _p - > read_only ) ) {
* _p - > read_only = _p - > array [ p_idx ] ;
return * _p - > read_only ;
}
2014-02-10 02:10:30 +01:00
return _p - > array [ p_idx ] ;
}
int Array : : size ( ) const {
return _p - > array . size ( ) ;
}
2020-05-14 14:29:06 +02:00
2020-12-15 13:04:21 +01:00
bool Array : : is_empty ( ) const {
return _p - > array . is_empty ( ) ;
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
void Array : : clear ( ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2014-02-10 02:10:30 +01:00
_p - > array . clear ( ) ;
}
2017-03-05 16:44:50 +01:00
bool Array : : operator = = ( const Array & p_array ) const {
2020-02-01 07:04:14 +01:00
return recursive_equal ( p_array , 0 ) ;
2014-02-10 02:10:30 +01:00
}
2020-11-05 03:01:55 +01:00
bool Array : : operator ! = ( const Array & p_array ) const {
2020-02-01 07:04:14 +01: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 + + ) {
2023-03-08 04:13:00 +01:00
if ( ! a1 [ i ] . hash_compare ( a2 [ i ] , recursion_count , false ) ) {
2020-02-01 07:04:14 +01:00
return false ;
}
}
return true ;
2020-11-05 03:01:55 +01: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 02:10:30 +01:00
uint32_t Array : : hash ( ) const {
2020-02-01 07:04:14 +01:00
return recursive_hash ( 0 ) ;
}
2014-02-10 02:10:30 +01:00
2020-02-01 07:04:14 +01: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 16:20:55 +02:00
uint32_t h = hash_murmur3_one_32 ( Variant : : ARRAY ) ;
2020-02-01 07:04:14 +01:00
recursion_count + + ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < _p - > array . size ( ) ; i + + ) {
2022-06-18 16:20:55 +02:00
h = hash_murmur3_one_32 ( _p - > array [ i ] . recursive_hash ( recursion_count ) , h ) ;
2014-02-10 02:10:30 +01:00
}
2022-06-18 16:20:55 +02:00
return hash_fmix32 ( h ) ;
2014-02-10 02:10:30 +01:00
}
2022-11-27 08:56:53 +01:00
void Array : : operator = ( const Array & p_array ) {
if ( this = = & p_array ) {
return ;
}
_ref ( p_array ) ;
}
void Array : : assign ( const Array & p_array ) {
const ContainerTypeValidate & typed = _p - > typed ;
const ContainerTypeValidate & source_typed = p_array . _p - > typed ;
2022-12-06 03:46:47 +01:00
2022-11-27 08:56:53 +01:00
if ( typed = = source_typed | | typed . type = = Variant : : NIL | | ( source_typed . type = = Variant : : OBJECT & & typed . can_reference ( source_typed ) ) ) {
// from same to same or
// from anything to variants or
// from subclasses to base classes
2020-04-21 00:06:00 +02:00
_p - > array = p_array . _p - > array ;
2022-11-27 08:56:53 +01:00
return ;
}
2020-04-21 17:16:45 +02:00
2022-11-27 08:56:53 +01:00
const Variant * source = p_array . _p - > array . ptr ( ) ;
int size = p_array . _p - > array . size ( ) ;
if ( ( source_typed . type = = Variant : : NIL & & typed . type = = Variant : : OBJECT ) | | ( source_typed . type = = Variant : : OBJECT & & source_typed . can_reference ( typed ) ) ) {
// from variants to objects or
// from base classes to subclasses
for ( int i = 0 ; i < size ; i + + ) {
const Variant & element = source [ i ] ;
if ( element . get_type ( ) ! = Variant : : NIL & & ( element . get_type ( ) ! = Variant : : OBJECT | | ! typed . validate_object ( element , " assign " ) ) ) {
2024-07-03 14:23:26 +02:00
ERR_FAIL_MSG ( vformat ( R " (Unable to convert array index %d from " % s " to " % s " .) " , i , Variant : : get_type_name ( element . get_type ( ) ) , Variant : : get_type_name ( typed . type ) ) ) ;
2020-04-21 17:16:45 +02:00
}
2022-11-27 08:56:53 +01:00
}
_p - > array = p_array . _p - > array ;
return ;
}
2023-02-01 23:23:47 +01:00
if ( typed . type = = Variant : : OBJECT | | source_typed . type = = Variant : : OBJECT ) {
ERR_FAIL_MSG ( vformat ( R " (Cannot assign contents of " Array [ % s ] " to " Array [ % s ] " .) " , Variant : : get_type_name ( source_typed . type ) , Variant : : get_type_name ( typed . type ) ) ) ;
}
2020-04-21 17:16:45 +02:00
2022-11-27 08:56:53 +01:00
Vector < Variant > array ;
array . resize ( size ) ;
Variant * data = array . ptrw ( ) ;
if ( source_typed . type = = Variant : : NIL & & typed . type ! = Variant : : OBJECT ) {
// from variants to primitives
for ( int i = 0 ; i < size ; i + + ) {
const Variant * value = source + i ;
if ( value - > get_type ( ) = = typed . type ) {
data [ i ] = * value ;
continue ;
}
if ( ! Variant : : can_convert_strict ( value - > get_type ( ) , typed . type ) ) {
2024-07-03 14:23:26 +02:00
ERR_FAIL_MSG ( vformat ( R " (Unable to convert array index %d from " % s " to " % s " .) " , i , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed . type ) ) ) ;
2022-11-27 08:56:53 +01:00
}
Callable : : CallError ce ;
Variant : : construct ( typed . type , data [ i ] , & value , 1 , ce ) ;
2024-07-03 14:23:26 +02:00
ERR_FAIL_COND_MSG ( ce . error , vformat ( R " (Unable to convert array index %d from " % s " to " % s " .) " , i , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed . type ) ) ) ;
2022-11-27 08:56:53 +01:00
}
} else if ( Variant : : can_convert_strict ( source_typed . type , typed . type ) ) {
2023-02-01 08:45:41 +01:00
// from primitives to different convertible primitives
2022-11-27 08:56:53 +01:00
for ( int i = 0 ; i < size ; i + + ) {
const Variant * value = source + i ;
Callable : : CallError ce ;
Variant : : construct ( typed . type , data [ i ] , & value , 1 , ce ) ;
2024-07-03 14:23:26 +02:00
ERR_FAIL_COND_MSG ( ce . error , vformat ( R " (Unable to convert array index %d from " % s " to " % s " .) " , i , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed . type ) ) ) ;
2020-04-21 00:06:00 +02:00
}
} else {
2022-11-27 08:56:53 +01:00
ERR_FAIL_MSG ( vformat ( R " (Cannot assign contents of " Array [ % s ] " to " Array [ % s ] " .) " , Variant : : get_type_name ( source_typed . type ) , Variant : : get_type_name ( typed . type ) ) ) ;
2020-04-21 00:06:00 +02:00
}
2022-11-27 08:56:53 +01:00
_p - > array = array ;
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2017-03-05 16:44:50 +01:00
void Array : : push_back ( const Variant & p_value ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND ( ! _p - > typed . validate ( value , " push_back " ) ) ;
_p - > array . push_back ( value ) ;
2014-02-10 02:10:30 +01:00
}
2020-11-08 21:09:45 +01:00
void Array : : append_array ( const Array & p_array ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Vector < Variant > validated_array = p_array . _p - > array ;
for ( int i = 0 ; i < validated_array . size ( ) ; + + i ) {
ERR_FAIL_COND ( ! _p - > typed . validate ( validated_array . write [ i ] , " append_array " ) ) ;
2022-06-15 20:32:48 +02:00
}
2022-12-06 03:46:47 +01:00
_p - > array . append_array ( validated_array ) ;
2020-11-08 21:09:45 +01:00
}
2014-02-10 02:10:30 +01:00
Error Array : : resize ( int p_new_size ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , ERR_LOCKED , " Array is in read-only state. " ) ;
2022-11-27 08:56:53 +01:00
Variant : : Type & variant_type = _p - > typed . type ;
int old_size = _p - > array . size ( ) ;
Error err = _p - > array . resize_zeroed ( p_new_size ) ;
if ( ! err & & variant_type ! = Variant : : NIL & & variant_type ! = Variant : : OBJECT ) {
for ( int i = old_size ; i < p_new_size ; i + + ) {
VariantInternal : : initialize ( & _p - > array . write [ i ] , variant_type ) ;
}
}
return err ;
2014-02-10 02:10:30 +01:00
}
2021-03-27 05:49:39 +01:00
Error Array : : insert ( int p_pos , const Variant & p_value ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , ERR_LOCKED , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " insert " ) , ERR_INVALID_PARAMETER ) ;
return _p - > array . insert ( p_pos , value ) ;
2014-02-10 02:10:30 +01:00
}
2021-02-25 15:10:39 +01:00
void Array : : fill ( const Variant & p_value ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND ( ! _p - > typed . validate ( value , " fill " ) ) ;
_p - > array . fill ( value ) ;
2021-02-25 15:10:39 +01:00
}
2017-03-05 16:44:50 +01:00
void Array : : erase ( const Variant & p_value ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND ( ! _p - > typed . validate ( value , " erase " ) ) ;
_p - > array . erase ( value ) ;
2014-02-10 02:10:30 +01:00
}
2016-11-18 21:30:16 +01:00
Variant Array : : front ( ) const {
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND_V_MSG ( _p - > array . is_empty ( ) , Variant ( ) , " Can't take value from empty array. " ) ;
2016-11-18 21:30:16 +01:00
return operator [ ] ( 0 ) ;
}
Variant Array : : back ( ) const {
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND_V_MSG ( _p - > array . is_empty ( ) , Variant ( ) , " Can't take value from empty array. " ) ;
2016-11-18 21:30:16 +01:00
return operator [ ] ( _p - > array . size ( ) - 1 ) ;
}
2022-10-15 14:43:16 +02:00
Variant Array : : pick_random ( ) const {
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND_V_MSG ( _p - > array . is_empty ( ) , Variant ( ) , " Can't take value from empty array. " ) ;
2022-10-15 14:43:16 +02:00
return operator [ ] ( Math : : rand ( ) % _p - > array . size ( ) ) ;
}
2017-03-05 16:44:50 +01:00
int Array : : find ( const Variant & p_value , int p_from ) const {
2022-12-06 03:46:47 +01:00
if ( _p - > array . size ( ) = = 0 ) {
return - 1 ;
}
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " find " ) , - 1 ) ;
int ret = - 1 ;
if ( p_from < 0 | | size ( ) = = 0 ) {
return ret ;
}
for ( int i = p_from ; i < size ( ) ; i + + ) {
if ( StringLikeVariantComparator : : compare ( _p - > array [ i ] , value ) ) {
ret = i ;
break ;
}
}
return ret ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int Array : : rfind ( const Variant & p_value , int p_from ) const {
2020-05-14 16:41:43 +02:00
if ( _p - > array . size ( ) = = 0 ) {
2016-06-03 23:10:43 +02:00
return - 1 ;
2020-05-14 16:41:43 +02:00
}
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " rfind " ) , - 1 ) ;
2016-06-03 23:10:43 +02:00
2016-06-10 22:28:09 +02: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 16:44:50 +01:00
for ( int i = p_from ; i > = 0 ; i - - ) {
2022-12-06 03:46:47 +01:00
if ( StringLikeVariantComparator : : compare ( _p - > array [ i ] , value ) ) {
2016-06-03 23:10:43 +02:00
return i ;
2019-07-01 12:59:42 +02:00
}
}
2016-06-03 23:10:43 +02:00
return - 1 ;
}
2017-03-05 16:44:50 +01:00
int Array : : count ( const Variant & p_value ) const {
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " count " ) , 0 ) ;
2020-05-14 16:41:43 +02:00
if ( _p - > array . size ( ) = = 0 ) {
2016-06-03 23:10:43 +02:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2016-06-03 23:10:43 +02:00
2017-03-05 16:44:50 +01:00
int amount = 0 ;
for ( int i = 0 ; i < _p - > array . size ( ) ; i + + ) {
2022-12-06 03:46:47 +01:00
if ( StringLikeVariantComparator : : compare ( _p - > array [ i ] , value ) ) {
2016-06-03 23:10:43 +02:00
amount + + ;
2019-07-01 12:59:42 +02:00
}
}
2016-06-03 23:10:43 +02:00
return amount ;
}
2017-03-05 16:44:50 +01:00
bool Array : : has ( const Variant & p_value ) const {
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " use 'has' " ) , false ) ;
2020-04-21 00:06:00 +02:00
2022-12-06 03:46:47 +01:00
return find ( value ) ! = - 1 ;
2016-07-02 19:03:35 +02:00
}
2021-07-04 00:17:03 +02:00
void Array : : remove_at ( int p_pos ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2021-07-04 00:17:03 +02:00
_p - > array . remove_at ( p_pos ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void Array : : set ( int p_idx , const Variant & p_value ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND ( ! _p - > typed . validate ( value , " set " ) ) ;
2020-04-21 00:06:00 +02:00
2022-12-06 03:46:47 +01:00
operator [ ] ( p_idx ) = value ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Variant & Array : : get ( int p_idx ) const {
2014-02-10 02:10:30 +01:00
return operator [ ] ( p_idx ) ;
}
2018-03-09 20:16:08 +01:00
Array Array : : duplicate ( bool p_deep ) const {
2020-02-01 07:04:14 +01:00
return recursive_duplicate ( p_deep , 0 ) ;
}
Array Array : : recursive_duplicate ( bool p_deep , int recursion_count ) const {
2017-09-06 23:13:05 +02:00
Array new_arr ;
2022-11-27 08:56:53 +01:00
new_arr . _p - > typed = _p - > typed ;
2020-02-01 07:04:14 +01:00
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return new_arr ;
}
if ( p_deep ) {
recursion_count + + ;
2022-11-27 08:56:53 +01:00
int element_count = size ( ) ;
new_arr . resize ( element_count ) ;
2020-02-01 07:04:14 +01:00
for ( int i = 0 ; i < element_count ; i + + ) {
new_arr [ i ] = get ( i ) . recursive_duplicate ( true , recursion_count ) ;
}
} else {
2022-11-27 08:56:53 +01:00
new_arr . _p - > array = _p - > array ;
2017-09-06 23:13:05 +02:00
}
return new_arr ;
}
2019-07-17 03:31:58 +02:00
2021-11-27 02:18:26 +01:00
Array Array : : slice ( int p_begin , int p_end , int p_step , bool p_deep ) const {
Array result ;
2022-10-09 00:10:00 +02:00
result . _p - > typed = _p - > typed ;
2019-07-17 03:31:58 +02:00
2021-11-27 02:18:26 +01:00
ERR_FAIL_COND_V_MSG ( p_step = = 0 , result , " Slice step cannot be zero. " ) ;
2019-07-17 03:31:58 +02:00
2022-01-10 13:56:55 +01:00
const int s = size ( ) ;
2019-07-17 03:31:58 +02:00
2023-07-06 15:03:17 +02:00
if ( s = = 0 | | ( p_begin < - s & & p_step < 0 ) | | ( p_begin > = s & & p_step > 0 ) ) {
return result ;
}
int begin = CLAMP ( p_begin , - s , s - 1 ) ;
2022-01-10 13:56:55 +01:00
if ( begin < 0 ) {
begin + = s ;
}
2023-07-06 15:03:17 +02:00
int end = CLAMP ( p_end , - s - 1 , s ) ;
2022-01-10 13:56:55 +01:00
if ( end < 0 ) {
end + = s ;
}
2020-05-01 18:06:36 +02:00
2023-07-06 15:03:17 +02:00
ERR_FAIL_COND_V_MSG ( p_step > 0 & & begin > end , result , " Slice step is positive, but bounds are decreasing. " ) ;
ERR_FAIL_COND_V_MSG ( p_step < 0 & & begin < end , result , " Slice step is negative, but bounds are increasing. " ) ;
2020-05-01 18:06:36 +02:00
2023-03-14 14:11:05 +01:00
int result_size = ( end - begin ) / p_step + ( ( ( end - begin ) % p_step ! = 0 ) ? 1 : 0 ) ;
2021-11-27 02:18:26 +01:00
result . resize ( result_size ) ;
2022-01-10 13:56:55 +01:00
for ( int src_idx = begin , dest_idx = 0 ; dest_idx < result_size ; + + dest_idx ) {
2021-11-27 02:18:26 +01:00
result [ dest_idx ] = p_deep ? get ( src_idx ) . duplicate ( true ) : get ( src_idx ) ;
src_idx + = p_step ;
2019-07-17 03:31:58 +02:00
}
2021-11-27 02:18:26 +01:00
return result ;
2019-07-17 03:31:58 +02:00
}
2020-10-19 21:21:16 +02:00
Array Array : : filter ( const Callable & p_callable ) const {
Array new_arr ;
new_arr . resize ( size ( ) ) ;
2022-10-09 00:10:00 +02:00
new_arr . _p - > typed = _p - > typed ;
2020-10-19 21:21:16 +02:00
int accepted_count = 0 ;
2021-05-21 14:04:55 +02:00
const Variant * argptrs [ 1 ] ;
2020-10-19 21:21:16 +02:00
for ( int i = 0 ; i < size ( ) ; i + + ) {
argptrs [ 0 ] = & get ( i ) ;
Variant result ;
Callable : : CallError ce ;
2022-07-28 22:56:41 +02:00
p_callable . callp ( argptrs , 1 , result , ce ) ;
2020-10-19 21:21:16 +02:00
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 14:04:55 +02:00
const Variant * argptrs [ 1 ] ;
2020-10-19 21:21:16 +02:00
for ( int i = 0 ; i < size ( ) ; i + + ) {
argptrs [ 0 ] = & get ( i ) ;
Variant result ;
Callable : : CallError ce ;
2022-07-28 22:56:41 +02:00
p_callable . callp ( argptrs , 1 , result , ce ) ;
2020-10-19 21:21:16 +02:00
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 14:04:55 +02:00
const Variant * argptrs [ 2 ] ;
2020-10-19 21:21:16 +02:00
for ( int i = start ; i < size ( ) ; i + + ) {
argptrs [ 0 ] = & ret ;
argptrs [ 1 ] = & get ( i ) ;
Variant result ;
Callable : : CallError ce ;
2022-07-28 22:56:41 +02:00
p_callable . callp ( argptrs , 2 , result , ce ) ;
2020-10-19 21:21:16 +02:00
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 20:19:47 +02: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 ;
2022-07-28 22:56:41 +02:00
p_callable . callp ( argptrs , 1 , result , ce ) ;
2021-07-10 20:19:47 +02:00
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 ;
2022-07-28 22:56:41 +02:00
p_callable . callp ( argptrs , 1 , result , ce ) ;
2021-07-10 20:19:47 +02:00
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 02:10:30 +01:00
struct _ArrayVariantSort {
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ bool operator ( ) ( const Variant & p_l , const Variant & p_r ) const {
bool valid = false ;
2014-02-10 02:10:30 +01:00
Variant res ;
2017-03-05 16:44:50 +01:00
Variant : : evaluate ( Variant : : OP_LESS , p_l , p_r , res , valid ) ;
2020-05-14 16:41:43 +02:00
if ( ! valid ) {
2017-03-05 16:44:50 +01:00
res = false ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return res ;
}
} ;
2020-10-13 20:59:37 +02:00
void Array : : sort ( ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2014-02-10 02:10:30 +01:00
_p - > array . sort_custom < _ArrayVariantSort > ( ) ;
}
2022-03-28 03:57:20 +02:00
void Array : : sort_custom ( const Callable & p_callable ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-03-28 03:57:20 +02:00
_p - > array . sort_custom < CallableComparator , true > ( p_callable ) ;
2014-02-10 02:10:30 +01:00
}
2018-01-10 19:36:53 +01:00
void Array : : shuffle ( ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2018-01-10 19:36:53 +01:00
const int n = _p - > array . size ( ) ;
2020-05-14 16:41:43 +02:00
if ( n < 2 ) {
2018-01-10 19:36:53 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-01-10 19:36:53 +01: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 ;
}
}
2023-01-20 20:18:56 +01:00
int Array : : bsearch ( const Variant & p_value , bool p_before ) const {
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " binary search " ) , - 1 ) ;
2021-09-19 20:13:09 +02:00
SearchArray < Variant , _ArrayVariantSort > avs ;
2022-12-06 03:46:47 +01:00
return avs . bisect ( _p - > array . ptrw ( ) , _p - > array . size ( ) , value , p_before ) ;
2017-11-02 19:04:38 +01:00
}
2023-01-20 20:18:56 +01:00
int Array : : bsearch_custom ( const Variant & p_value , const Callable & p_callable , bool p_before ) const {
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed . validate ( value , " custom binary search " ) , - 1 ) ;
2017-11-02 19:04:38 +01:00
2022-12-06 03:46:47 +01:00
return _p - > array . bsearch_custom < CallableComparator > ( value , p_before , p_callable ) ;
2017-11-02 19:04:38 +01:00
}
2021-03-14 08:21:32 +01:00
void Array : : reverse ( ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2021-03-14 08:21:32 +01:00
_p - > array . reverse ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void Array : : push_front ( const Variant & p_value ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2022-12-06 03:46:47 +01:00
Variant value = p_value ;
ERR_FAIL_COND ( ! _p - > typed . validate ( value , " push_front " ) ) ;
_p - > array . insert ( 0 , value ) ;
2015-12-12 12:27:30 +01:00
}
2017-03-05 16:44:50 +01:00
Variant Array : : pop_back ( ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , Variant ( ) , " Array is in read-only state. " ) ;
2020-12-15 13:04:21 +01:00
if ( ! _p - > array . is_empty ( ) ) {
2021-08-27 00:51:17 +02:00
const int n = _p - > array . size ( ) - 1 ;
const Variant ret = _p - > array . get ( n ) ;
2016-08-27 17:33:45 +02:00
_p - > array . resize ( n ) ;
return ret ;
}
return Variant ( ) ;
2015-12-12 12:27:30 +01:00
}
2017-03-05 16:44:50 +01:00
Variant Array : : pop_front ( ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , Variant ( ) , " Array is in read-only state. " ) ;
2020-12-15 13:04:21 +01:00
if ( ! _p - > array . is_empty ( ) ) {
2021-08-27 00:51:17 +02:00
const Variant ret = _p - > array . get ( 0 ) ;
2021-07-04 00:17:03 +02:00
_p - > array . remove_at ( 0 ) ;
2016-08-27 17:33:45 +02:00
return ret ;
}
return Variant ( ) ;
2015-12-12 12:27:30 +01:00
}
2021-08-27 00:51:17 +02:00
Variant Array : : pop_at ( int p_pos ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , Variant ( ) , " Array is in read-only state. " ) ;
2021-08-27 00:51:17 +02: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-04 00:17:03 +02:00
_p - > array . remove_at ( p_pos ) ;
2021-08-27 00:51:17 +02:00
return ret ;
}
2018-08-23 20:31:02 +02: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-20 01:57:29 +02:00
const void * Array : : id ( ) const {
2021-12-30 06:14:09 +01:00
return _p ;
2019-04-20 01:57:29 +02:00
}
2020-04-21 00:06:00 +02: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 ) ;
2022-11-27 08:56:53 +01:00
assign ( p_from ) ;
2021-03-15 14:07:34 +01:00
}
2020-04-21 00:06:00 +02:00
void Array : : set_typed ( uint32_t p_type , const StringName & p_class_name , const Variant & p_script ) {
2022-05-17 19:14:42 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Array is in read-only state. " ) ;
2020-04-21 00:06:00 +02: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 16:30:06 +01:00
bool Array : : is_typed ( ) const {
return _p - > typed . type ! = Variant : : NIL ;
}
2022-11-27 08:56:53 +01:00
bool Array : : is_same_typed ( const Array & p_other ) const {
return _p - > typed = = p_other . _p - > typed ;
}
2021-03-09 16:30:06 +01:00
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 ;
}
2023-01-22 10:07:48 +01:00
void Array : : make_read_only ( ) {
if ( _p - > read_only = = nullptr ) {
2022-05-17 19:14:42 +02:00
_p - > read_only = memnew ( Variant ) ;
}
}
bool Array : : is_read_only ( ) const {
return _p - > read_only ! = nullptr ;
}
2017-03-05 16:44:50 +01:00
Array : : Array ( const Array & p_from ) {
2020-04-02 01:20:12 +02:00
_p = nullptr ;
2014-02-10 02:10:30 +01:00
_ref ( p_from ) ;
}
2018-08-23 20:31:02 +02:00
2017-01-11 12:53:31 +01:00
Array : : Array ( ) {
2017-03-05 16:44:50 +01:00
_p = memnew ( ArrayPrivate ) ;
2014-02-10 02:10:30 +01:00
_p - > refcount . init ( ) ;
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
Array : : ~ Array ( ) {
_unref ( ) ;
}