2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* dictionary.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-09 22:10:30 -03:00
# include "dictionary.h"
2017-01-16 08:04:19 +01:00
2022-05-08 10:09:19 +02:00
# include "core/templates/hash_map.h"
2020-11-07 19:33:38 -03:00
# include "core/templates/safe_refcount.h"
2023-06-24 13:03:28 -05:00
# include "core/variant/container_type_validate.h"
2020-11-07 19:33:38 -03:00
# include "core/variant/variant.h"
2021-07-01 16:03:37 -03:00
// required in this order by VariantInternal, do not remove this comment.
# include "core/object/class_db.h"
# include "core/object/object.h"
# include "core/variant/type_info.h"
# include "core/variant/variant_internal.h"
2014-02-09 22:10:30 -03:00
struct DictionaryPrivate {
SafeRefCount refcount ;
2022-05-16 15:44:43 +02:00
Variant * read_only = nullptr ; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
2022-12-05 21:46:47 -05:00
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > variant_map ;
2023-06-24 13:03:28 -05:00
ContainerTypeValidate typed_key ;
ContainerTypeValidate typed_value ;
Variant * typed_fallback = nullptr ; // Allows a typed dictionary to return dummy values when attempting an invalid access.
2017-01-08 14:16:21 -03:00
} ;
2014-02-09 22:10:30 -03:00
2025-03-12 06:43:48 +08:00
Dictionary : : ConstIterator Dictionary : : begin ( ) const {
return _p - > variant_map . begin ( ) ;
}
Dictionary : : ConstIterator Dictionary : : end ( ) const {
return _p - > variant_map . end ( ) ;
}
2025-03-14 03:04:25 +08:00
LocalVector < Variant > Dictionary : : get_key_list ( ) const {
LocalVector < Variant > keys ;
2017-01-08 14:16:21 -03:00
2025-03-14 03:04:25 +08:00
keys . reserve ( _p - > variant_map . size ( ) ) ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2025-03-14 03:04:25 +08:00
keys . push_back ( E . key ) ;
2017-01-08 14:16:21 -03:00
}
2025-03-14 03:04:25 +08:00
return keys ;
2014-02-09 22:10:30 -03:00
}
2018-05-19 17:57:44 -03:00
Variant Dictionary : : get_key_at_index ( int p_index ) const {
int index = 0 ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2018-05-19 17:57:44 -03:00
if ( index = = p_index ) {
2022-05-08 10:09:19 +02:00
return E . key ;
2018-05-19 17:57:44 -03:00
}
index + + ;
}
return Variant ( ) ;
}
Variant Dictionary : : get_value_at_index ( int p_index ) const {
int index = 0 ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2018-05-19 17:57:44 -03:00
if ( index = = p_index ) {
2022-05-08 10:09:19 +02:00
return E . value ;
2018-05-19 17:57:44 -03:00
}
index + + ;
}
return Variant ( ) ;
}
2024-09-10 08:56:53 -05:00
// WARNING: This operator does not validate the value type. For scripting/extensions this is
// done in `variant_setget.cpp`. Consider using `set()` if the data might be invalid.
2017-03-05 16:44:50 +01:00
Variant & Dictionary : : operator [ ] ( const Variant & p_key ) {
2024-09-10 08:56:53 -05:00
Variant key = p_key ;
if ( unlikely ( ! _p - > typed_key . validate ( key , " use `operator[]` " ) ) ) {
if ( unlikely ( ! _p - > typed_fallback ) ) {
_p - > typed_fallback = memnew ( Variant ) ;
}
VariantInternal : : initialize ( _p - > typed_fallback , _p - > typed_value . type ) ;
return * _p - > typed_fallback ;
} else if ( unlikely ( _p - > read_only ) ) {
if ( likely ( _p - > variant_map . has ( key ) ) ) {
* _p - > read_only = _p - > variant_map [ key ] ;
2023-03-11 01:08:23 +01:00
} else {
2024-09-10 08:56:53 -05:00
VariantInternal : : initialize ( _p - > read_only , _p - > typed_value . type ) ;
2022-05-16 15:44:43 +02:00
}
return * _p - > read_only ;
2021-07-01 16:03:37 -03:00
} else {
2025-03-05 13:07:30 -05:00
const uint32_t old_size = _p - > variant_map . size ( ) ;
Variant & value = _p - > variant_map [ key ] ;
if ( _p - > variant_map . size ( ) > old_size ) {
VariantInternal : : initialize ( & value , _p - > typed_value . type ) ;
2024-09-10 08:56:53 -05:00
}
2025-03-05 13:07:30 -05:00
return value ;
2021-07-01 16:03:37 -03:00
}
2014-02-09 22:10:30 -03:00
}
2017-03-05 16:44:50 +01:00
const Variant & Dictionary : : operator [ ] ( const Variant & p_key ) const {
2024-09-10 08:56:53 -05:00
Variant key = p_key ;
if ( unlikely ( ! _p - > typed_key . validate ( key , " use `operator[]` " ) ) ) {
if ( unlikely ( ! _p - > typed_fallback ) ) {
_p - > typed_fallback = memnew ( Variant ) ;
}
VariantInternal : : initialize ( _p - > typed_fallback , _p - > typed_value . type ) ;
return * _p - > typed_fallback ;
} else {
// Will not insert key, so no initialization is necessary.
return _p - > variant_map [ key ] ;
}
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2017-03-05 16:44:50 +01:00
const Variant * Dictionary : : getptr ( const Variant & p_key ) const {
2024-09-10 08:56:53 -05:00
Variant key = p_key ;
if ( unlikely ( ! _p - > typed_key . validate ( key , " getptr " ) ) ) {
return nullptr ;
}
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : ConstIterator E ( _p - > variant_map . find ( key ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! E ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2022-05-08 10:09:19 +02:00
return & E - > value ;
2014-02-09 22:10:30 -03:00
}
2017-01-08 14:16:21 -03:00
2024-09-10 08:56:53 -05:00
// WARNING: This method does not validate the value type.
2017-03-05 16:44:50 +01:00
Variant * Dictionary : : getptr ( const Variant & p_key ) {
2024-09-10 08:56:53 -05:00
Variant key = p_key ;
if ( unlikely ( ! _p - > typed_key . validate ( key , " getptr " ) ) ) {
return nullptr ;
}
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : Iterator E ( _p - > variant_map . find ( key ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! E ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2022-05-16 15:44:43 +02:00
if ( unlikely ( _p - > read_only ! = nullptr ) ) {
* _p - > read_only = E - > value ;
return _p - > read_only ;
} else {
return & E - > value ;
}
2014-02-09 22:10:30 -03:00
}
2017-03-05 16:44:50 +01:00
Variant Dictionary : : get_valid ( const Variant & p_key ) const {
2023-06-24 13:03:28 -05:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " get_valid " ) , Variant ( ) ) ;
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : ConstIterator E ( _p - > variant_map . find ( key ) ) ;
2017-11-05 15:27:28 +01:00
2020-05-14 16:41:43 +02:00
if ( ! E ) {
2014-02-09 22:10:30 -03:00
return Variant ( ) ;
2020-05-14 16:41:43 +02:00
}
2022-05-08 10:09:19 +02:00
return E - > value ;
2014-02-09 22:10:30 -03:00
}
2018-07-30 00:04:32 -04:00
Variant Dictionary : : get ( const Variant & p_key , const Variant & p_default ) const {
2023-06-24 13:03:28 -05:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " get " ) , p_default ) ;
const Variant * result = getptr ( key ) ;
2018-07-30 00:04:32 -04:00
if ( ! result ) {
return p_default ;
}
return * result ;
}
2023-06-10 15:13:38 -05:00
Variant Dictionary : : get_or_add ( const Variant & p_key , const Variant & p_default ) {
2023-06-24 13:03:28 -05:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " get " ) , p_default ) ;
const Variant * result = getptr ( key ) ;
2023-06-10 15:13:38 -05:00
if ( ! result ) {
2023-06-24 13:03:28 -05:00
Variant value = p_default ;
ERR_FAIL_COND_V ( ! _p - > typed_value . validate ( value , " add " ) , value ) ;
operator [ ] ( key ) = value ;
return value ;
2023-06-10 15:13:38 -05:00
}
return * result ;
}
2024-09-10 08:56:53 -05:00
bool Dictionary : : set ( const Variant & p_key , const Variant & p_value ) {
ERR_FAIL_COND_V_MSG ( _p - > read_only , false , " Dictionary is in read-only state. " ) ;
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " set " ) , false ) ;
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed_value . validate ( value , " set " ) , false ) ;
_p - > variant_map [ key ] = value ;
return true ;
}
2014-02-09 22:10:30 -03:00
int Dictionary : : size ( ) const {
return _p - > variant_map . size ( ) ;
}
2020-05-14 14:29:06 +02:00
2020-12-15 12:04:21 +00:00
bool Dictionary : : is_empty ( ) const {
2014-02-09 22:10:30 -03:00
return ! _p - > variant_map . size ( ) ;
}
2017-03-05 16:44:50 +01:00
bool Dictionary : : has ( const Variant & p_key ) const {
2023-06-24 13:03:28 -05:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " use 'has' " ) , false ) ;
2025-04-09 12:22:48 -04:00
return _p - > variant_map . has ( key ) ;
2014-02-09 22:10:30 -03:00
}
2016-04-04 18:37:43 +02:00
2017-03-05 16:44:50 +01:00
bool Dictionary : : has_all ( const Array & p_keys ) const {
for ( int i = 0 ; i < p_keys . size ( ) ; i + + ) {
2023-06-24 13:03:28 -05:00
Variant key = p_keys [ i ] ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " use 'has_all' " ) , false ) ;
2025-04-29 15:27:12 -04:00
if ( ! _p - > variant_map . has ( key ) ) {
2016-04-04 18:37:43 +02:00
return false ;
}
}
return true ;
}
2022-08-05 19:08:27 +02:00
Variant Dictionary : : find_key ( const Variant & p_value ) const {
2023-06-24 13:03:28 -05:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed_value . validate ( value , " find_key " ) , Variant ( ) ) ;
2022-08-05 19:08:27 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2023-06-24 13:03:28 -05:00
if ( E . value = = value ) {
2022-08-05 19:08:27 +02:00
return E . key ;
}
}
return Variant ( ) ;
}
2018-08-14 19:19:05 +02:00
bool Dictionary : : erase ( const Variant & p_key ) {
2023-06-24 13:03:28 -05:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " erase " ) , false ) ;
2022-05-16 15:44:43 +02:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , false , " Dictionary is in read-only state. " ) ;
2023-06-24 13:03:28 -05:00
return _p - > variant_map . erase ( key ) ;
2018-07-18 23:07:31 +02:00
}
2017-03-05 16:44:50 +01:00
bool Dictionary : : operator = = ( const Dictionary & p_dictionary ) const {
2020-02-01 07:04:14 +01:00
return recursive_equal ( p_dictionary , 0 ) ;
2014-02-09 22:10:30 -03:00
}
2018-10-06 16:20:41 -04:00
bool Dictionary : : operator ! = ( const Dictionary & p_dictionary ) const {
2020-02-01 07:04:14 +01:00
return ! recursive_equal ( p_dictionary , 0 ) ;
}
bool Dictionary : : recursive_equal ( const Dictionary & p_dictionary , int recursion_count ) const {
// Cheap checks
if ( _p = = p_dictionary . _p ) {
return true ;
}
if ( _p - > variant_map . size ( ) ! = p_dictionary . _p - > variant_map . size ( ) ) {
return false ;
}
// Heavy O(n) check
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return true ;
}
recursion_count + + ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & this_E : _p - > variant_map ) {
2022-12-05 21:46:47 -05:00
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : ConstIterator other_E ( p_dictionary . _p - > variant_map . find ( this_E . key ) ) ;
2023-03-07 19:13:00 -08:00
if ( ! other_E | | ! this_E . value . hash_compare ( other_E - > value , recursion_count , false ) ) {
2020-02-01 07:04:14 +01:00
return false ;
}
}
return true ;
2018-10-06 16:20:41 -04:00
}
2017-03-05 16:44:50 +01:00
void Dictionary : : _ref ( const Dictionary & p_from ) const {
2014-02-09 22:10:30 -03:00
//make a copy first (thread safe)
2020-05-14 16:41:43 +02:00
if ( ! p_from . _p - > refcount . ref ( ) ) {
2014-02-09 22:10:30 -03:00
return ; // couldn't copy
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
//if this is the same, unreference the other one
2017-03-05 16:44:50 +01:00
if ( p_from . _p = = _p ) {
2014-02-09 22:10:30 -03:00
_p - > refcount . unref ( ) ;
return ;
}
2020-05-14 16:41:43 +02:00
if ( _p ) {
2014-02-09 22:10:30 -03:00
_unref ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-03-05 16:44:50 +01:00
_p = p_from . _p ;
2014-02-09 22:10:30 -03:00
}
void Dictionary : : clear ( ) {
2022-05-16 15:44:43 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Dictionary is in read-only state. " ) ;
2014-02-09 22:10:30 -03:00
_p - > variant_map . clear ( ) ;
}
2025-04-18 22:10:26 -04:00
struct _DictionaryVariantSort {
_FORCE_INLINE_ bool operator ( ) ( const KeyValue < Variant , Variant > & p_l , const KeyValue < Variant , Variant > & p_r ) const {
bool valid = false ;
Variant res ;
Variant : : evaluate ( Variant : : OP_LESS , p_l . key , p_r . key , res , valid ) ;
if ( ! valid ) {
res = false ;
}
return res ;
}
} ;
2023-05-17 19:52:44 -05:00
void Dictionary : : sort ( ) {
ERR_FAIL_COND_MSG ( _p - > read_only , " Dictionary is in read-only state. " ) ;
2025-04-18 22:10:26 -04:00
_p - > variant_map . sort_custom < _DictionaryVariantSort > ( ) ;
2023-05-17 19:52:44 -05:00
}
2022-04-04 18:46:55 +02:00
void Dictionary : : merge ( const Dictionary & p_dictionary , bool p_overwrite ) {
2022-09-08 18:14:10 +02:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Dictionary is in read-only state. " ) ;
2022-04-04 18:46:55 +02:00
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
2023-06-24 13:03:28 -05:00
Variant key = E . key ;
Variant value = E . value ;
ERR_FAIL_COND ( ! _p - > typed_key . validate ( key , " merge " ) ) ;
2024-09-11 17:22:49 +02:00
ERR_FAIL_COND ( ! _p - > typed_value . validate ( value , " merge " ) ) ;
2023-06-24 13:03:28 -05:00
if ( p_overwrite | | ! has ( key ) ) {
operator [ ] ( key ) = value ;
2022-04-04 18:46:55 +02:00
}
}
}
2022-09-08 18:14:10 +02:00
Dictionary Dictionary : : merged ( const Dictionary & p_dictionary , bool p_overwrite ) const {
Dictionary ret = duplicate ( ) ;
ret . merge ( p_dictionary , p_overwrite ) ;
return ret ;
}
2014-02-09 22:10:30 -03:00
void Dictionary : : _unref ( ) const {
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( _p ) ;
2014-02-09 22:10:30 -03:00
if ( _p - > refcount . unref ( ) ) {
2022-05-16 15:44:43 +02:00
if ( _p - > read_only ) {
memdelete ( _p - > read_only ) ;
}
2023-06-24 13:03:28 -05:00
if ( _p - > typed_fallback ) {
memdelete ( _p - > typed_fallback ) ;
}
2014-02-09 22:10:30 -03:00
memdelete ( _p ) ;
}
2020-04-02 01:20:12 +02:00
_p = nullptr ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2014-02-09 22:10:30 -03:00
uint32_t Dictionary : : hash ( ) const {
2020-02-01 07:04:14 +01:00
return recursive_hash ( 0 ) ;
}
uint32_t Dictionary : : 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 : : DICTIONARY ) ;
2015-12-13 15:20:58 -03:00
2020-02-01 07:04:14 +01:00
recursion_count + + ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2022-06-18 16:20:55 +02:00
h = hash_murmur3_one_32 ( E . key . recursive_hash ( recursion_count ) , h ) ;
h = hash_murmur3_one_32 ( E . value . recursive_hash ( recursion_count ) , h ) ;
2015-12-13 15:20:58 -03:00
}
2022-06-18 16:20:55 +02:00
return hash_fmix32 ( h ) ;
2014-02-09 22:10:30 -03:00
}
Array Dictionary : : keys ( ) const {
2017-07-23 12:23:18 -03:00
Array varr ;
2023-06-24 13:03:28 -05:00
if ( is_typed_key ( ) ) {
varr . set_typed ( get_typed_key_builtin ( ) , get_typed_key_class_name ( ) , get_typed_key_script ( ) ) ;
}
2020-12-15 12:04:21 +00:00
if ( _p - > variant_map . is_empty ( ) ) {
2017-07-23 12:23:18 -03:00
return varr ;
2020-05-14 16:41:43 +02:00
}
2017-07-23 12:23:18 -03:00
2019-10-10 18:12:20 +02:00
varr . resize ( size ( ) ) ;
2017-11-05 15:27:28 +01:00
int i = 0 ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
varr [ i ] = E . key ;
2017-11-05 15:27:28 +01:00
i + + ;
2017-07-23 12:23:18 -03:00
}
return varr ;
2014-02-09 22:10:30 -03:00
}
2016-06-05 14:20:52 +02:00
Array Dictionary : : values ( ) const {
Array varr ;
2023-06-24 13:03:28 -05:00
if ( is_typed_value ( ) ) {
varr . set_typed ( get_typed_value_builtin ( ) , get_typed_value_class_name ( ) , get_typed_value_script ( ) ) ;
}
2020-12-15 12:04:21 +00:00
if ( _p - > variant_map . is_empty ( ) ) {
2017-01-08 14:16:21 -03:00
return varr ;
2020-05-14 16:41:43 +02:00
}
2017-01-08 14:16:21 -03:00
2019-10-10 18:12:20 +02:00
varr . resize ( size ( ) ) ;
2017-11-05 15:27:28 +01:00
int i = 0 ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
varr [ i ] = E . value ;
2017-11-05 15:27:28 +01:00
i + + ;
2016-06-05 14:20:52 +02:00
}
2017-01-08 14:16:21 -03:00
2016-06-05 14:20:52 +02:00
return varr ;
}
2023-06-24 13:03:28 -05:00
void Dictionary : : assign ( const Dictionary & p_dictionary ) {
const ContainerTypeValidate & typed_key = _p - > typed_key ;
const ContainerTypeValidate & typed_key_source = p_dictionary . _p - > typed_key ;
const ContainerTypeValidate & typed_value = _p - > typed_value ;
const ContainerTypeValidate & typed_value_source = p_dictionary . _p - > typed_value ;
if ( ( typed_key = = typed_key_source | | typed_key . type = = Variant : : NIL | | ( typed_key_source . type = = Variant : : OBJECT & & typed_key . can_reference ( typed_key_source ) ) ) & &
( typed_value = = typed_value_source | | typed_value . type = = Variant : : NIL | | ( typed_value_source . type = = Variant : : OBJECT & & typed_value . can_reference ( typed_value_source ) ) ) ) {
// From same to same or,
// from anything to variants or,
// from subclasses to base classes.
_p - > variant_map = p_dictionary . _p - > variant_map ;
return ;
}
int size = p_dictionary . _p - > variant_map . size ( ) ;
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > variant_map = HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > ( size ) ;
Vector < Variant > key_array ;
key_array . resize ( size ) ;
Variant * key_data = key_array . ptrw ( ) ;
Vector < Variant > value_array ;
value_array . resize ( size ) ;
Variant * value_data = value_array . ptrw ( ) ;
if ( typed_key = = typed_key_source | | typed_key . type = = Variant : : NIL | | ( typed_key_source . type = = Variant : : OBJECT & & typed_key . can_reference ( typed_key_source ) ) ) {
// From same to same or,
// from anything to variants or,
// from subclasses to base classes.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * key = & E . key ;
key_data [ i + + ] = * key ;
}
} else if ( ( typed_key_source . type = = Variant : : NIL & & typed_key . type = = Variant : : OBJECT ) | | ( typed_key_source . type = = Variant : : OBJECT & & typed_key_source . can_reference ( typed_key ) ) ) {
// From variants to objects or,
// from base classes to subclasses.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * key = & E . key ;
if ( key - > get_type ( ) ! = Variant : : NIL & & ( key - > get_type ( ) ! = Variant : : OBJECT | | ! typed_key . validate_object ( * key , " assign " ) ) ) {
ERR_FAIL_MSG ( vformat ( R " (Unable to convert key from " % s " to " % s " .) " , Variant : : get_type_name ( key - > get_type ( ) ) , Variant : : get_type_name ( typed_key . type ) ) ) ;
}
key_data [ i + + ] = * key ;
}
} else if ( typed_key . type = = Variant : : OBJECT | | typed_key_source . type = = Variant : : OBJECT ) {
ERR_FAIL_MSG ( vformat ( R " (Cannot assign contents of " Dictionary [ % s , % s ] " to " Dictionary [ % s , % s ] " .) " , Variant : : get_type_name ( typed_key_source . type ) , Variant : : get_type_name ( typed_value_source . type ) ,
Variant : : get_type_name ( typed_key . type ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
} else if ( typed_key_source . type = = Variant : : NIL & & typed_key . type ! = Variant : : OBJECT ) {
// From variants to primitives.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * key = & E . key ;
if ( key - > get_type ( ) = = typed_key . type ) {
key_data [ i + + ] = * key ;
continue ;
}
if ( ! Variant : : can_convert_strict ( key - > get_type ( ) , typed_key . type ) ) {
ERR_FAIL_MSG ( vformat ( R " (Unable to convert key from " % s " to " % s " .) " , Variant : : get_type_name ( key - > get_type ( ) ) , Variant : : get_type_name ( typed_key . type ) ) ) ;
}
Callable : : CallError ce ;
Variant : : construct ( typed_key . type , key_data [ i + + ] , & key , 1 , ce ) ;
ERR_FAIL_COND_MSG ( ce . error , vformat ( R " (Unable to convert key from " % s " to " % s " .) " , Variant : : get_type_name ( key - > get_type ( ) ) , Variant : : get_type_name ( typed_key . type ) ) ) ;
}
} else if ( Variant : : can_convert_strict ( typed_key_source . type , typed_key . type ) ) {
// From primitives to different convertible primitives.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * key = & E . key ;
Callable : : CallError ce ;
Variant : : construct ( typed_key . type , key_data [ i + + ] , & key , 1 , ce ) ;
ERR_FAIL_COND_MSG ( ce . error , vformat ( R " (Unable to convert key from " % s " to " % s " .) " , Variant : : get_type_name ( key - > get_type ( ) ) , Variant : : get_type_name ( typed_key . type ) ) ) ;
}
} else {
ERR_FAIL_MSG ( vformat ( R " (Cannot assign contents of " Dictionary [ % s , % s ] " to " Dictionary [ % s , % s ] . ) " , Variant::get_type_name(typed_key_source.type), Variant::get_type_name(typed_value_source.type),
Variant : : get_type_name ( typed_key . type ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
}
if ( typed_value = = typed_value_source | | typed_value . type = = Variant : : NIL | | ( typed_value_source . type = = Variant : : OBJECT & & typed_value . can_reference ( typed_value_source ) ) ) {
// From same to same or,
// from anything to variants or,
// from subclasses to base classes.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * value = & E . value ;
value_data [ i + + ] = * value ;
}
} else if ( ( ( typed_value_source . type = = Variant : : NIL & & typed_value . type = = Variant : : OBJECT ) | | ( typed_value_source . type = = Variant : : OBJECT & & typed_value_source . can_reference ( typed_value ) ) ) ) {
// From variants to objects or,
// from base classes to subclasses.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * value = & E . value ;
if ( value - > get_type ( ) ! = Variant : : NIL & & ( value - > get_type ( ) ! = Variant : : OBJECT | | ! typed_value . validate_object ( * value , " assign " ) ) ) {
ERR_FAIL_MSG ( vformat ( R " (Unable to convert value at key " % s " from " % s " to " % s " .) " , key_data [ i ] , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
}
value_data [ i + + ] = * value ;
}
} else if ( typed_value . type = = Variant : : OBJECT | | typed_value_source . type = = Variant : : OBJECT ) {
ERR_FAIL_MSG ( vformat ( R " (Cannot assign contents of " Dictionary [ % s , % s ] " to " Dictionary [ % s , % s ] " .) " , Variant : : get_type_name ( typed_key_source . type ) , Variant : : get_type_name ( typed_value_source . type ) ,
Variant : : get_type_name ( typed_key . type ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
} else if ( typed_value_source . type = = Variant : : NIL & & typed_value . type ! = Variant : : OBJECT ) {
// From variants to primitives.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * value = & E . value ;
if ( value - > get_type ( ) = = typed_value . type ) {
value_data [ i + + ] = * value ;
continue ;
}
if ( ! Variant : : can_convert_strict ( value - > get_type ( ) , typed_value . type ) ) {
ERR_FAIL_MSG ( vformat ( R " (Unable to convert value at key " % s " from " % s " to " % s " .) " , key_data [ i ] , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
}
Callable : : CallError ce ;
Variant : : construct ( typed_value . type , value_data [ i + + ] , & value , 1 , ce ) ;
ERR_FAIL_COND_MSG ( ce . error , vformat ( R " (Unable to convert value at key " % s " from " % s " to " % s " .) " , key_data [ i - 1 ] , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
}
} else if ( Variant : : can_convert_strict ( typed_value_source . type , typed_value . type ) ) {
// From primitives to different convertible primitives.
int i = 0 ;
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
const Variant * value = & E . value ;
Callable : : CallError ce ;
Variant : : construct ( typed_value . type , value_data [ i + + ] , & value , 1 , ce ) ;
ERR_FAIL_COND_MSG ( ce . error , vformat ( R " (Unable to convert value at key " % s " from " % s " to " % s " .) " , key_data [ i - 1 ] , Variant : : get_type_name ( value - > get_type ( ) ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
}
} else {
ERR_FAIL_MSG ( vformat ( R " (Cannot assign contents of " Dictionary [ % s , % s ] " to " Dictionary [ % s , % s ] . ) " , Variant::get_type_name(typed_key_source.type), Variant::get_type_name(typed_value_source.type),
Variant : : get_type_name ( typed_key . type ) , Variant : : get_type_name ( typed_value . type ) ) ) ;
}
for ( int i = 0 ; i < size ; i + + ) {
variant_map . insert ( key_data [ i ] , value_data [ i ] ) ;
}
_p - > variant_map = variant_map ;
}
2017-03-05 16:44:50 +01:00
const Variant * Dictionary : : next ( const Variant * p_key ) const {
2020-04-02 01:20:12 +02:00
if ( p_key = = nullptr ) {
2017-11-05 15:27:28 +01:00
// caller wants to get the first element
2022-05-08 10:09:19 +02:00
if ( _p - > variant_map . begin ( ) ) {
return & _p - > variant_map . begin ( ) - > key ;
2020-05-14 16:41:43 +02:00
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2017-11-05 15:27:28 +01:00
}
2023-06-24 13:03:28 -05:00
Variant key = * p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " next " ) , nullptr ) ;
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : Iterator E = _p - > variant_map . find ( key ) ;
2017-11-05 15:27:28 +01:00
2022-05-08 10:09:19 +02:00
if ( ! E ) {
return nullptr ;
}
+ + E ;
if ( E ) {
return & E - > key ;
2020-05-14 16:41:43 +02:00
}
2022-05-08 10:09:19 +02:00
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-09 22:10:30 -03:00
}
2018-03-09 21:16:08 +02:00
Dictionary Dictionary : : duplicate ( bool p_deep ) const {
Overhaul `Variant::duplicate()` for resources
This in the scope of a duplication triggered via any type in the `Variant` realm. that is, the following: `Variant` itself, `Array` and `Dictionary`. That includes invoking `duplicate()` from scripts.
A `duplicate_deep(deep_subresources_mode)` method is added to `Variant`, `Array` and `Dictionary` (for compatibility reasons, simply adding an extra parameter was not possible). The default value for it is `RESOURCE_DEEP_DUPLICATE_NONE`, which is like calling `duplicate(true)`.
Remarks:
- The results of copying resources via those `Variant` types are exactly the same as if the copy were initiated from the `Resource` type at C++.
- In order to keep some separation between `Variant` and the higher-level animal which is `Resource`, `Variant` still contains the original code for that, so it's self-sufficient unless there's a `Resource` involved. Once the deep copy finds a `Resource` that has to be copied according to the duplication parameters, the algorithm invokes the `Resource` duplication machinery. When the stack is unwind back to a nesting level `Variant` can handle, `Variant` duplication logic keeps functioning.
While that is good from a responsibility separation standpoint, that would have a caveat: `Variant` would not be aware of the mapping between original and duplicate subresources and so wouldn't be able to keep preventing multiple duplicates.
To avoid that, this commit also introduces a wormwhole, a sharing mechanism by which `Variant` and `Resource` can collaborate in managing the lifetime of the original-to-duplicates map. The user-visible benefit is that the overduplicate prevention works as broadly as the whole `Variant` entity being copied, including all nesting levels, regardless how disconnected the data members containing resources may be across al the nesting levels. In other words, despite the aforementioned division of duties between `Variant` and `Resource` duplication logic, the duplicates map is shared among them. It's created when first finding a `Resource` and, however how deep the copy was working at that point, the map kept alive unitl the stack is unwind to the root user call, until the first step of the recursion.
Thanks to that common map of duplicates, this commit is able to fix the issue that `Resource::duplicate_for_local_scene()` used to ignore overridden duplicate logic.
2025-01-21 11:55:23 +01:00
return recursive_duplicate ( p_deep , RESOURCE_DEEP_DUPLICATE_NONE , 0 ) ;
}
Dictionary Dictionary : : duplicate_deep ( ResourceDeepDuplicateMode p_deep_subresources_mode ) const {
return recursive_duplicate ( true , p_deep_subresources_mode , 0 ) ;
2020-02-01 07:04:14 +01:00
}
2023-01-22 11:07:48 +02:00
void Dictionary : : make_read_only ( ) {
if ( _p - > read_only = = nullptr ) {
2022-05-16 15:44:43 +02:00
_p - > read_only = memnew ( Variant ) ;
}
}
bool Dictionary : : is_read_only ( ) const {
return _p - > read_only ! = nullptr ;
}
Overhaul `Variant::duplicate()` for resources
This in the scope of a duplication triggered via any type in the `Variant` realm. that is, the following: `Variant` itself, `Array` and `Dictionary`. That includes invoking `duplicate()` from scripts.
A `duplicate_deep(deep_subresources_mode)` method is added to `Variant`, `Array` and `Dictionary` (for compatibility reasons, simply adding an extra parameter was not possible). The default value for it is `RESOURCE_DEEP_DUPLICATE_NONE`, which is like calling `duplicate(true)`.
Remarks:
- The results of copying resources via those `Variant` types are exactly the same as if the copy were initiated from the `Resource` type at C++.
- In order to keep some separation between `Variant` and the higher-level animal which is `Resource`, `Variant` still contains the original code for that, so it's self-sufficient unless there's a `Resource` involved. Once the deep copy finds a `Resource` that has to be copied according to the duplication parameters, the algorithm invokes the `Resource` duplication machinery. When the stack is unwind back to a nesting level `Variant` can handle, `Variant` duplication logic keeps functioning.
While that is good from a responsibility separation standpoint, that would have a caveat: `Variant` would not be aware of the mapping between original and duplicate subresources and so wouldn't be able to keep preventing multiple duplicates.
To avoid that, this commit also introduces a wormwhole, a sharing mechanism by which `Variant` and `Resource` can collaborate in managing the lifetime of the original-to-duplicates map. The user-visible benefit is that the overduplicate prevention works as broadly as the whole `Variant` entity being copied, including all nesting levels, regardless how disconnected the data members containing resources may be across al the nesting levels. In other words, despite the aforementioned division of duties between `Variant` and `Resource` duplication logic, the duplicates map is shared among them. It's created when first finding a `Resource` and, however how deep the copy was working at that point, the map kept alive unitl the stack is unwind to the root user call, until the first step of the recursion.
Thanks to that common map of duplicates, this commit is able to fix the issue that `Resource::duplicate_for_local_scene()` used to ignore overridden duplicate logic.
2025-01-21 11:55:23 +01:00
Dictionary Dictionary : : recursive_duplicate ( bool p_deep , ResourceDeepDuplicateMode p_deep_subresources_mode , int recursion_count ) const {
2017-01-11 08:53:31 -03:00
Dictionary n ;
2023-06-24 13:03:28 -05:00
n . _p - > typed_key = _p - > typed_key ;
n . _p - > typed_value = _p - > typed_value ;
2016-08-02 19:11:05 -03:00
2020-02-01 07:04:14 +01:00
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return n ;
}
if ( p_deep ) {
Overhaul `Variant::duplicate()` for resources
This in the scope of a duplication triggered via any type in the `Variant` realm. that is, the following: `Variant` itself, `Array` and `Dictionary`. That includes invoking `duplicate()` from scripts.
A `duplicate_deep(deep_subresources_mode)` method is added to `Variant`, `Array` and `Dictionary` (for compatibility reasons, simply adding an extra parameter was not possible). The default value for it is `RESOURCE_DEEP_DUPLICATE_NONE`, which is like calling `duplicate(true)`.
Remarks:
- The results of copying resources via those `Variant` types are exactly the same as if the copy were initiated from the `Resource` type at C++.
- In order to keep some separation between `Variant` and the higher-level animal which is `Resource`, `Variant` still contains the original code for that, so it's self-sufficient unless there's a `Resource` involved. Once the deep copy finds a `Resource` that has to be copied according to the duplication parameters, the algorithm invokes the `Resource` duplication machinery. When the stack is unwind back to a nesting level `Variant` can handle, `Variant` duplication logic keeps functioning.
While that is good from a responsibility separation standpoint, that would have a caveat: `Variant` would not be aware of the mapping between original and duplicate subresources and so wouldn't be able to keep preventing multiple duplicates.
To avoid that, this commit also introduces a wormwhole, a sharing mechanism by which `Variant` and `Resource` can collaborate in managing the lifetime of the original-to-duplicates map. The user-visible benefit is that the overduplicate prevention works as broadly as the whole `Variant` entity being copied, including all nesting levels, regardless how disconnected the data members containing resources may be across al the nesting levels. In other words, despite the aforementioned division of duties between `Variant` and `Resource` duplication logic, the duplicates map is shared among them. It's created when first finding a `Resource` and, however how deep the copy was working at that point, the map kept alive unitl the stack is unwind to the root user call, until the first step of the recursion.
Thanks to that common map of duplicates, this commit is able to fix the issue that `Resource::duplicate_for_local_scene()` used to ignore overridden duplicate logic.
2025-01-21 11:55:23 +01:00
bool is_call_chain_end = recursion_count = = 0 ;
2020-02-01 07:04:14 +01:00
recursion_count + + ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
Overhaul `Variant::duplicate()` for resources
This in the scope of a duplication triggered via any type in the `Variant` realm. that is, the following: `Variant` itself, `Array` and `Dictionary`. That includes invoking `duplicate()` from scripts.
A `duplicate_deep(deep_subresources_mode)` method is added to `Variant`, `Array` and `Dictionary` (for compatibility reasons, simply adding an extra parameter was not possible). The default value for it is `RESOURCE_DEEP_DUPLICATE_NONE`, which is like calling `duplicate(true)`.
Remarks:
- The results of copying resources via those `Variant` types are exactly the same as if the copy were initiated from the `Resource` type at C++.
- In order to keep some separation between `Variant` and the higher-level animal which is `Resource`, `Variant` still contains the original code for that, so it's self-sufficient unless there's a `Resource` involved. Once the deep copy finds a `Resource` that has to be copied according to the duplication parameters, the algorithm invokes the `Resource` duplication machinery. When the stack is unwind back to a nesting level `Variant` can handle, `Variant` duplication logic keeps functioning.
While that is good from a responsibility separation standpoint, that would have a caveat: `Variant` would not be aware of the mapping between original and duplicate subresources and so wouldn't be able to keep preventing multiple duplicates.
To avoid that, this commit also introduces a wormwhole, a sharing mechanism by which `Variant` and `Resource` can collaborate in managing the lifetime of the original-to-duplicates map. The user-visible benefit is that the overduplicate prevention works as broadly as the whole `Variant` entity being copied, including all nesting levels, regardless how disconnected the data members containing resources may be across al the nesting levels. In other words, despite the aforementioned division of duties between `Variant` and `Resource` duplication logic, the duplicates map is shared among them. It's created when first finding a `Resource` and, however how deep the copy was working at that point, the map kept alive unitl the stack is unwind to the root user call, until the first step of the recursion.
Thanks to that common map of duplicates, this commit is able to fix the issue that `Resource::duplicate_for_local_scene()` used to ignore overridden duplicate logic.
2025-01-21 11:55:23 +01:00
n [ E . key . recursive_duplicate ( true , p_deep_subresources_mode , recursion_count ) ] = E . value . recursive_duplicate ( true , p_deep_subresources_mode , recursion_count ) ;
}
// Variant::recursive_duplicate() may have created a remap cache by now.
if ( is_call_chain_end ) {
Resource : : _teardown_duplicate_from_variant ( ) ;
2020-02-01 07:04:14 +01:00
}
} else {
2022-05-08 10:09:19 +02:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
n [ E . key ] = E . value ;
2020-02-01 07:04:14 +01:00
}
2016-08-02 19:11:05 -03:00
}
return n ;
}
2024-11-27 18:15:49 +03:00
void Dictionary : : set_typed ( const ContainerType & p_key_type , const ContainerType & p_value_type ) {
set_typed ( p_key_type . builtin_type , p_key_type . class_name , p_key_type . script , p_value_type . builtin_type , p_value_type . class_name , p_key_type . script ) ;
}
2023-06-24 13:03:28 -05:00
void Dictionary : : set_typed ( uint32_t p_key_type , const StringName & p_key_class_name , const Variant & p_key_script , uint32_t p_value_type , const StringName & p_value_class_name , const Variant & p_value_script ) {
ERR_FAIL_COND_MSG ( _p - > read_only , " Dictionary is in read-only state. " ) ;
ERR_FAIL_COND_MSG ( _p - > variant_map . size ( ) > 0 , " Type can only be set when dictionary is empty. " ) ;
ERR_FAIL_COND_MSG ( _p - > refcount . get ( ) > 1 , " Type can only be set when dictionary has no more than one user. " ) ;
ERR_FAIL_COND_MSG ( _p - > typed_key . type ! = Variant : : NIL | | _p - > typed_value . type ! = Variant : : NIL , " Type can only be set once. " ) ;
ERR_FAIL_COND_MSG ( ( p_key_class_name ! = StringName ( ) & & p_key_type ! = Variant : : OBJECT ) | | ( p_value_class_name ! = StringName ( ) & & p_value_type ! = Variant : : OBJECT ) , " Class names can only be set for type OBJECT. " ) ;
Ref < Script > key_script = p_key_script ;
ERR_FAIL_COND_MSG ( key_script . is_valid ( ) & & p_key_class_name = = StringName ( ) , " Script class can only be set together with base class name. " ) ;
Ref < Script > value_script = p_value_script ;
ERR_FAIL_COND_MSG ( value_script . is_valid ( ) & & p_value_class_name = = StringName ( ) , " Script class can only be set together with base class name. " ) ;
_p - > typed_key . type = Variant : : Type ( p_key_type ) ;
_p - > typed_key . class_name = p_key_class_name ;
_p - > typed_key . script = key_script ;
_p - > typed_key . where = " TypedDictionary.Key " ;
_p - > typed_value . type = Variant : : Type ( p_value_type ) ;
_p - > typed_value . class_name = p_value_class_name ;
_p - > typed_value . script = value_script ;
_p - > typed_value . where = " TypedDictionary.Value " ;
}
bool Dictionary : : is_typed ( ) const {
return is_typed_key ( ) | | is_typed_value ( ) ;
}
bool Dictionary : : is_typed_key ( ) const {
return _p - > typed_key . type ! = Variant : : NIL ;
}
bool Dictionary : : is_typed_value ( ) const {
return _p - > typed_value . type ! = Variant : : NIL ;
}
2024-12-20 15:30:15 +01:00
bool Dictionary : : is_same_instance ( const Dictionary & p_other ) const {
return _p = = p_other . _p ;
}
2023-06-24 13:03:28 -05:00
bool Dictionary : : is_same_typed ( const Dictionary & p_other ) const {
return is_same_typed_key ( p_other ) & & is_same_typed_value ( p_other ) ;
}
bool Dictionary : : is_same_typed_key ( const Dictionary & p_other ) const {
return _p - > typed_key = = p_other . _p - > typed_key ;
}
bool Dictionary : : is_same_typed_value ( const Dictionary & p_other ) const {
return _p - > typed_value = = p_other . _p - > typed_value ;
}
2024-11-27 18:15:49 +03:00
ContainerType Dictionary : : get_key_type ( ) const {
ContainerType type ;
type . builtin_type = _p - > typed_key . type ;
type . class_name = _p - > typed_key . class_name ;
type . script = _p - > typed_key . script ;
return type ;
}
ContainerType Dictionary : : get_value_type ( ) const {
ContainerType type ;
type . builtin_type = _p - > typed_value . type ;
type . class_name = _p - > typed_value . class_name ;
type . script = _p - > typed_value . script ;
return type ;
}
2023-06-24 13:03:28 -05:00
uint32_t Dictionary : : get_typed_key_builtin ( ) const {
return _p - > typed_key . type ;
}
uint32_t Dictionary : : get_typed_value_builtin ( ) const {
return _p - > typed_value . type ;
}
StringName Dictionary : : get_typed_key_class_name ( ) const {
return _p - > typed_key . class_name ;
}
StringName Dictionary : : get_typed_value_class_name ( ) const {
return _p - > typed_value . class_name ;
}
Variant Dictionary : : get_typed_key_script ( ) const {
return _p - > typed_key . script ;
}
Variant Dictionary : : get_typed_value_script ( ) const {
return _p - > typed_value . script ;
}
2017-03-05 16:44:50 +01:00
void Dictionary : : operator = ( const Dictionary & p_dictionary ) {
2022-05-16 15:44:43 +02:00
if ( this = = & p_dictionary ) {
return ;
}
2014-02-09 22:10:30 -03:00
_ref ( p_dictionary ) ;
}
2019-04-20 01:57:29 +02:00
const void * Dictionary : : id ( ) const {
2021-12-30 13:14:09 +08:00
return _p ;
2019-04-20 01:57:29 +02:00
}
2023-06-24 13:03:28 -05:00
Dictionary : : Dictionary ( const Dictionary & p_base , uint32_t p_key_type , const StringName & p_key_class_name , const Variant & p_key_script , uint32_t p_value_type , const StringName & p_value_class_name , const Variant & p_value_script ) {
_p = memnew ( DictionaryPrivate ) ;
_p - > refcount . init ( ) ;
set_typed ( p_key_type , p_key_class_name , p_key_script , p_value_type , p_value_class_name , p_value_script ) ;
assign ( p_base ) ;
}
2017-03-05 16:44:50 +01:00
Dictionary : : Dictionary ( const Dictionary & p_from ) {
2020-04-02 01:20:12 +02:00
_p = nullptr ;
2014-02-09 22:10:30 -03:00
_ref ( p_from ) ;
}
2017-01-11 08:53:31 -03:00
Dictionary : : Dictionary ( ) {
2017-03-05 16:44:50 +01:00
_p = memnew ( DictionaryPrivate ) ;
2014-02-09 22:10:30 -03:00
_p - > refcount . init ( ) ;
}
2020-05-14 14:29:06 +02:00
2024-11-27 14:04:41 +02:00
Dictionary : : Dictionary ( std : : initializer_list < KeyValue < Variant , Variant > > p_init ) {
_p = memnew ( DictionaryPrivate ) ;
_p - > refcount . init ( ) ;
for ( const KeyValue < Variant , Variant > & E : p_init ) {
operator [ ] ( E . key ) = E . value ;
}
}
2014-02-09 22:10:30 -03:00
Dictionary : : ~ Dictionary ( ) {
_unref ( ) ;
}