2014-02-10 01:10:30 +00: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-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "dictionary.h"
2017-01-16 07:04:19 +00:00
2022-05-08 08:09:19 +00:00
# include "core/templates/hash_map.h"
2020-11-07 22:33:38 +00:00
# include "core/templates/safe_refcount.h"
2023-06-24 18:03:28 +00:00
# include "core/variant/container_type_validate.h"
2020-11-07 22:33:38 +00:00
# include "core/variant/variant.h"
2021-07-01 19:03:37 +00: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-10 01:10:30 +00:00
struct DictionaryPrivate {
SafeRefCount refcount ;
2022-05-16 13:44:43 +00: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-06 02:46:47 +00:00
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > variant_map ;
2023-06-24 18:03:28 +00: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 17:16:21 +00:00
} ;
2014-02-10 01:10:30 +00:00
void Dictionary : : get_key_list ( List < Variant > * p_keys ) const {
2020-12-15 12:04:21 +00:00
if ( _p - > variant_map . is_empty ( ) ) {
2017-01-08 17:16:21 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-01-08 17:16:21 +00:00
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
p_keys - > push_back ( E . key ) ;
2017-01-08 17:16:21 +00:00
}
2014-02-10 01:10:30 +00:00
}
2018-05-19 20:57:44 +00:00
Variant Dictionary : : get_key_at_index ( int p_index ) const {
int index = 0 ;
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2018-05-19 20:57:44 +00:00
if ( index = = p_index ) {
2022-05-08 08:09:19 +00:00
return E . key ;
2018-05-19 20:57:44 +00:00
}
index + + ;
}
return Variant ( ) ;
}
Variant Dictionary : : get_value_at_index ( int p_index ) const {
int index = 0 ;
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2018-05-19 20:57:44 +00:00
if ( index = = p_index ) {
2022-05-08 08:09:19 +00:00
return E . value ;
2018-05-19 20:57:44 +00:00
}
index + + ;
}
return Variant ( ) ;
}
2014-02-10 01:10:30 +00:00
Variant & Dictionary : : operator [ ] ( const Variant & p_key ) {
2022-05-16 13:44:43 +00:00
if ( unlikely ( _p - > read_only ) ) {
2023-12-28 22:44:23 +00:00
if ( likely ( _p - > variant_map . has ( p_key ) ) ) {
2022-05-16 13:44:43 +00:00
* _p - > read_only = _p - > variant_map [ p_key ] ;
2023-03-11 00:08:23 +00:00
} else {
* _p - > read_only = Variant ( ) ;
2022-05-16 13:44:43 +00:00
}
return * _p - > read_only ;
2021-07-01 19:03:37 +00:00
} else {
2023-12-28 22:44:23 +00:00
return _p - > variant_map [ p_key ] ;
2021-07-01 19:03:37 +00:00
}
2014-02-10 01:10:30 +00:00
}
const Variant & Dictionary : : operator [ ] ( const Variant & p_key ) const {
2022-12-06 02:46:47 +00:00
// Will not insert key, so no conversion is necessary.
return _p - > variant_map [ p_key ] ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
const Variant * Dictionary : : getptr ( const Variant & p_key ) const {
2022-12-06 02:46:47 +00:00
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : ConstIterator E ( _p - > variant_map . find ( p_key ) ) ;
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2022-05-08 08:09:19 +00:00
return & E - > value ;
2014-02-10 01:10:30 +00:00
}
2017-01-08 17:16:21 +00:00
2014-02-10 01:10:30 +00:00
Variant * Dictionary : : getptr ( const Variant & p_key ) {
2022-12-06 02:46:47 +00:00
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : Iterator E ( _p - > variant_map . find ( p_key ) ) ;
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2022-05-16 13:44:43 +00:00
if ( unlikely ( _p - > read_only ! = nullptr ) ) {
* _p - > read_only = E - > value ;
return _p - > read_only ;
} else {
return & E - > value ;
}
2014-02-10 01:10:30 +00:00
}
Variant Dictionary : : get_valid ( const Variant & p_key ) const {
2023-06-24 18:03:28 +00: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 14:27:28 +00:00
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
2020-05-14 14:41:43 +00:00
}
2022-05-08 08:09:19 +00:00
return E - > value ;
2014-02-10 01:10:30 +00:00
}
2018-07-30 04:04:32 +00:00
Variant Dictionary : : get ( const Variant & p_key , const Variant & p_default ) const {
2023-06-24 18:03:28 +00: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 04:04:32 +00:00
if ( ! result ) {
return p_default ;
}
return * result ;
}
2023-06-10 20:13:38 +00:00
Variant Dictionary : : get_or_add ( const Variant & p_key , const Variant & p_default ) {
2023-06-24 18:03:28 +00: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 20:13:38 +00:00
if ( ! result ) {
2023-06-24 18:03:28 +00:00
Variant value = p_default ;
ERR_FAIL_COND_V ( ! _p - > typed_value . validate ( value , " add " ) , value ) ;
operator [ ] ( key ) = value ;
return value ;
2023-06-10 20:13:38 +00:00
}
return * result ;
}
2014-02-10 01:10:30 +00:00
int Dictionary : : size ( ) const {
return _p - > variant_map . size ( ) ;
}
2020-05-14 12:29:06 +00:00
2020-12-15 12:04:21 +00:00
bool Dictionary : : is_empty ( ) const {
2014-02-10 01:10:30 +00:00
return ! _p - > variant_map . size ( ) ;
}
bool Dictionary : : has ( const Variant & p_key ) const {
2023-06-24 18:03:28 +00:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " use 'has' " ) , false ) ;
2022-12-06 02:46:47 +00:00
return _p - > variant_map . has ( p_key ) ;
2014-02-10 01:10:30 +00:00
}
2016-04-04 16:37:43 +00:00
bool Dictionary : : has_all ( const Array & p_keys ) const {
for ( int i = 0 ; i < p_keys . size ( ) ; i + + ) {
2023-06-24 18:03:28 +00:00
Variant key = p_keys [ i ] ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " use 'has_all' " ) , false ) ;
if ( ! has ( key ) ) {
2016-04-04 16:37:43 +00:00
return false ;
}
}
return true ;
}
2022-08-05 17:08:27 +00:00
Variant Dictionary : : find_key ( const Variant & p_value ) const {
2023-06-24 18:03:28 +00:00
Variant value = p_value ;
ERR_FAIL_COND_V ( ! _p - > typed_value . validate ( value , " find_key " ) , Variant ( ) ) ;
2022-08-05 17:08:27 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2023-06-24 18:03:28 +00:00
if ( E . value = = value ) {
2022-08-05 17:08:27 +00:00
return E . key ;
}
}
return Variant ( ) ;
}
2018-08-14 17:19:05 +00:00
bool Dictionary : : erase ( const Variant & p_key ) {
2023-06-24 18:03:28 +00:00
Variant key = p_key ;
ERR_FAIL_COND_V ( ! _p - > typed_key . validate ( key , " erase " ) , false ) ;
2022-05-16 13:44:43 +00:00
ERR_FAIL_COND_V_MSG ( _p - > read_only , false , " Dictionary is in read-only state. " ) ;
2023-06-24 18:03:28 +00:00
return _p - > variant_map . erase ( key ) ;
2018-07-18 21:07:31 +00:00
}
2014-02-10 01:10:30 +00:00
bool Dictionary : : operator = = ( const Dictionary & p_dictionary ) const {
2020-02-01 06:04:14 +00:00
return recursive_equal ( p_dictionary , 0 ) ;
2014-02-10 01:10:30 +00:00
}
2018-10-06 20:20:41 +00:00
bool Dictionary : : operator ! = ( const Dictionary & p_dictionary ) const {
2020-02-01 06:04:14 +00: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 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & this_E : _p - > variant_map ) {
2022-12-06 02:46:47 +00:00
HashMap < Variant , Variant , VariantHasher , StringLikeVariantComparator > : : ConstIterator other_E ( p_dictionary . _p - > variant_map . find ( this_E . key ) ) ;
2023-03-08 03:13:00 +00:00
if ( ! other_E | | ! this_E . value . hash_compare ( other_E - > value , recursion_count , false ) ) {
2020-02-01 06:04:14 +00:00
return false ;
}
}
return true ;
2018-10-06 20:20:41 +00:00
}
2014-02-10 01:10:30 +00:00
void Dictionary : : _ref ( const Dictionary & p_from ) const {
//make a copy first (thread safe)
2020-05-14 14:41:43 +00:00
if ( ! p_from . _p - > refcount . ref ( ) ) {
2014-02-10 01:10:30 +00:00
return ; // couldn't copy
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
//if this is the same, unreference the other one
if ( p_from . _p = = _p ) {
_p - > refcount . unref ( ) ;
return ;
}
2020-05-14 14:41:43 +00:00
if ( _p ) {
2014-02-10 01:10:30 +00:00
_unref ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
_p = p_from . _p ;
}
void Dictionary : : clear ( ) {
2022-05-16 13:44:43 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Dictionary is in read-only state. " ) ;
2014-02-10 01:10:30 +00:00
_p - > variant_map . clear ( ) ;
}
2022-04-04 16:46:55 +00:00
void Dictionary : : merge ( const Dictionary & p_dictionary , bool p_overwrite ) {
2022-09-08 16:14:10 +00:00
ERR_FAIL_COND_MSG ( _p - > read_only , " Dictionary is in read-only state. " ) ;
2022-04-04 16:46:55 +00:00
for ( const KeyValue < Variant , Variant > & E : p_dictionary . _p - > variant_map ) {
2023-06-24 18:03:28 +00:00
Variant key = E . key ;
Variant value = E . value ;
ERR_FAIL_COND ( ! _p - > typed_key . validate ( key , " merge " ) ) ;
ERR_FAIL_COND ( ! _p - > typed_key . validate ( value , " merge " ) ) ;
if ( p_overwrite | | ! has ( key ) ) {
operator [ ] ( key ) = value ;
2022-04-04 16:46:55 +00:00
}
}
}
2022-09-08 16:14:10 +00: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-10 01:10:30 +00:00
void Dictionary : : _unref ( ) const {
2023-09-09 14:11:33 +00:00
ERR_FAIL_NULL ( _p ) ;
2014-02-10 01:10:30 +00:00
if ( _p - > refcount . unref ( ) ) {
2022-05-16 13:44:43 +00:00
if ( _p - > read_only ) {
memdelete ( _p - > read_only ) ;
}
2023-06-24 18:03:28 +00:00
if ( _p - > typed_fallback ) {
memdelete ( _p - > typed_fallback ) ;
}
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
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
uint32_t Dictionary : : hash ( ) const {
2020-02-01 06:04:14 +00: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 14:20:55 +00:00
uint32_t h = hash_murmur3_one_32 ( Variant : : DICTIONARY ) ;
2015-12-13 18:20:58 +00:00
2020-02-01 06:04:14 +00:00
recursion_count + + ;
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
2022-06-18 14:20:55 +00: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 18:20:58 +00:00
}
2022-06-18 14:20:55 +00:00
return hash_fmix32 ( h ) ;
2014-02-10 01:10:30 +00:00
}
Array Dictionary : : keys ( ) const {
2017-07-23 15:23:18 +00:00
Array varr ;
2023-06-24 18:03:28 +00: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 15:23:18 +00:00
return varr ;
2020-05-14 14:41:43 +00:00
}
2017-07-23 15:23:18 +00:00
2019-10-10 16:12:20 +00:00
varr . resize ( size ( ) ) ;
2017-11-05 14:27:28 +00:00
int i = 0 ;
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
varr [ i ] = E . key ;
2017-11-05 14:27:28 +00:00
i + + ;
2017-07-23 15:23:18 +00:00
}
return varr ;
2014-02-10 01:10:30 +00:00
}
2016-06-05 12:20:52 +00:00
Array Dictionary : : values ( ) const {
Array varr ;
2023-06-24 18:03:28 +00: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 17:16:21 +00:00
return varr ;
2020-05-14 14:41:43 +00:00
}
2017-01-08 17:16:21 +00:00
2019-10-10 16:12:20 +00:00
varr . resize ( size ( ) ) ;
2017-11-05 14:27:28 +00:00
int i = 0 ;
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
varr [ i ] = E . value ;
2017-11-05 14:27:28 +00:00
i + + ;
2016-06-05 12:20:52 +00:00
}
2017-01-08 17:16:21 +00:00
2016-06-05 12:20:52 +00:00
return varr ;
}
2023-06-24 18:03:28 +00: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 ;
}
2014-02-10 01:10:30 +00:00
const Variant * Dictionary : : next ( const Variant * p_key ) const {
2020-04-01 23:20:12 +00:00
if ( p_key = = nullptr ) {
2017-11-05 14:27:28 +00:00
// caller wants to get the first element
2022-05-08 08:09:19 +00:00
if ( _p - > variant_map . begin ( ) ) {
return & _p - > variant_map . begin ( ) - > key ;
2020-05-14 14:41:43 +00:00
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2017-11-05 14:27:28 +00:00
}
2023-06-24 18:03:28 +00: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 14:27:28 +00:00
2022-05-08 08:09:19 +00:00
if ( ! E ) {
return nullptr ;
}
+ + E ;
if ( E ) {
return & E - > key ;
2020-05-14 14:41:43 +00:00
}
2022-05-08 08:09:19 +00:00
2020-04-01 23:20:12 +00:00
return nullptr ;
2014-02-10 01:10:30 +00:00
}
2018-03-09 19:16:08 +00:00
Dictionary Dictionary : : duplicate ( bool p_deep ) const {
2020-02-01 06:04:14 +00:00
return recursive_duplicate ( p_deep , 0 ) ;
}
2023-01-22 09:07:48 +00:00
void Dictionary : : make_read_only ( ) {
if ( _p - > read_only = = nullptr ) {
2022-05-16 13:44:43 +00:00
_p - > read_only = memnew ( Variant ) ;
}
}
bool Dictionary : : is_read_only ( ) const {
return _p - > read_only ! = nullptr ;
}
2020-02-01 06:04:14 +00:00
Dictionary Dictionary : : recursive_duplicate ( bool p_deep , int recursion_count ) const {
2017-01-11 11:53:31 +00:00
Dictionary n ;
2023-06-24 18:03:28 +00:00
n . _p - > typed_key = _p - > typed_key ;
n . _p - > typed_value = _p - > typed_value ;
2016-08-02 22:11:05 +00:00
2020-02-01 06:04:14 +00:00
if ( recursion_count > MAX_RECURSION ) {
ERR_PRINT ( " Max recursion reached " ) ;
return n ;
}
if ( p_deep ) {
recursion_count + + ;
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
n [ E . key . recursive_duplicate ( true , recursion_count ) ] = E . value . recursive_duplicate ( true , recursion_count ) ;
2020-02-01 06:04:14 +00:00
}
} else {
2022-05-08 08:09:19 +00:00
for ( const KeyValue < Variant , Variant > & E : _p - > variant_map ) {
n [ E . key ] = E . value ;
2020-02-01 06:04:14 +00:00
}
2016-08-02 22:11:05 +00:00
}
return n ;
}
2023-06-24 18:03:28 +00: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 ;
}
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 ;
}
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 ;
}
2014-02-10 01:10:30 +00:00
void Dictionary : : operator = ( const Dictionary & p_dictionary ) {
2022-05-16 13:44:43 +00:00
if ( this = = & p_dictionary ) {
return ;
}
2014-02-10 01:10:30 +00:00
_ref ( p_dictionary ) ;
}
2019-04-19 23:57:29 +00:00
const void * Dictionary : : id ( ) const {
2021-12-30 05:14:09 +00:00
return _p ;
2019-04-19 23:57:29 +00:00
}
2023-06-24 18:03:28 +00: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 ) ;
}
2014-02-10 01:10:30 +00:00
Dictionary : : Dictionary ( const Dictionary & p_from ) {
2020-04-01 23:20:12 +00:00
_p = nullptr ;
2014-02-10 01:10:30 +00:00
_ref ( p_from ) ;
}
2017-01-11 11:53:31 +00:00
Dictionary : : Dictionary ( ) {
2014-02-10 01:10:30 +00:00
_p = memnew ( DictionaryPrivate ) ;
_p - > refcount . init ( ) ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
Dictionary : : ~ Dictionary ( ) {
_unref ( ) ;
}