summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.h2
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/debugger/local_debugger.cpp6
-rw-r--r--core/debugger/script_debugger.cpp2
-rw-r--r--core/debugger/script_debugger.h6
-rw-r--r--core/extension/gdnative_interface.cpp12
-rw-r--r--core/extension/gdnative_interface.h2
-rw-r--r--core/input/input.cpp12
-rw-r--r--core/input/input.h5
-rw-r--r--core/io/file_access_pack.h4
-rw-r--r--core/io/json.cpp4
-rw-r--r--core/io/json.h2
-rw-r--r--core/io/logger.cpp10
-rw-r--r--core/io/resource.h2
-rw-r--r--core/io/resource_format_binary.cpp4
-rw-r--r--core/io/resource_format_binary.h2
-rw-r--r--core/io/resource_importer.cpp4
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/io/stream_peer_ssl.cpp1
-rw-r--r--core/io/stream_peer_ssl.h1
-rw-r--r--core/math/a_star.cpp24
-rw-r--r--core/math/a_star.h7
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/quick_hull.h2
-rw-r--r--core/math/static_raycaster.h2
-rw-r--r--core/multiplayer/multiplayer.h2
-rw-r--r--core/multiplayer/multiplayer_api.h4
-rw-r--r--core/object/callable_method_pointer.h82
-rw-r--r--core/object/class_db.cpp2
-rw-r--r--core/object/class_db.h5
-rw-r--r--core/object/object.h6
-rw-r--r--core/object/script_language.cpp2
-rw-r--r--core/object/script_language.h4
-rw-r--r--core/object/script_language_extension.h4
-rw-r--r--core/os/os.cpp31
-rw-r--r--core/string/translation.h4
-rw-r--r--core/string/ustring.cpp27
-rw-r--r--core/templates/bin_sorted_array.h4
-rw-r--r--core/templates/hash_set.h473
-rw-r--r--core/templates/rb_set.h3
-rw-r--r--core/templates/rid_owner.h2
-rw-r--r--core/variant/variant.cpp4
-rw-r--r--core/variant/variant_call.cpp5
43 files changed, 702 insertions, 84 deletions
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index bacc8adc54..d9b1a9b81b 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -91,7 +91,7 @@ protected:
bool using_datapack = false;
List<String> input_presets;
- RBSet<String> custom_features;
+ HashSet<String> custom_features;
HashMap<StringName, StringName> feature_overrides;
HashMap<StringName, AutoloadInfo> autoloads;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index a53929a3af..ea1304f5ba 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -645,7 +645,7 @@ void register_global_constants() {
// rpc
BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_DISABLED", Multiplayer::RPC_MODE_DISABLED);
BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_ANY_PEER", Multiplayer::RPC_MODE_ANY_PEER);
- BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTH", Multiplayer::RPC_MODE_AUTHORITY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTHORITY", Multiplayer::RPC_MODE_AUTHORITY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE", Multiplayer::TRANSFER_MODE_UNRELIABLE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE_ORDERED", Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED);
diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp
index f378ba94c3..06e08081e9 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -241,15 +241,15 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else if (line.begins_with("br") || line.begins_with("break")) {
if (line.get_slice_count(" ") <= 1) {
- const HashMap<int, RBSet<StringName>> &breakpoints = script_debugger->get_breakpoints();
+ const HashMap<int, HashSet<StringName>> &breakpoints = script_debugger->get_breakpoints();
if (breakpoints.size() == 0) {
print_line("No Breakpoints.");
continue;
}
print_line("Breakpoint(s): " + itos(breakpoints.size()));
- for (const KeyValue<int, RBSet<StringName>> &E : breakpoints) {
- print_line("\t" + String(E.value.front()->get()) + ":" + itos(E.key));
+ for (const KeyValue<int, HashSet<StringName>> &E : breakpoints) {
+ print_line("\t" + String(*E.value.begin()) + ":" + itos(E.key));
}
} else {
diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp
index 1efa7f7690..e30f3e7886 100644
--- a/core/debugger/script_debugger.cpp
+++ b/core/debugger/script_debugger.cpp
@@ -50,7 +50,7 @@ int ScriptDebugger::get_depth() const {
void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
if (!breakpoints.has(p_line)) {
- breakpoints[p_line] = RBSet<StringName>();
+ breakpoints[p_line] = HashSet<StringName>();
}
breakpoints[p_line].insert(p_source);
}
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index a5a72d7c54..5124b357a5 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -33,8 +33,8 @@
#include "core/object/script_language.h"
#include "core/string/string_name.h"
+#include "core/templates/hash_set.h"
#include "core/templates/rb_map.h"
-#include "core/templates/rb_set.h"
#include "core/templates/vector.h"
class ScriptDebugger {
@@ -44,7 +44,7 @@ class ScriptDebugger {
int depth = -1;
bool skip_breakpoints = false;
- HashMap<int, RBSet<StringName>> breakpoints;
+ HashMap<int, HashSet<StringName>> breakpoints;
ScriptLanguage *break_lang = nullptr;
Vector<StackInfo> error_stack_info;
@@ -66,7 +66,7 @@ public:
bool is_breakpoint(int p_line, const StringName &p_source) const;
bool is_breakpoint_line(int p_line) const;
void clear_breakpoints();
- const HashMap<int, RBSet<StringName>> &get_breakpoints() const { return breakpoints; }
+ const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
void debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
ScriptLanguage *get_break_language() const;
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index a1d54f9c6d..58103e3af3 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -230,6 +230,16 @@ static void gdnative_variant_iter_get(const GDNativeVariantPtr p_self, GDNativeV
}
/// Variant functions.
+static GDNativeInt gdnative_variant_hash(const GDNativeVariantPtr p_self) {
+ const Variant *self = (const Variant *)p_self;
+ return self->hash();
+}
+
+static GDNativeInt gdnative_variant_recursive_hash(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count) {
+ const Variant *self = (const Variant *)p_self;
+ return self->recursive_hash(p_recursion_count);
+}
+
static GDNativeBool gdnative_variant_hash_compare(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other) {
const Variant *self = (const Variant *)p_self;
const Variant *other = (const Variant *)p_other;
@@ -944,6 +954,8 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_iter_init = gdnative_variant_iter_init;
gdni.variant_iter_next = gdnative_variant_iter_next;
gdni.variant_iter_get = gdnative_variant_iter_get;
+ gdni.variant_hash = gdnative_variant_hash;
+ gdni.variant_recursive_hash = gdnative_variant_recursive_hash;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
gdni.variant_sub = gdnative_variant_sub;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 98976b29f6..095c7983ee 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -413,6 +413,8 @@ typedef struct {
GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
+ GDNativeInt (*variant_hash)(const GDNativeVariantPtr p_self);
+ GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 4befdfac58..b3a68bb98c 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -134,8 +134,12 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
+ ClassDB::bind_method(D_METHOD("is_using_accumulated_input"), &Input::is_using_accumulated_input);
ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
+
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
@@ -897,6 +901,10 @@ void Input::set_use_accumulated_input(bool p_enable) {
use_accumulated_input = p_enable;
}
+bool Input::is_using_accumulated_input() {
+ return use_accumulated_input;
+}
+
void Input::release_pressed_events() {
flush_buffered_events(); // this is needed to release actions strengths
@@ -1401,8 +1409,8 @@ String Input::get_joy_guid(int p_device) const {
return joy_names[p_device].uid;
}
-Array Input::get_connected_joypads() {
- Array ret;
+TypedArray<int> Input::get_connected_joypads() {
+ TypedArray<int> ret;
HashMap<int, Joypad>::Iterator elem = joy_names.begin();
while (elem) {
if (elem->value.connected) {
diff --git a/core/input/input.h b/core/input/input.h
index 7bb7889a43..f02f2abae5 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -35,6 +35,8 @@
#include "core/object/object.h"
#include "core/os/keyboard.h"
#include "core/os/thread_safe.h"
+#include "core/templates/rb_set.h"
+#include "core/variant/typed_array.h"
class Input : public Object {
GDCLASS(Input, Object);
@@ -258,7 +260,7 @@ public:
float get_joy_axis(int p_device, JoyAxis p_axis) const;
String get_joy_name(int p_idx);
- Array get_connected_joypads();
+ TypedArray<int> get_connected_joypads();
Vector2 get_joy_vibration_strength(int p_device);
float get_joy_vibration_duration(int p_device);
uint64_t get_joy_vibration_timestamp(int p_device);
@@ -325,6 +327,7 @@ public:
bool is_using_input_buffering();
void set_use_input_buffering(bool p_enable);
void set_use_accumulated_input(bool p_enable);
+ bool is_using_accumulated_input();
void release_pressed_events();
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 404ad38c96..19a0cce796 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -34,9 +34,9 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/string/print_string.h"
+#include "core/templates/hash_set.h"
#include "core/templates/list.h"
#include "core/templates/rb_map.h"
-#include "core/templates/rb_set.h"
// Godot's packed file magic header ("GDPC" in ASCII).
#define PACK_HEADER_MAGIC 0x43504447
@@ -73,7 +73,7 @@ private:
PackedDir *parent = nullptr;
String name;
HashMap<String, PackedDir *> subdirs;
- RBSet<String> files;
+ HashSet<String> files;
};
struct PathMD5 {
diff --git a/core/io/json.cpp b/core/io/json.cpp
index b3a9762e75..4c4d91f851 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -55,7 +55,7 @@ String JSON::_make_indent(const String &p_indent, int p_size) {
return indent_text;
}
-String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, RBSet<const void *> &p_markers, bool p_full_precision) {
+String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) {
String colon = ":";
String end_statement = "";
@@ -529,7 +529,7 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
}
String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
- RBSet<const void *> markers;
+ HashSet<const void *> markers;
return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
}
diff --git a/core/io/json.h b/core/io/json.h
index f883d3963a..6ba0a8c76b 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -70,7 +70,7 @@ class JSON : public RefCounted {
static const char *tk_name[];
static String _make_indent(const String &p_indent, int p_size);
- static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, RBSet<const void *> &p_markers, bool p_full_precision = false);
+ static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 925bfdbd02..5820ec0c09 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -128,7 +128,7 @@ void RotatedFileLogger::clear_old_backups() {
da->list_dir_begin();
String f = da->get_next();
- RBSet<String> backups;
+ HashSet<String> backups;
while (!f.is_empty()) {
if (!da->current_is_dir() && f.begins_with(basename) && f.get_extension() == extension && f != base_path.get_file()) {
backups.insert(f);
@@ -137,12 +137,12 @@ void RotatedFileLogger::clear_old_backups() {
}
da->list_dir_end();
- if (backups.size() > max_backups) {
+ if (backups.size() > (uint32_t)max_backups) {
// since backups are appended with timestamp and Set iterates them in sorted order,
// first backups are the oldest
int to_delete = backups.size() - max_backups;
- for (RBSet<String>::Element *E = backups.front(); E && to_delete > 0; E = E->next(), --to_delete) {
- da->remove(E->get());
+ for (HashSet<String>::Iterator E = backups.begin(); E && to_delete > 0; ++E, --to_delete) {
+ da->remove(*E);
}
}
}
@@ -172,7 +172,7 @@ void RotatedFileLogger::rotate_file() {
}
file = FileAccess::open(base_path, FileAccess::WRITE);
- file->detach_from_objectdb(); // Note: This FileAccess instance will exist longer than ObjectDB, therefor can't be registered in ObjectDB.
+ file->detach_from_objectdb(); // Note: This FileAccess instance will exist longer than ObjectDB, therefore can't be registered in ObjectDB.
}
RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) :
diff --git a/core/io/resource.h b/core/io/resource.h
index 53c828f9cd..a45bc6e1e4 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -54,7 +54,7 @@ public:
virtual String get_base_extension() const { return "res"; }
private:
- RBSet<ObjectID> owners;
+ HashSet<ObjectID> owners;
friend class ResBase;
friend class ResourceCache;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index cf87869a32..24458f20b4 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1976,7 +1976,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
}
if (p.pi.type == Variant::OBJECT && missing_resource_properties.has(F.name)) {
- // Was this missing resource overriden? If so do not save the old value.
+ // Was this missing resource overridden? If so do not save the old value.
Ref<Resource> res = p.value;
if (res.is_null()) {
p.value = missing_resource_properties[F.name];
@@ -2022,7 +2022,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
// save internal resource table
f->store_32(saved_resources.size()); //amount of internal resources
Vector<uint64_t> ofs_pos;
- RBSet<String> used_unique_ids;
+ HashSet<String> used_unique_ids;
for (Ref<Resource> &r : saved_resources) {
if (r->is_built_in()) {
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index db29909dd5..5da880ddb8 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -127,7 +127,7 @@ class ResourceFormatSaverBinaryInstance {
bool big_endian;
bool takeover_paths;
String magic;
- RBSet<Ref<Resource>> resource_set;
+ HashSet<Ref<Resource>> resource_set;
struct NonPersistentKey { //for resource properties generated on the fly
Ref<Resource> base;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 5deee9721b..934cb780e6 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -139,7 +139,7 @@ Ref<Resource> ResourceFormatImporter::load(const String &p_path, const String &p
}
void ResourceFormatImporter::get_recognized_extensions(List<String> *p_extensions) const {
- RBSet<String> found;
+ HashSet<String> found;
for (int i = 0; i < importers.size(); i++) {
List<String> local_exts;
@@ -159,7 +159,7 @@ void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_
return;
}
- RBSet<String> found;
+ HashSet<String> found;
for (int i = 0; i < importers.size(); i++) {
String res_type = importers[i]->get_resource_type();
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index e189ad1dff..815dd1dd72 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -145,7 +145,7 @@ private:
bool start_next = true;
int requests = 0;
int poll_requests = 0;
- RBSet<String> sub_tasks;
+ HashSet<String> sub_tasks;
};
static void _thread_load_function(void *p_userdata);
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index ea8435e587..5b90fb52a6 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -60,6 +60,7 @@ void StreamPeerSSL::_bind_methods() {
ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerSSL::accept_stream, DEFVAL(Ref<X509Certificate>()));
ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status);
+ ClassDB::bind_method(D_METHOD("get_stream"), &StreamPeerSSL::get_stream);
ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream);
ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled);
ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled);
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h
index 15f646d897..fe68667adc 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_ssl.h
@@ -61,6 +61,7 @@ public:
virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>()) = 0;
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_valid_cert = Ref<X509Certificate>()) = 0;
virtual Status get_status() const = 0;
+ virtual Ref<StreamPeer> get_stream() const = 0;
virtual void disconnect_from_stream() = 0;
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 29aa959e54..efa970c681 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -151,15 +151,15 @@ void AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) {
s.direction = Segment::BIDIRECTIONAL;
}
- RBSet<Segment>::Element *element = segments.find(s);
- if (element != nullptr) {
- s.direction |= element->get().direction;
+ HashSet<Segment, Segment>::Iterator element = segments.find(s);
+ if (element) {
+ s.direction |= element->direction;
if (s.direction == Segment::BIDIRECTIONAL) {
// Both are neighbours of each other now
a->unlinked_neighbours.remove(b->id);
b->unlinked_neighbours.remove(a->id);
}
- segments.erase(element);
+ segments.remove(element);
}
segments.insert(s);
@@ -177,16 +177,16 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) {
Segment s(p_id, p_with_id);
int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : s.direction;
- RBSet<Segment>::Element *element = segments.find(s);
- if (element != nullptr) {
+ HashSet<Segment, Segment>::Iterator element = segments.find(s);
+ if (element) {
// s is the new segment
// Erase the directions to be removed
- s.direction = (element->get().direction & ~remove_direction);
+ s.direction = (element->direction & ~remove_direction);
a->neighbours.remove(b->id);
if (bidirectional) {
b->neighbours.remove(a->id);
- if (element->get().direction != Segment::BIDIRECTIONAL) {
+ if (element->direction != Segment::BIDIRECTIONAL) {
a->unlinked_neighbours.remove(b->id);
b->unlinked_neighbours.remove(a->id);
}
@@ -198,7 +198,7 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) {
}
}
- segments.erase(element);
+ segments.remove(element);
if (s.direction != Segment::NONE) {
segments.insert(s);
}
@@ -235,10 +235,10 @@ Vector<int> AStar3D::get_point_connections(int p_id) {
bool AStar3D::are_points_connected(int p_id, int p_with_id, bool bidirectional) const {
Segment s(p_id, p_with_id);
- const RBSet<Segment>::Element *element = segments.find(s);
+ const HashSet<Segment, Segment>::Iterator element = segments.find(s);
- return element != nullptr &&
- (bidirectional || (element->get().direction & s.direction) == s.direction);
+ return element &&
+ (bidirectional || (element->direction & s.direction) == s.direction);
}
void AStar3D::clear() {
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 086be839b5..e2f75ad18c 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -92,7 +92,10 @@ class AStar3D : public RefCounted {
};
unsigned char direction = NONE;
- bool operator<(const Segment &p_s) const { return key < p_s.key; }
+ static uint32_t hash(const Segment &p_seg) {
+ return hash_one_uint64(p_seg.key);
+ }
+ bool operator==(const Segment &p_s) const { return key == p_s.key; }
Segment() {}
Segment(int p_from, int p_to) {
@@ -112,7 +115,7 @@ class AStar3D : public RefCounted {
uint64_t pass = 1;
OAHashMap<int, Point *> points;
- RBSet<Segment> segments;
+ HashSet<Segment, Segment> segments;
bool _solve(Point *begin_point, Point *end_point);
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 43744deeb0..c7727a44a1 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -52,7 +52,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
Vector<bool> valid_points;
valid_points.resize(p_points.size());
- RBSet<Vector3> valid_cache;
+ HashSet<Vector3> valid_cache;
for (int i = 0; i < p_points.size(); i++) {
Vector3 sp = p_points[i].snapped(Vector3(0.0001, 0.0001, 0.0001));
diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h
index 1c354880b4..6783743fc2 100644
--- a/core/math/quick_hull.h
+++ b/core/math/quick_hull.h
@@ -33,8 +33,8 @@
#include "core/math/aabb.h"
#include "core/math/geometry_3d.h"
+#include "core/templates/hash_set.h"
#include "core/templates/list.h"
-#include "core/templates/rb_set.h"
class QuickHull {
public:
diff --git a/core/math/static_raycaster.h b/core/math/static_raycaster.h
index adc81906d7..bc6511c073 100644
--- a/core/math/static_raycaster.h
+++ b/core/math/static_raycaster.h
@@ -102,7 +102,7 @@ public:
virtual void add_mesh(const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices, unsigned int p_id) = 0;
virtual void commit() = 0;
- virtual void set_mesh_filter(const RBSet<int> &p_mesh_ids) = 0;
+ virtual void set_mesh_filter(const HashSet<int> &p_mesh_ids) = 0;
virtual void clear_mesh_filter() = 0;
static Ref<StaticRaycaster> create();
diff --git a/core/multiplayer/multiplayer.h b/core/multiplayer/multiplayer.h
index 5eb968171a..f4c965b0f8 100644
--- a/core/multiplayer/multiplayer.h
+++ b/core/multiplayer/multiplayer.h
@@ -46,7 +46,7 @@ enum TransferMode {
enum RPCMode {
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
RPC_MODE_ANY_PEER, // Any peer can call this RPC
- RPC_MODE_AUTHORITY, // / Only the node's multiplayer authority (server by default) can call this RPC
+ RPC_MODE_AUTHORITY, // Only the node's multiplayer authority (server by default) can call this RPC
};
struct RPCConfig {
diff --git a/core/multiplayer/multiplayer_api.h b/core/multiplayer/multiplayer_api.h
index b93f2acbd3..cc7743ccf8 100644
--- a/core/multiplayer/multiplayer_api.h
+++ b/core/multiplayer/multiplayer_api.h
@@ -113,7 +113,7 @@ public:
private:
Ref<MultiplayerPeer> multiplayer_peer;
- RBSet<int> connected_peers;
+ HashSet<int> connected_peers;
int remote_sender_id = 0;
int remote_sender_override = 0;
@@ -172,7 +172,7 @@ public:
bool has_multiplayer_peer() const { return multiplayer_peer.is_valid(); }
Vector<int> get_peer_ids() const;
- const RBSet<int> get_connected_peers() const { return connected_peers; }
+ const HashSet<int> get_connected_peers() const { return connected_peers; }
int get_remote_sender_id() const { return remote_sender_override ? remote_sender_override : remote_sender_id; }
void set_remote_sender_override(int p_id) { remote_sender_override = p_id; }
int get_unique_id() const;
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 577d4b9fbd..f2a440b49a 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -245,4 +245,86 @@ Callable create_custom_callable_function_pointer(T *p_instance,
#define callable_mp(I, M) create_custom_callable_function_pointer(I, M)
#endif
+// STATIC VERSIONS
+
+template <class... P>
+class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
+ struct Data {
+ void (*method)(P...);
+ } data;
+
+public:
+ virtual ObjectID get_object() const {
+ return ObjectID();
+ }
+
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
+ r_return_value = Variant();
+ }
+
+ CallableCustomStaticMethodPointer(void (*p_method)(P...)) {
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
+ }
+};
+
+template <class T, class... P>
+Callable create_custom_callable_static_function_pointer(
+#ifdef DEBUG_METHODS_ENABLED
+ const char *p_func_text,
+#endif
+ void (*p_method)(P...)) {
+ typedef CallableCustomStaticMethodPointer<P...> CCMP; // Messes with memnew otherwise.
+ CCMP *ccmp = memnew(CCMP(p_method));
+#ifdef DEBUG_METHODS_ENABLED
+ ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
+#endif
+ return Callable(ccmp);
+}
+
+template <class R, class... P>
+class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
+ struct Data {
+ R(*method)
+ (P...);
+ } data;
+
+public:
+ virtual ObjectID get_object() const {
+ return ObjectID();
+ }
+
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
+ }
+
+ CallableCustomStaticMethodPointerRet(R (*p_method)(P...)) {
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
+ }
+};
+
+template <class R, class... P>
+Callable create_custom_callable_static_function_pointer(
+#ifdef DEBUG_METHODS_ENABLED
+ const char *p_func_text,
+#endif
+ R (*p_method)(P...)) {
+ typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP; // Messes with memnew otherwise.
+ CCMP *ccmp = memnew(CCMP(p_method));
+#ifdef DEBUG_METHODS_ENABLED
+ ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
+#endif
+ return Callable(ccmp);
+}
+
+#ifdef DEBUG_METHODS_ENABLED
+#define callable_mp_static(M) create_custom_callable_static_function_pointer(#M, M)
+#else
+#define callable_mp_static(M) create_custom_callable_static_function_pointer(M)
+#endif
+
#endif // CALLABLE_METHOD_POINTER_H
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index d19cbf2642..f61bd24efd 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -1390,7 +1390,7 @@ void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p
}
HashMap<StringName, HashMap<StringName, Variant>> ClassDB::default_values;
-RBSet<StringName> ClassDB::default_values_cached;
+HashSet<StringName> ClassDB::default_values_cached;
Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid) {
if (!default_values_cached.has(p_class)) {
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 67b71ab058..2448a86e33 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -38,6 +38,7 @@
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
#include "core/object/callable_method_pointer.h"
+#include "core/templates/hash_set.h"
#define DEFVAL(m_defval) (m_defval)
@@ -110,7 +111,7 @@ public:
#ifdef DEBUG_METHODS_ENABLED
List<StringName> constant_order;
List<StringName> method_order;
- RBSet<StringName> methods_in_properties;
+ HashSet<StringName> methods_in_properties;
List<MethodInfo> virtual_methods;
HashMap<StringName, MethodInfo> virtual_methods_map;
HashMap<StringName, Vector<Error>> method_error_values;
@@ -149,7 +150,7 @@ public:
static void _add_class2(const StringName &p_class, const StringName &p_inherits);
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
- static RBSet<StringName> default_values_cached;
+ static HashSet<StringName> default_values_cached;
// Native structs, used by binder
struct NativeStruct {
diff --git a/core/object/object.h b/core/object/object.h
index ca7b9965f1..988d261d77 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -37,9 +37,9 @@
#include "core/os/rw_lock.h"
#include "core/os/spin_lock.h"
#include "core/templates/hash_map.h"
+#include "core/templates/hash_set.h"
#include "core/templates/list.h"
#include "core/templates/rb_map.h"
-#include "core/templates/rb_set.h"
#include "core/templates/safe_refcount.h"
#include "core/templates/vmap.h"
#include "core/variant/callable_bind.h"
@@ -510,7 +510,7 @@ private:
#ifdef TOOLS_ENABLED
bool _edited = false;
uint32_t _edited_version = 0;
- RBSet<String> editor_section_folding;
+ HashSet<String> editor_section_folding;
#endif
ScriptInstance *script_instance = nullptr;
Variant script; // Reference does not exist yet, store it in a Variant.
@@ -815,7 +815,7 @@ public:
#ifdef TOOLS_ENABLED
void editor_set_section_unfold(const String &p_section, bool p_unfolded);
bool editor_is_section_unfolded(const String &p_section);
- const RBSet<String> &editor_get_section_folding() const { return editor_section_folding; }
+ const HashSet<String> &editor_get_section_folding() const { return editor_section_folding; }
void editor_clear_section_folding() { editor_section_folding.clear(); }
#endif
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 1546d52fd2..66c9a80193 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -475,7 +475,7 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
}
void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const HashMap<StringName, Variant> &p_values) {
- RBSet<StringName> new_values;
+ HashSet<StringName> new_values;
for (const PropertyInfo &E : p_properties) {
StringName n = E.name;
new_values.insert(n);
diff --git a/core/object/script_language.h b/core/object/script_language.h
index b1481a372e..0a8e79a24e 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -155,7 +155,7 @@ public:
virtual int get_member_line(const StringName &p_member) const { return -1; }
virtual void get_constants(HashMap<StringName, Variant> *p_constants) {}
- virtual void get_members(RBSet<StringName> *p_constants) {}
+ virtual void get_members(HashSet<StringName> *p_constants) {}
virtual bool is_placeholder_fallback_enabled() const { return false; }
@@ -283,7 +283,7 @@ public:
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { return Ref<Script>(); }
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) { return Vector<ScriptTemplate>(); }
virtual bool is_using_templates() { return false; }
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const = 0;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
virtual Script *create_script() const = 0;
virtual bool has_named_classes() const = 0;
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 5ffa6c5a70..406a431a11 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -163,7 +163,7 @@ public:
}
}
GDVIRTUAL0RC(TypedArray<StringName>, _get_members)
- virtual void get_members(RBSet<StringName> *p_members) override {
+ virtual void get_members(HashSet<StringName> *p_members) override {
TypedArray<StringName> members;
GDVIRTUAL_REQUIRED_CALL(_get_members, members);
for (int i = 0; i < members.size(); i++) {
@@ -282,7 +282,7 @@ public:
EXBIND0R(bool, is_using_templates)
GDVIRTUAL6RC(Dictionary, _validate, const String &, const String &, bool, bool, bool, bool)
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override {
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override {
Dictionary ret;
GDVIRTUAL_REQUIRED_CALL(_validate, p_script, p_path, r_functions != nullptr, r_errors != nullptr, r_warnings != nullptr, r_safe_lines != nullptr, ret);
if (!ret.has("valid")) {
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 4f7095b0fc..327f1c95f2 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -413,19 +413,29 @@ bool OS::has_feature(const String &p_feature) {
if (sizeof(void *) == 4 && p_feature == "32") {
return true;
}
-#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__)
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
if (p_feature == "x86_64") {
return true;
}
-#elif (defined(__i386) || defined(__i386__))
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+ if (p_feature == "x86_32") {
+ return true;
+ }
+#endif
if (p_feature == "x86") {
return true;
}
-#elif defined(__aarch64__)
+#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
+#if defined(__aarch64__) || defined(_M_ARM64)
if (p_feature == "arm64") {
return true;
}
-#elif defined(__arm__)
+#elif defined(__arm__) || defined(_M_ARM)
+ if (p_feature == "arm32") {
+ return true;
+ }
+#endif
#if defined(__ARM_ARCH_7A__)
if (p_feature == "armv7a" || p_feature == "armv7") {
return true;
@@ -457,6 +467,19 @@ bool OS::has_feature(const String &p_feature) {
if (p_feature == "ppc") {
return true;
}
+#elif defined(__wasm__)
+#if defined(__wasm64__)
+ if (p_feature == "wasm64") {
+ return true;
+ }
+#elif defined(__wasm32__)
+ if (p_feature == "wasm32") {
+ return true;
+ }
+#endif
+ if (p_feature == "wasm") {
+ return true;
+ }
#endif
if (_check_internal_feature_support(p_feature)) {
diff --git a/core/string/translation.h b/core/string/translation.h
index f58f6f91a2..20c6ebd5a5 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -74,7 +74,7 @@ class TranslationServer : public Object {
String locale = "en";
String fallback;
- RBSet<Ref<Translation>> translations;
+ HashSet<Ref<Translation>> translations;
Ref<Translation> tool_translation;
Ref<Translation> doc_translation;
@@ -111,7 +111,7 @@ class TranslationServer : public Object {
String name;
String script;
String default_country;
- RBSet<String> supported_countries;
+ HashSet<String> supported_countries;
};
static Vector<LocaleScriptInfo> locale_script_info;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index f6ad0fe3b0..d189f3224b 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -2039,7 +2039,7 @@ int64_t String::hex_to_int() const {
}
// Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error
bool overflow = ((hex > INT64_MAX / 16) && (sign == 1 || (sign == -1 && hex != (INT64_MAX >> 4) + 1))) || (sign == -1 && hex == (INT64_MAX >> 4) + 1 && c > '0');
- ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as a 64-bit signed integer, since the value is " + (sign == 1 ? "too large." : "too small."));
hex *= 16;
hex += n;
s++;
@@ -2078,7 +2078,7 @@ int64_t String::bin_to_int() const {
}
// Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error
bool overflow = ((binary > INT64_MAX / 2) && (sign == 1 || (sign == -1 && binary != (INT64_MAX >> 1) + 1))) || (sign == -1 && binary == (INT64_MAX >> 1) + 1 && c > '0');
- ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as a 64-bit signed integer, since the value is " + (sign == 1 ? "too large." : "too small."));
binary *= 2;
binary += n;
s++;
@@ -2101,7 +2101,7 @@ int64_t String::to_int() const {
char32_t c = operator[](i);
if (is_digit(c)) {
bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
- ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as a 64-bit signed integer, since the value is " + (sign == 1 ? "too large." : "too small."));
integer *= 10;
integer += c - '0';
@@ -2130,7 +2130,7 @@ int64_t String::to_int(const char *p_str, int p_len) {
char c = p_str[i];
if (is_digit(c)) {
bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
- ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as a 64-bit signed integer, since the value is " + (sign == 1 ? "too large." : "too small."));
integer *= 10;
integer += c - '0';
@@ -2161,7 +2161,7 @@ int64_t String::to_int(const wchar_t *p_str, int p_len) {
wchar_t c = p_str[i];
if (is_digit(c)) {
bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
- ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as a 64-bit signed integer, since the value is " + (sign == 1 ? "too large." : "too small."));
integer *= 10;
integer += c - '0';
@@ -2483,7 +2483,7 @@ int64_t String::to_int(const char32_t *p_str, int p_len, bool p_clamp) {
return INT64_MIN;
}
} else {
- ERR_FAIL_V_MSG(sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + number + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ ERR_FAIL_V_MSG(sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + number + " as a 64-bit signed integer, since the value is " + (sign == 1 ? "too large." : "too small."));
}
}
integer *= 10;
@@ -3712,18 +3712,15 @@ String String::uri_encode() const {
const CharString temp = utf8();
String res;
for (int i = 0; i < temp.length(); ++i) {
- char ord = temp[i];
+ uint8_t ord = temp[i];
if (ord == '.' || ord == '-' || ord == '~' || is_ascii_identifier_char(ord)) {
res += ord;
} else {
- char h_Val[3];
-#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(h_Val, 3, "%02hhX", ord);
-#else
- sprintf(h_Val, "%02hhX", ord);
-#endif
- res += "%";
- res += h_Val;
+ char p[4] = { '%', 0, 0, 0 };
+ static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ p[1] = hex[ord >> 4];
+ p[2] = hex[ord & 0xF];
+ res += p;
}
}
return res;
diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h
index 59ac4cdaa1..d928bd7a82 100644
--- a/core/templates/bin_sorted_array.h
+++ b/core/templates/bin_sorted_array.h
@@ -61,7 +61,7 @@ public:
}
uint64_t move(uint64_t p_idx, uint64_t p_bin) {
- ERR_FAIL_COND_V(p_idx >= array.size(), -1);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_idx, array.size(), -1);
uint64_t current_bin = bin_limits.size() - 1;
while (p_idx > bin_limits[current_bin]) {
@@ -113,7 +113,7 @@ public:
}
void remove_at(uint64_t p_idx) {
- ERR_FAIL_COND(p_idx >= array.size());
+ ERR_FAIL_UNSIGNED_INDEX(p_idx, array.size());
uint64_t new_idx = move(p_idx, 0);
uint64_t swap_idx = array.size() - 1;
diff --git a/core/templates/hash_set.h b/core/templates/hash_set.h
new file mode 100644
index 0000000000..2318067dcc
--- /dev/null
+++ b/core/templates/hash_set.h
@@ -0,0 +1,473 @@
+/*************************************************************************/
+/* hash_set.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef HASH_SET_H
+#define HASH_SET_H
+
+#include "core/math/math_funcs.h"
+#include "core/os/memory.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/hashfuncs.h"
+#include "core/templates/paged_allocator.h"
+
+/**
+ * Implementation of Set using a bidi indexed hash map.
+ * Use RBSet instead of this only if the following conditions are met:
+ *
+ * - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
+ * - Iteration order does matter (via operator<)
+ *
+ */
+
+template <class TKey,
+ class Hasher = HashMapHasherDefault,
+ class Comparator = HashMapComparatorDefault<TKey>>
+class HashSet {
+public:
+ static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
+ static constexpr float MAX_OCCUPANCY = 0.75;
+ static constexpr uint32_t EMPTY_HASH = 0;
+
+private:
+ TKey *keys = nullptr;
+ uint32_t *hash_to_key = nullptr;
+ uint32_t *key_to_hash = nullptr;
+ uint32_t *hashes = nullptr;
+
+ uint32_t capacity_index = 0;
+ uint32_t num_elements = 0;
+
+ _FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
+ uint32_t hash = Hasher::hash(p_key);
+
+ if (unlikely(hash == EMPTY_HASH)) {
+ hash = EMPTY_HASH + 1;
+ }
+
+ return hash;
+ }
+
+ _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
+ uint32_t original_pos = p_hash % p_capacity;
+ return (p_pos - original_pos + p_capacity) % p_capacity;
+ }
+
+ bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
+ if (keys == nullptr) {
+ return false; // Failed lookups, no elements
+ }
+
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+ uint32_t hash = _hash(p_key);
+ uint32_t pos = hash % capacity;
+ uint32_t distance = 0;
+
+ while (true) {
+ if (hashes[pos] == EMPTY_HASH) {
+ return false;
+ }
+
+ if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
+ return false;
+ }
+
+ if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
+ r_pos = hash_to_key[pos];
+ return true;
+ }
+
+ pos = (pos + 1) % capacity;
+ distance++;
+ }
+ }
+
+ uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+ uint32_t hash = p_hash;
+ uint32_t index = p_index;
+ uint32_t distance = 0;
+ uint32_t pos = hash % capacity;
+
+ while (true) {
+ if (hashes[pos] == EMPTY_HASH) {
+ hashes[pos] = hash;
+ key_to_hash[index] = pos;
+ hash_to_key[pos] = index;
+ return pos;
+ }
+
+ // Not an empty slot, let's check the probing length of the existing one.
+ uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
+ if (existing_probe_len < distance) {
+ key_to_hash[index] = pos;
+ SWAP(hash, hashes[pos]);
+ SWAP(index, hash_to_key[pos]);
+ distance = existing_probe_len;
+ }
+
+ pos = (pos + 1) % capacity;
+ distance++;
+ }
+ }
+
+ void _resize_and_rehash(uint32_t p_new_capacity_index) {
+ // Capacity can't be 0.
+ capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
+
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+
+ uint32_t *old_hashes = hashes;
+ uint32_t *old_key_to_hash = key_to_hash;
+
+ hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+ keys = reinterpret_cast<TKey *>(Memory::realloc_static(keys, sizeof(TKey) * capacity));
+ key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+ hash_to_key = reinterpret_cast<uint32_t *>(Memory::realloc_static(hash_to_key, sizeof(uint32_t) * capacity));
+
+ for (uint32_t i = 0; i < capacity; i++) {
+ hashes[i] = EMPTY_HASH;
+ }
+
+ for (uint32_t i = 0; i < num_elements; i++) {
+ uint32_t h = old_hashes[old_key_to_hash[i]];
+ _insert_with_hash(h, i);
+ }
+
+ Memory::free_static(old_hashes);
+ Memory::free_static(old_key_to_hash);
+ }
+
+ _FORCE_INLINE_ int32_t _insert(const TKey &p_key) {
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+ if (unlikely(keys == nullptr)) {
+ // Allocate on demand to save memory.
+
+ hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+ keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
+ key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+ hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+
+ for (uint32_t i = 0; i < capacity; i++) {
+ hashes[i] = EMPTY_HASH;
+ }
+ }
+
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
+
+ if (exists) {
+ return pos;
+ } else {
+ if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
+ ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, -1, "Hash table maximum capacity reached, aborting insertion.");
+ _resize_and_rehash(capacity_index + 1);
+ }
+
+ uint32_t hash = _hash(p_key);
+ memnew_placement(&keys[num_elements], TKey(p_key));
+ _insert_with_hash(hash, num_elements);
+ num_elements++;
+ return num_elements - 1;
+ }
+ }
+
+ void _init_from(const HashSet &p_other) {
+ capacity_index = p_other.capacity_index;
+ num_elements = p_other.num_elements;
+
+ if (p_other.num_elements == 0) {
+ return;
+ }
+
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+
+ hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+ keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
+ key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+ hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+
+ for (uint32_t i = 0; i < num_elements; i++) {
+ memnew_placement(&keys[i], TKey(p_other.keys[i]));
+ key_to_hash[i] = p_other.key_to_hash[i];
+ }
+
+ for (uint32_t i = 0; i < capacity; i++) {
+ hashes[i] = p_other.hashes[i];
+ hash_to_key[i] = p_other.hash_to_key[i];
+ }
+ }
+
+public:
+ _FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
+ _FORCE_INLINE_ uint32_t size() const { return num_elements; }
+
+ /* Standard Godot Container API */
+
+ bool is_empty() const {
+ return num_elements == 0;
+ }
+
+ void clear() {
+ if (keys == nullptr) {
+ return;
+ }
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+ for (uint32_t i = 0; i < capacity; i++) {
+ hashes[i] = EMPTY_HASH;
+ }
+ for (uint32_t i = 0; i < num_elements; i++) {
+ keys[i].~TKey();
+ }
+
+ num_elements = 0;
+ }
+
+ _FORCE_INLINE_ bool has(const TKey &p_key) const {
+ uint32_t _pos = 0;
+ return _lookup_pos(p_key, _pos);
+ }
+
+ bool erase(const TKey &p_key) {
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
+
+ if (!exists) {
+ return false;
+ }
+
+ uint32_t key_pos = pos;
+ pos = key_to_hash[pos]; //make hash pos
+
+ uint32_t capacity = hash_table_size_primes[capacity_index];
+ uint32_t next_pos = (pos + 1) % capacity;
+ while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
+ uint32_t kpos = hash_to_key[pos];
+ uint32_t kpos_next = hash_to_key[next_pos];
+ SWAP(key_to_hash[kpos], key_to_hash[kpos_next]);
+ SWAP(hashes[next_pos], hashes[pos]);
+ SWAP(hash_to_key[next_pos], hash_to_key[pos]);
+
+ pos = next_pos;
+ next_pos = (pos + 1) % capacity;
+ }
+
+ hashes[pos] = EMPTY_HASH;
+ keys[key_pos].~TKey();
+ num_elements--;
+ if (key_pos < num_elements) {
+ // Not the last key, move the last one here to keep keys lineal
+ memnew_placement(&keys[key_pos], TKey(keys[num_elements]));
+ keys[num_elements].~TKey();
+ key_to_hash[key_pos] = key_to_hash[num_elements];
+ hash_to_key[key_to_hash[num_elements]] = key_pos;
+ }
+
+ return true;
+ }
+
+ // Reserves space for a number of elements, useful to avoid many resizes and rehashes.
+ // If adding a known (possibly large) number of elements at once, must be larger than old capacity.
+ void reserve(uint32_t p_new_capacity) {
+ uint32_t new_index = capacity_index;
+
+ while (hash_table_size_primes[new_index] < p_new_capacity) {
+ ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
+ new_index++;
+ }
+
+ if (new_index == capacity_index) {
+ return;
+ }
+
+ if (keys == nullptr) {
+ capacity_index = new_index;
+ return; // Unallocated yet.
+ }
+ _resize_and_rehash(new_index);
+ }
+
+ /** Iterator API **/
+
+ struct Iterator {
+ _FORCE_INLINE_ const TKey &operator*() const {
+ return keys[index];
+ }
+ _FORCE_INLINE_ const TKey *operator->() const {
+ return &keys[index];
+ }
+ _FORCE_INLINE_ Iterator &operator++() {
+ index++;
+ if (index >= (int32_t)num_keys) {
+ index = -1;
+ keys = nullptr;
+ num_keys = 0;
+ }
+ return *this;
+ }
+ _FORCE_INLINE_ Iterator &operator--() {
+ index--;
+ if (index < 0) {
+ index = -1;
+ keys = nullptr;
+ num_keys = 0;
+ }
+ return *this;
+ }
+
+ _FORCE_INLINE_ bool operator==(const Iterator &b) const { return keys == b.keys && index == b.index; }
+ _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return keys != b.keys || index != b.index; }
+
+ _FORCE_INLINE_ explicit operator bool() const {
+ return keys != nullptr;
+ }
+
+ _FORCE_INLINE_ Iterator(const TKey *p_keys, uint32_t p_num_keys, int32_t p_index = -1) {
+ keys = p_keys;
+ num_keys = p_num_keys;
+ index = p_index;
+ }
+ _FORCE_INLINE_ Iterator() {}
+ _FORCE_INLINE_ Iterator(const Iterator &p_it) {
+ keys = p_it.keys;
+ num_keys = p_it.num_keys;
+ index = p_it.index;
+ }
+ _FORCE_INLINE_ void operator=(const Iterator &p_it) {
+ keys = p_it.keys;
+ num_keys = p_it.num_keys;
+ index = p_it.index;
+ }
+
+ private:
+ const TKey *keys = nullptr;
+ uint32_t num_keys = 0;
+ int32_t index = -1;
+ };
+
+ _FORCE_INLINE_ Iterator begin() const {
+ return num_elements ? Iterator(keys, num_elements, 0) : Iterator();
+ }
+ _FORCE_INLINE_ Iterator end() const {
+ return Iterator();
+ }
+ _FORCE_INLINE_ Iterator last() const {
+ if (num_elements == 0) {
+ return Iterator();
+ }
+ return Iterator(keys, num_elements, num_elements - 1);
+ }
+
+ _FORCE_INLINE_ Iterator find(const TKey &p_key) const {
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
+ if (!exists) {
+ return end();
+ }
+ return Iterator(keys, num_elements, pos);
+ }
+
+ _FORCE_INLINE_ void remove(const Iterator &p_iter) {
+ if (p_iter) {
+ erase(*p_iter);
+ }
+ }
+
+ /* Insert */
+
+ Iterator insert(const TKey &p_key) {
+ uint32_t pos = _insert(p_key);
+ return Iterator(keys, num_elements, pos);
+ }
+
+ /* Constructors */
+
+ HashSet(const HashSet &p_other) {
+ _init_from(p_other);
+ }
+
+ void operator=(const HashSet &p_other) {
+ if (this == &p_other) {
+ return; // Ignore self assignment.
+ }
+
+ clear();
+
+ if (keys != nullptr) {
+ Memory::free_static(keys);
+ Memory::free_static(key_to_hash);
+ Memory::free_static(hash_to_key);
+ Memory::free_static(hashes);
+ keys = nullptr;
+ hashes = nullptr;
+ hash_to_key = nullptr;
+ key_to_hash = nullptr;
+ }
+
+ _init_from(p_other);
+ }
+
+ HashSet(uint32_t p_initial_capacity) {
+ // Capacity can't be 0.
+ capacity_index = 0;
+ reserve(p_initial_capacity);
+ }
+ HashSet() {
+ capacity_index = MIN_CAPACITY_INDEX;
+ }
+
+ void reset() {
+ clear();
+
+ if (keys != nullptr) {
+ Memory::free_static(keys);
+ Memory::free_static(key_to_hash);
+ Memory::free_static(hash_to_key);
+ Memory::free_static(hashes);
+ keys = nullptr;
+ hashes = nullptr;
+ hash_to_key = nullptr;
+ key_to_hash = nullptr;
+ }
+ capacity_index = MIN_CAPACITY_INDEX;
+ }
+
+ ~HashSet() {
+ clear();
+
+ if (keys != nullptr) {
+ Memory::free_static(keys);
+ Memory::free_static(key_to_hash);
+ Memory::free_static(hash_to_key);
+ Memory::free_static(hashes);
+ }
+ }
+};
+
+#endif // HASH_SET_H
diff --git a/core/templates/rb_set.h b/core/templates/rb_set.h
index 2de816769c..226ea979c9 100644
--- a/core/templates/rb_set.h
+++ b/core/templates/rb_set.h
@@ -99,6 +99,7 @@ public:
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+ explicit operator bool() const { return E != nullptr; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
@@ -128,6 +129,8 @@ public:
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+ explicit operator bool() const { return E != nullptr; }
+
private:
const Element *E = nullptr;
};
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index d26977380e..9c74b41818 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -34,9 +34,9 @@
#include "core/os/memory.h"
#include "core/os/spin_lock.h"
#include "core/string/print_string.h"
+#include "core/templates/hash_set.h"
#include "core/templates/list.h"
#include "core/templates/oa_hash_map.h"
-#include "core/templates/rb_set.h"
#include "core/templates/rid.h"
#include "core/templates/safe_refcount.h"
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index e69bd88413..2b4e777865 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3102,6 +3102,10 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
return *reinterpret_cast<const String *>(_data._mem) == *reinterpret_cast<const String *>(p_variant._data._mem);
} break;
+ case STRING_NAME: {
+ return *reinterpret_cast<const StringName *>(_data._mem) == *reinterpret_cast<const StringName *>(p_variant._data._mem);
+ } break;
+
case VECTOR2: {
const Vector2 *l = reinterpret_cast<const Vector2 *>(_data._mem);
const Vector2 *r = reinterpret_cast<const Vector2 *>(p_variant._data._mem);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 2e77a4b2f8..3fe5ead347 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1472,6 +1472,10 @@ static void _register_variant_builtin_methods() {
bind_static_method(String, chr, sarray("char"), varray());
bind_static_method(String, humanize_size, sarray("size"), varray());
+ /* StringName */
+
+ bind_method(StringName, hash, sarray(), varray());
+
/* Vector2 */
bind_method(Vector2, angle, sarray(), varray());
@@ -1684,6 +1688,7 @@ static void _register_variant_builtin_methods() {
bind_method(NodePath, get_name_count, sarray(), varray());
bind_method(NodePath, get_name, sarray("idx"), varray());
bind_method(NodePath, get_subname_count, sarray(), varray());
+ bind_method(NodePath, hash, sarray(), varray());
bind_method(NodePath, get_subname, sarray("idx"), varray());
bind_method(NodePath, get_concatenated_subnames, sarray(), varray());
bind_method(NodePath, get_as_property_path, sarray(), varray());