2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* string_name.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
2019-02-12 13:30:56 +01:00
# include "string_name.h"
2017-01-16 08:04:19 +01:00
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
2020-11-07 23:33:38 +01:00
# include "core/string/print_string.h"
2017-01-16 08:04:19 +01:00
2014-02-10 02:10:30 +01:00
StaticCString StaticCString : : create ( const char * p_ptr ) {
StaticCString scs ;
scs . ptr = p_ptr ;
return scs ;
}
StringName : : _Data * StringName : : _table [ STRING_TABLE_LEN ] ;
2021-07-17 23:22:52 +02:00
StringName _scs_create ( const char * p_chr , bool p_static ) {
return ( p_chr [ 0 ] ? StringName ( StaticCString : : create ( p_chr ) , p_static ) : StringName ( ) ) ;
2014-02-10 02:10:30 +01:00
}
bool StringName : : configured = false ;
2020-02-28 11:02:20 +01:00
Mutex StringName : : mutex ;
2014-02-10 02:10:30 +01:00
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
bool StringName : : debug_stringname = false ;
# endif
2014-02-10 02:10:30 +01:00
void StringName : : setup ( ) {
ERR_FAIL_COND ( configured ) ;
for ( int i = 0 ; i < STRING_TABLE_LEN ; i + + ) {
2020-04-02 01:20:12 +02:00
_table [ i ] = nullptr ;
2014-02-10 02:10:30 +01:00
}
configured = true ;
}
void StringName : : cleanup ( ) {
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2017-01-07 22:25:37 +01:00
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
if ( unlikely ( debug_stringname ) ) {
Vector < _Data * > data ;
for ( int i = 0 ; i < STRING_TABLE_LEN ; i + + ) {
_Data * d = _table [ i ] ;
while ( d ) {
data . push_back ( d ) ;
d = d - > next ;
}
}
2022-03-14 00:44:19 +01:00
print_line ( " \n StringName reference ranking (from most to least referenced): \n " ) ;
2021-07-20 22:01:18 +02:00
data . sort_custom < DebugSortReferences > ( ) ;
2022-03-14 00:44:19 +01:00
int unreferenced_stringnames = 0 ;
int rarely_referenced_stringnames = 0 ;
for ( int i = 0 ; i < data . size ( ) ; i + + ) {
2021-07-20 22:01:18 +02:00
print_line ( itos ( i + 1 ) + " : " + data [ i ] - > get_name ( ) + " - " + itos ( data [ i ] - > debug_references ) ) ;
2022-03-14 00:44:19 +01:00
if ( data [ i ] - > debug_references = = 0 ) {
unreferenced_stringnames + = 1 ;
} else if ( data [ i ] - > debug_references < 5 ) {
rarely_referenced_stringnames + = 1 ;
}
2021-07-20 22:01:18 +02:00
}
2022-03-14 00:44:19 +01:00
print_line ( vformat ( " \n Out of %d StringNames, %d StringNames were never referenced during this run (0 times) (%.2f%%). " , data . size ( ) , unreferenced_stringnames , unreferenced_stringnames / float ( data . size ( ) ) * 100 ) ) ;
print_line ( vformat ( " Out of %d StringNames, %d StringNames were rarely referenced during this run (1-4 times) (%.2f%%). " , data . size ( ) , rarely_referenced_stringnames , rarely_referenced_stringnames / float ( data . size ( ) ) * 100 ) ) ;
2021-07-20 22:01:18 +02:00
}
# endif
2015-04-21 00:38:02 +02:00
int lost_strings = 0 ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < STRING_TABLE_LEN ; i + + ) {
while ( _table [ i ] ) {
_Data * d = _table [ i ] ;
2022-01-20 22:09:03 +01:00
if ( d - > static_count . get ( ) ! = d - > refcount . get ( ) ) {
lost_strings + + ;
if ( OS : : get_singleton ( ) - > is_stdout_verbose ( ) ) {
2023-10-19 17:11:42 +02:00
String dname = String ( d - > cname ? d - > cname : d - > name ) ;
print_line ( vformat ( " Orphan StringName: %s (static: %d, total: %d) " , dname , d - > static_count . get ( ) , d - > refcount . get ( ) ) ) ;
2015-04-21 00:38:02 +02:00
}
}
2016-03-09 00:00:52 +01:00
_table [ i ] = _table [ i ] - > next ;
2014-02-10 02:10:30 +01:00
memdelete ( d ) ;
}
}
2018-08-24 08:47:34 +02:00
if ( lost_strings ) {
2023-10-19 17:11:42 +02:00
print_verbose ( vformat ( " StringName: %d unclaimed string names at exit. " , lost_strings ) ) ;
2015-04-21 00:38:02 +02:00
}
2021-07-17 23:22:52 +02:00
configured = false ;
2014-02-10 02:10:30 +01:00
}
void StringName : : unref ( ) {
ERR_FAIL_COND ( ! configured ) ;
if ( _data & & _data - > refcount . unref ( ) ) {
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2014-02-10 02:10:30 +01:00
2021-07-17 23:22:52 +02:00
if ( _data - > static_count . get ( ) > 0 ) {
if ( _data - > cname ) {
ERR_PRINT ( " BUG: Unreferenced static string to 0: " + String ( _data - > cname ) ) ;
} else {
ERR_PRINT ( " BUG: Unreferenced static string to 0: " + String ( _data - > name ) ) ;
}
}
2014-02-10 02:10:30 +01:00
if ( _data - > prev ) {
_data - > prev - > next = _data - > next ;
} else {
if ( _table [ _data - > idx ] ! = _data ) {
ERR_PRINT ( " BUG! " ) ;
}
_table [ _data - > idx ] = _data - > next ;
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( _data - > next ) {
_data - > next - > prev = _data - > prev ;
}
memdelete ( _data ) ;
}
2016-03-09 00:00:52 +01:00
2020-04-02 01:20:12 +02:00
_data = nullptr ;
2014-02-10 02:10:30 +01:00
}
bool StringName : : operator = = ( const String & p_name ) const {
if ( ! _data ) {
return ( p_name . length ( ) = = 0 ) ;
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return ( _data - > get_name ( ) = = p_name ) ;
}
bool StringName : : operator = = ( const char * p_name ) const {
if ( ! _data ) {
return ( p_name [ 0 ] = = 0 ) ;
}
return ( _data - > get_name ( ) = = p_name ) ;
}
bool StringName : : operator ! = ( const String & p_name ) const {
return ! ( operator = = ( p_name ) ) ;
}
2022-12-20 15:22:44 +01:00
bool StringName : : operator ! = ( const char * p_name ) const {
return ! ( operator = = ( p_name ) ) ;
}
2014-02-10 02:10:30 +01:00
bool StringName : : operator ! = ( const StringName & p_name ) const {
2016-03-09 00:00:52 +01:00
// the real magic of all this mess happens here.
2014-02-10 02:10:30 +01:00
// this is why path comparisons are very fast
return _data ! = p_name . _data ;
}
void StringName : : operator = ( const StringName & p_name ) {
2020-05-14 16:41:43 +02:00
if ( this = = & p_name ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
unref ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( p_name . _data & & p_name . _data - > refcount . ref ( ) ) {
2016-03-09 00:00:52 +01:00
_data = p_name . _data ;
2014-02-10 02:10:30 +01:00
}
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
StringName : : StringName ( const StringName & p_name ) {
2020-04-02 01:20:12 +02:00
_data = nullptr ;
2016-03-09 00:00:52 +01:00
2018-04-18 22:20:39 +02:00
ERR_FAIL_COND ( ! configured ) ;
if ( p_name . _data & & p_name . _data - > refcount . ref ( ) ) {
2016-03-09 00:00:52 +01:00
_data = p_name . _data ;
}
2014-02-10 02:10:30 +01:00
}
2023-04-07 23:32:37 +02:00
void StringName : : assign_static_unique_class_name ( StringName * ptr , const char * p_name ) {
mutex . lock ( ) ;
if ( * ptr = = StringName ( ) ) {
* ptr = StringName ( p_name , true ) ;
}
mutex . unlock ( ) ;
}
2021-07-17 23:22:52 +02:00
StringName : : StringName ( const char * p_name , bool p_static ) {
2020-04-02 01:20:12 +02:00
_data = nullptr ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! configured ) ;
2020-05-14 16:41:43 +02:00
if ( ! p_name | | p_name [ 0 ] = = 0 ) {
2016-08-22 06:14:08 +02:00
return ; //empty, ignore
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
uint32_t hash = String : : hash ( p_name ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
uint32_t idx = hash & STRING_TABLE_MASK ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
_data = _table [ idx ] ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
while ( _data ) {
// compare hash first
2020-05-14 16:41:43 +02:00
if ( _data - > hash = = hash & & _data - > get_name ( ) = = p_name ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_data = _data - > next ;
}
2023-02-04 04:19:52 +01:00
if ( _data & & _data - > refcount . ref ( ) ) {
// exists
if ( p_static ) {
_data - > static_count . increment ( ) ;
}
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
2023-02-04 04:19:52 +01:00
if ( unlikely ( debug_stringname ) ) {
_data - > debug_references + + ;
2014-02-10 02:10:30 +01:00
}
2023-02-04 04:19:52 +01:00
# endif
2021-07-20 22:01:18 +02:00
return ;
2014-02-10 02:10:30 +01:00
}
_data = memnew ( _Data ) ;
_data - > name = p_name ;
_data - > refcount . init ( ) ;
2021-07-17 23:22:52 +02:00
_data - > static_count . set ( p_static ? 1 : 0 ) ;
2014-02-10 02:10:30 +01:00
_data - > hash = hash ;
_data - > idx = idx ;
2020-04-02 01:20:12 +02:00
_data - > cname = nullptr ;
2014-02-10 02:10:30 +01:00
_data - > next = _table [ idx ] ;
2020-04-02 01:20:12 +02:00
_data - > prev = nullptr ;
2022-04-16 12:23:32 +02:00
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
if ( unlikely ( debug_stringname ) ) {
// Keep in memory, force static.
_data - > refcount . ref ( ) ;
_data - > static_count . increment ( ) ;
}
# endif
2020-05-14 16:41:43 +02:00
if ( _table [ idx ] ) {
2014-02-10 02:10:30 +01:00
_table [ idx ] - > prev = _data ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_table [ idx ] = _data ;
}
2021-07-17 23:22:52 +02:00
StringName : : StringName ( const StaticCString & p_static_string , bool p_static ) {
2020-04-02 01:20:12 +02:00
_data = nullptr ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! configured ) ;
ERR_FAIL_COND ( ! p_static_string . ptr | | ! p_static_string . ptr [ 0 ] ) ;
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2014-02-10 02:10:30 +01:00
uint32_t hash = String : : hash ( p_static_string . ptr ) ;
uint32_t idx = hash & STRING_TABLE_MASK ;
_data = _table [ idx ] ;
while ( _data ) {
// compare hash first
2020-05-14 16:41:43 +02:00
if ( _data - > hash = = hash & & _data - > get_name ( ) = = p_static_string . ptr ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_data = _data - > next ;
}
2023-02-04 04:19:52 +01:00
if ( _data & & _data - > refcount . ref ( ) ) {
// exists
if ( p_static ) {
_data - > static_count . increment ( ) ;
}
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
2023-02-04 04:19:52 +01:00
if ( unlikely ( debug_stringname ) ) {
_data - > debug_references + + ;
2014-02-10 02:10:30 +01:00
}
2023-02-04 04:19:52 +01:00
# endif
return ;
2014-02-10 02:10:30 +01:00
}
_data = memnew ( _Data ) ;
_data - > refcount . init ( ) ;
2021-07-17 23:22:52 +02:00
_data - > static_count . set ( p_static ? 1 : 0 ) ;
2014-02-10 02:10:30 +01:00
_data - > hash = hash ;
2016-03-09 00:00:52 +01:00
_data - > idx = idx ;
2014-02-10 02:10:30 +01:00
_data - > cname = p_static_string . ptr ;
_data - > next = _table [ idx ] ;
2020-04-02 01:20:12 +02:00
_data - > prev = nullptr ;
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
if ( unlikely ( debug_stringname ) ) {
// Keep in memory, force static.
_data - > refcount . ref ( ) ;
_data - > static_count . increment ( ) ;
}
# endif
2020-05-14 16:41:43 +02:00
if ( _table [ idx ] ) {
2014-02-10 02:10:30 +01:00
_table [ idx ] - > prev = _data ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_table [ idx ] = _data ;
}
2021-07-17 23:22:52 +02:00
StringName : : StringName ( const String & p_name , bool p_static ) {
2020-04-02 01:20:12 +02:00
_data = nullptr ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! configured ) ;
2021-12-09 10:42:46 +01:00
if ( p_name . is_empty ( ) ) {
2016-08-22 06:14:08 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-08-22 06:14:08 +02:00
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
uint32_t hash = p_name . hash ( ) ;
uint32_t idx = hash & STRING_TABLE_MASK ;
_data = _table [ idx ] ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
while ( _data ) {
2020-05-14 16:41:43 +02:00
if ( _data - > hash = = hash & & _data - > get_name ( ) = = p_name ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_data = _data - > next ;
}
2016-03-09 00:00:52 +01:00
2023-02-04 04:19:52 +01:00
if ( _data & & _data - > refcount . ref ( ) ) {
// exists
if ( p_static ) {
_data - > static_count . increment ( ) ;
}
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
2023-02-04 04:19:52 +01:00
if ( unlikely ( debug_stringname ) ) {
_data - > debug_references + + ;
2014-02-10 02:10:30 +01:00
}
2023-02-04 04:19:52 +01:00
# endif
return ;
2014-02-10 02:10:30 +01:00
}
_data = memnew ( _Data ) ;
_data - > name = p_name ;
_data - > refcount . init ( ) ;
2021-07-17 23:22:52 +02:00
_data - > static_count . set ( p_static ? 1 : 0 ) ;
2014-02-10 02:10:30 +01:00
_data - > hash = hash ;
_data - > idx = idx ;
2020-04-02 01:20:12 +02:00
_data - > cname = nullptr ;
2014-02-10 02:10:30 +01:00
_data - > next = _table [ idx ] ;
2020-04-02 01:20:12 +02:00
_data - > prev = nullptr ;
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
if ( unlikely ( debug_stringname ) ) {
// Keep in memory, force static.
_data - > refcount . ref ( ) ;
_data - > static_count . increment ( ) ;
}
# endif
2020-05-14 16:41:43 +02:00
if ( _table [ idx ] ) {
2014-02-10 02:10:30 +01:00
_table [ idx ] - > prev = _data ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_table [ idx ] = _data ;
}
StringName StringName : : search ( const char * p_name ) {
ERR_FAIL_COND_V ( ! configured , StringName ( ) ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL_V ( p_name , StringName ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! p_name [ 0 ] ) {
2014-02-10 02:10:30 +01:00
return StringName ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2014-02-10 02:10:30 +01:00
uint32_t hash = String : : hash ( p_name ) ;
uint32_t idx = hash & STRING_TABLE_MASK ;
_Data * _data = _table [ idx ] ;
while ( _data ) {
// compare hash first
2020-05-14 16:41:43 +02:00
if ( _data - > hash = = hash & & _data - > get_name ( ) = = p_name ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_data = _data - > next ;
}
if ( _data & & _data - > refcount . ref ( ) ) {
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
if ( unlikely ( debug_stringname ) ) {
_data - > debug_references + + ;
}
# endif
2014-02-10 02:10:30 +01:00
return StringName ( _data ) ;
}
return StringName ( ) ; //does not exist
}
2020-07-27 12:43:20 +02:00
StringName StringName : : search ( const char32_t * p_name ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND_V ( ! configured , StringName ( ) ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL_V ( p_name , StringName ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! p_name [ 0 ] ) {
2014-02-10 02:10:30 +01:00
return StringName ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2014-02-10 02:10:30 +01:00
uint32_t hash = String : : hash ( p_name ) ;
uint32_t idx = hash & STRING_TABLE_MASK ;
_Data * _data = _table [ idx ] ;
while ( _data ) {
// compare hash first
2020-05-14 16:41:43 +02:00
if ( _data - > hash = = hash & & _data - > get_name ( ) = = p_name ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_data = _data - > next ;
}
if ( _data & & _data - > refcount . ref ( ) ) {
return StringName ( _data ) ;
}
return StringName ( ) ; //does not exist
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
StringName StringName : : search ( const String & p_name ) {
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND_V ( p_name . is_empty ( ) , StringName ( ) ) ;
2014-02-10 02:10:30 +01:00
2020-02-28 11:02:20 +01:00
MutexLock lock ( mutex ) ;
2014-02-10 02:10:30 +01:00
uint32_t hash = p_name . hash ( ) ;
uint32_t idx = hash & STRING_TABLE_MASK ;
_Data * _data = _table [ idx ] ;
while ( _data ) {
// compare hash first
2020-05-14 16:41:43 +02:00
if ( _data - > hash = = hash & & p_name = = _data - > get_name ( ) ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
_data = _data - > next ;
}
if ( _data & & _data - > refcount . ref ( ) ) {
2021-07-20 22:01:18 +02:00
# ifdef DEBUG_ENABLED
if ( unlikely ( debug_stringname ) ) {
_data - > debug_references + + ;
}
# endif
2014-02-10 02:10:30 +01:00
return StringName ( _data ) ;
}
return StringName ( ) ; //does not exist
}
2020-11-05 03:01:55 +01:00
bool operator = = ( const String & p_name , const StringName & p_string_name ) {
return p_name = = p_string_name . operator String ( ) ;
}
bool operator ! = ( const String & p_name , const StringName & p_string_name ) {
return p_name ! = p_string_name . operator String ( ) ;
}
bool operator = = ( const char * p_name , const StringName & p_string_name ) {
return p_name = = p_string_name . operator String ( ) ;
}
bool operator ! = ( const char * p_name , const StringName & p_string_name ) {
return p_name ! = p_string_name . operator String ( ) ;
}