diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 79fa6a08952..2aedbdf45f2 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1091,7 +1091,7 @@ bool ProjectSettings::has_custom_feature(const String &p_feature) const { return custom_features.has(p_feature); } -OrderedHashMap ProjectSettings::get_autoload_list() const { +const HashMap &ProjectSettings::get_autoload_list() const { return autoloads; } @@ -1135,13 +1135,13 @@ void ProjectSettings::_bind_methods() { void ProjectSettings::_add_builtin_input_map() { if (InputMap::get_singleton()) { - OrderedHashMap>> builtins = InputMap::get_singleton()->get_builtins(); + HashMap>> builtins = InputMap::get_singleton()->get_builtins(); - for (OrderedHashMap>>::Element E = builtins.front(); E; E = E.next()) { + for (KeyValue>> &E : builtins) { Array events; // Convert list of input events into array - for (List>::Element *I = E.get().front(); I; I = I->next()) { + for (List>::Element *I = E.value.front(); I; I = I->next()) { events.push_back(I->get()); } @@ -1149,7 +1149,7 @@ void ProjectSettings::_add_builtin_input_map() { action["deadzone"] = Variant(0.5f); action["events"] = events; - String action_name = "input/" + E.key(); + String action_name = "input/" + E.key; GLOBAL_DEF(action_name, action); input_presets.push_back(action_name); } diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 614a11f7262..8655526edd7 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -33,7 +33,7 @@ #include "core/object/class_db.h" #include "core/os/thread_safe.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" #include "core/templates/set.h" class ProjectSettings : public Object { @@ -94,7 +94,7 @@ protected: Set custom_features; Map feature_overrides; - OrderedHashMap autoloads; + HashMap autoloads; String project_data_dir_name; @@ -181,7 +181,7 @@ public: bool has_custom_feature(const String &p_feature) const; - OrderedHashMap get_autoload_list() const; + const HashMap &get_autoload_list() const; void add_autoload(const AutoloadInfo &p_autoload); void remove_autoload(const StringName &p_autoload); bool has_autoload(const StringName &p_autoload) const; diff --git a/core/input/input.cpp b/core/input/input.cpp index 40cea2cd800..3a2e50a6740 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -636,21 +636,21 @@ void Input::_parse_input_event_impl(const Ref &p_event, bool p_is_em } } - for (OrderedHashMap::ConstElement E = InputMap::get_singleton()->get_action_map().front(); E; E = E.next()) { - if (InputMap::get_singleton()->event_is_action(p_event, E.key())) { + for (const KeyValue &E : InputMap::get_singleton()->get_action_map()) { + if (InputMap::get_singleton()->event_is_action(p_event, E.key)) { // If not echo and action pressed state has changed - if (!p_event->is_echo() && is_action_pressed(E.key(), false) != p_event->is_action_pressed(E.key())) { + if (!p_event->is_echo() && is_action_pressed(E.key, false) != p_event->is_action_pressed(E.key)) { Action action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); action.process_frame = Engine::get_singleton()->get_process_frames(); - action.pressed = p_event->is_action_pressed(E.key()); + action.pressed = p_event->is_action_pressed(E.key); action.strength = 0.0f; action.raw_strength = 0.0f; - action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key(), true); - action_state[E.key()] = action; + action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true); + action_state[E.key] = action; } - action_state[E.key()].strength = p_event->get_action_strength(E.key()); - action_state[E.key()].raw_strength = p_event->get_action_raw_strength(E.key()); + action_state[E.key].strength = p_event->get_action_strength(E.key); + action_state[E.key].raw_strength = p_event->get_action_raw_strength(E.key); } } diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index ab94c00999c..51c1cf9608b 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -119,8 +119,8 @@ List InputMap::get_actions() const { return actions; } - for (OrderedHashMap::Element E = input_map.front(); E; E = E.next()) { - actions.push_back(E.key()); + for (const KeyValue &E : input_map) { + actions.push_back(E.key); } return actions; @@ -203,12 +203,12 @@ Array InputMap::_action_get_events(const StringName &p_action) { } const List> *InputMap::action_get_events(const StringName &p_action) { - const OrderedHashMap::Element E = input_map.find(p_action); + HashMap::Iterator E = input_map.find(p_action); if (!E) { return nullptr; } - return &E.get().inputs; + return &E->value.inputs; } bool InputMap::event_is_action(const Ref &p_event, const StringName &p_action, bool p_exact_match) const { @@ -216,7 +216,7 @@ bool InputMap::event_is_action(const Ref &p_event, const StringName } bool InputMap::event_get_action_status(const Ref &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const { - OrderedHashMap::Element E = input_map.find(p_action); + HashMap::Iterator E = input_map.find(p_action); ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action)); Ref input_event_action = p_event; @@ -235,11 +235,11 @@ bool InputMap::event_get_action_status(const Ref &p_event, const Str return input_event_action->get_action() == p_action; } - List>::Element *event = _find_event(E.get(), p_event, p_exact_match, r_pressed, r_strength, r_raw_strength); + List>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength); return event != nullptr; } -const OrderedHashMap &InputMap::get_action_map() const { +const HashMap &InputMap::get_action_map() const { return input_map; } @@ -360,7 +360,7 @@ String InputMap::get_builtin_display_name(const String &p_name) const { return p_name; } -const OrderedHashMap>> &InputMap::get_builtins() { +const HashMap>> &InputMap::get_builtins() { // Return cache if it has already been built. if (default_builtin_cache.size()) { return default_builtin_cache; @@ -686,19 +686,19 @@ const OrderedHashMap>> &InputMap::get_builtins() { return default_builtin_cache; } -const OrderedHashMap>> &InputMap::get_builtins_with_feature_overrides_applied() { +const HashMap>> &InputMap::get_builtins_with_feature_overrides_applied() { if (default_builtin_with_overrides_cache.size() > 0) { return default_builtin_with_overrides_cache; } - OrderedHashMap>> builtins = get_builtins(); + HashMap>> builtins = get_builtins(); // Get a list of all built in inputs which are valid overrides for the OS // Key = builtin name (e.g. ui_accept) // Value = override/feature names (e.g. macos, if it was defined as "ui_accept.macos" and the platform supports that feature) Map> builtins_with_overrides; - for (OrderedHashMap>>::Element E = builtins.front(); E; E = E.next()) { - String fullname = E.key(); + for (const KeyValue>> &E : builtins) { + String fullname = E.key; Vector split = fullname.split("."); String name = split[0]; @@ -709,8 +709,8 @@ const OrderedHashMap>> &InputMap::get_builtins_with } } - for (OrderedHashMap>>::Element E = builtins.front(); E; E = E.next()) { - String fullname = E.key(); + for (const KeyValue>> &E : builtins) { + String fullname = E.key; Vector split = fullname.split("."); String name = split[0]; @@ -726,22 +726,22 @@ const OrderedHashMap>> &InputMap::get_builtins_with continue; } - default_builtin_with_overrides_cache.insert(name, E.value()); + default_builtin_with_overrides_cache.insert(name, E.value); } return default_builtin_with_overrides_cache; } void InputMap::load_default() { - OrderedHashMap>> builtins = get_builtins_with_feature_overrides_applied(); + HashMap>> builtins = get_builtins_with_feature_overrides_applied(); - for (OrderedHashMap>>::Element E = builtins.front(); E; E = E.next()) { - String name = E.key(); + for (const KeyValue>> &E : builtins) { + String name = E.key; add_action(name); - List> inputs = E.get(); - for (List>::Element *I = inputs.front(); I; I = I->next()) { + const List> &inputs = E.value; + for (const List>::Element *I = inputs.front(); I; I = I->next()) { Ref iek = I->get(); // For the editor, only add keyboard actions. diff --git a/core/input/input_map.h b/core/input/input_map.h index 79b4d1038fc..2400a4a3f7e 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -34,7 +34,7 @@ #include "core/input/input_event.h" #include "core/object/class_db.h" #include "core/object/object.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" class InputMap : public Object { GDCLASS(InputMap, Object); @@ -54,9 +54,9 @@ public: private: static InputMap *singleton; - mutable OrderedHashMap input_map; - OrderedHashMap>> default_builtin_cache; - OrderedHashMap>> default_builtin_with_overrides_cache; + mutable HashMap input_map; + HashMap>> default_builtin_cache; + HashMap>> default_builtin_with_overrides_cache; List>::Element *_find_event(Action &p_action, const Ref &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const; @@ -85,7 +85,7 @@ public: bool event_is_action(const Ref &p_event, const StringName &p_action, bool p_exact_match = false) const; bool event_get_action_status(const Ref &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const; - const OrderedHashMap &get_action_map() const; + const HashMap &get_action_map() const; void load_from_project_settings(); void load_default(); @@ -93,8 +93,8 @@ public: String get_builtin_display_name(const String &p_name) const; // Use an Ordered Map so insertion order is preserved. We want the elements to be 'grouped' somewhat. - const OrderedHashMap>> &get_builtins(); - const OrderedHashMap>> &get_builtins_with_feature_overrides_applied(); + const HashMap>> &get_builtins(); + const HashMap>> &get_builtins_with_feature_overrides_applied(); InputMap(); ~InputMap(); diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index bc24cac9558..dd0191f43fa 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -73,7 +73,7 @@ void ConfigFile::set_value(const String &p_section, const String &p_key, const V } else { if (!values.has(p_section)) { - values[p_section] = OrderedHashMap(); + values[p_section] = HashMap(); } values[p_section][p_key] = p_value; @@ -102,16 +102,16 @@ bool ConfigFile::has_section_key(const String &p_section, const String &p_key) c } void ConfigFile::get_sections(List *r_sections) const { - for (OrderedHashMap>::ConstElement E = values.front(); E; E = E.next()) { - r_sections->push_back(E.key()); + for (const KeyValue> &E : values) { + r_sections->push_back(E.key); } } void ConfigFile::get_section_keys(const String &p_section, List *r_keys) const { ERR_FAIL_COND_MSG(!values.has(p_section), vformat("Cannot get keys from nonexistent section \"%s\".", p_section)); - for (OrderedHashMap::ConstElement E = values[p_section].front(); E; E = E.next()) { - r_keys->push_back(E.key()); + for (const KeyValue &E : values[p_section]) { + r_keys->push_back(E.key); } } @@ -174,18 +174,21 @@ Error ConfigFile::save_encrypted_pass(const String &p_path, const String &p_pass } Error ConfigFile::_internal_save(Ref file) { - for (OrderedHashMap>::Element E = values.front(); E; E = E.next()) { - if (E != values.front()) { + bool first = true; + for (const KeyValue> &E : values) { + if (first) { + first = false; + } else { file->store_string("\n"); } - if (!E.key().is_empty()) { - file->store_string("[" + E.key() + "]\n\n"); + if (!E.key.is_empty()) { + file->store_string("[" + E.key + "]\n\n"); } - for (OrderedHashMap::Element F = E.get().front(); F; F = F.next()) { + for (const KeyValue &F : E.value) { String vstr; - VariantWriter::write_to_string(F.get(), vstr); - file->store_string(F.key().property_name_encode() + "=" + vstr + "\n"); + VariantWriter::write_to_string(F.value, vstr); + file->store_string(F.key.property_name_encode() + "=" + vstr + "\n"); } } diff --git a/core/io/config_file.h b/core/io/config_file.h index 7a52b0e16ac..3b07ec52f57 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -33,13 +33,13 @@ #include "core/io/file_access.h" #include "core/object/ref_counted.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" #include "core/variant/variant_parser.h" class ConfigFile : public RefCounted { GDCLASS(ConfigFile, RefCounted); - OrderedHashMap> values; + HashMap> values; PackedStringArray _get_sections() const; PackedStringArray _get_section_keys(const String &p_section) const; diff --git a/core/io/missing_resource.cpp b/core/io/missing_resource.cpp index 7aae6c6f0ad..29814cdeb3b 100644 --- a/core/io/missing_resource.cpp +++ b/core/io/missing_resource.cpp @@ -53,8 +53,8 @@ bool MissingResource::_get(const StringName &p_name, Variant &r_ret) const { } void MissingResource::_get_property_list(List *p_list) const { - for (OrderedHashMap::ConstElement E = properties.front(); E; E = E.next()) { - p_list->push_back(PropertyInfo(E.value().get_type(), E.key())); + for (const KeyValue &E : properties) { + p_list->push_back(PropertyInfo(E.value.get_type(), E.key)); } } diff --git a/core/io/missing_resource.h b/core/io/missing_resource.h index e87efe1a987..6536a4119bd 100644 --- a/core/io/missing_resource.h +++ b/core/io/missing_resource.h @@ -38,7 +38,7 @@ class MissingResource : public Resource { GDCLASS(MissingResource, Resource) - OrderedHashMap properties; + HashMap properties; String original_class; bool recording_properties = false; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index e6535c67a40..e81382b72ed 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -478,10 +478,8 @@ void ResourceCache::clear() { if (resources.size()) { ERR_PRINT("Resources still in use at exit (run with --verbose for details)."); if (OS::get_singleton()->is_stdout_verbose()) { - const String *K = nullptr; - while ((K = resources.next(K))) { - Resource *r = resources[*K]; - print_line(vformat("Resource still in use: %s (%s)", *K, r->get_class())); + for (const KeyValue &E : resources) { + print_line(vformat("Resource still in use: %s (%s)", E.key, E.value->get_class())); } } } @@ -516,10 +514,8 @@ Resource *ResourceCache::get(const String &p_path) { void ResourceCache::get_cached_resources(List> *p_resources) { lock.read_lock(); - const String *K = nullptr; - while ((K = resources.next(K))) { - Resource *r = resources[*K]; - p_resources->push_back(Ref(r)); + for (KeyValue &E : resources) { + p_resources->push_back(Ref(E.value)); } lock.read_unlock(); } @@ -544,9 +540,8 @@ void ResourceCache::dump(const char *p_file, bool p_short) { ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file at path '" + String::utf8(p_file) + "'."); } - const String *K = nullptr; - while ((K = resources.next(K))) { - Resource *r = resources[*K]; + for (KeyValue &E : resources) { + Resource *r = E.value; if (!type_count.has(r->get_class())) { type_count[r->get_class()] = 0; diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 515b7c710e2..fc324a26da9 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -149,12 +149,12 @@ Error ResourceUID::save_to_cache() { cache_entries = 0; - for (OrderedHashMap::Element E = unique_ids.front(); E; E = E.next()) { - f->store_64(E.key()); - uint32_t s = E.get().cs.length(); + for (KeyValue &E : unique_ids) { + f->store_64(E.key); + uint32_t s = E.value.cs.length(); f->store_32(s); - f->store_buffer((const uint8_t *)E.get().cs.ptr(), s); - E.get().saved_to_cache = true; + f->store_buffer((const uint8_t *)E.value.cs.ptr(), s); + E.value.saved_to_cache = true; cache_entries++; } @@ -202,8 +202,8 @@ Error ResourceUID::update_cache() { MutexLock l(mutex); Ref f; - for (OrderedHashMap::Element E = unique_ids.front(); E; E = E.next()) { - if (!E.get().saved_to_cache) { + for (KeyValue &E : unique_ids) { + if (!E.value.saved_to_cache) { if (f.is_null()) { f = FileAccess::open(get_cache_file(), FileAccess::READ_WRITE); //append if (f.is_null()) { @@ -211,11 +211,11 @@ Error ResourceUID::update_cache() { } f->seek_end(); } - f->store_64(E.key()); - uint32_t s = E.get().cs.length(); + f->store_64(E.key); + uint32_t s = E.value.cs.length(); f->store_32(s); - f->store_buffer((const uint8_t *)E.get().cs.ptr(), s); - E.get().saved_to_cache = true; + f->store_buffer((const uint8_t *)E.value.cs.ptr(), s); + E.value.saved_to_cache = true; cache_entries++; } } diff --git a/core/io/resource_uid.h b/core/io/resource_uid.h index 0b7ffdf6d0c..da42553cf58 100644 --- a/core/io/resource_uid.h +++ b/core/io/resource_uid.h @@ -33,7 +33,7 @@ #include "core/object/ref_counted.h" #include "core/string/string_name.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" class ResourceUID : public Object { GDCLASS(ResourceUID, Object) @@ -53,7 +53,7 @@ private: bool saved_to_cache = false; }; - OrderedHashMap unique_ids; //unique IDs and utf8 paths (less memory used) + HashMap unique_ids; //unique IDs and utf8 paths (less memory used) static ResourceUID *singleton; uint32_t cache_entries = 0; diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 593f27b7cfd..d0fcde832bf 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -90,10 +90,8 @@ bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inh void ClassDB::get_class_list(List *p_classes) { OBJTYPE_RLOCK; - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - p_classes->push_back(*k); + for (const KeyValue &E : classes) { + p_classes->push_back(E.key); } p_classes->sort(); @@ -102,11 +100,9 @@ void ClassDB::get_class_list(List *p_classes) { void ClassDB::get_inheriters_from_class(const StringName &p_class, List *p_classes) { OBJTYPE_RLOCK; - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - if (*k != p_class && _is_parent_class(*k, p_class)) { - p_classes->push_back(*k); + for (const KeyValue &E : classes) { + if (E.key != p_class && _is_parent_class(E.key, p_class)) { + p_classes->push_back(E.key); } } } @@ -114,11 +110,9 @@ void ClassDB::get_inheriters_from_class(const StringName &p_class, List *p_classes) { OBJTYPE_RLOCK; - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - if (*k != p_class && _get_parent_class(*k) == p_class) { - p_classes->push_back(*k); + for (const KeyValue &E : classes) { + if (E.key != p_class && _get_parent_class(E.key) == p_class) { + p_classes->push_back(E.key); } } } @@ -172,17 +166,12 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); - List names; + List class_list; + ClassDB::get_class_list(&class_list); + // Must be alphabetically sorted for hash to compute. + class_list.sort_custom(); - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - names.push_back(*k); - } - //must be alphabetically sorted for hash to compute - names.sort_custom(); - - for (const StringName &E : names) { + for (const StringName &E : class_list) { ClassInfo *t = classes.getptr(E); ERR_FAIL_COND_V_MSG(!t, 0, "Cannot get class '" + String(E) + "'."); if (t->api != p_api || !t->exposed) { @@ -195,10 +184,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { List snames; - k = nullptr; - - while ((k = t->method_map.next(k))) { - String name = k->operator String(); + for (const KeyValue &F : t->method_map) { + String name = F.key.operator String(); ERR_CONTINUE(name.is_empty()); @@ -206,7 +193,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { continue; // Ignore non-virtual methods that start with an underscore } - snames.push_back(*k); + snames.push_back(F.key); } snames.sort_custom(); @@ -241,10 +228,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { List snames; - k = nullptr; - - while ((k = t->constant_map.next(k))) { - snames.push_back(*k); + for (const KeyValue &F : t->constant_map) { + snames.push_back(F.key); } snames.sort_custom(); @@ -259,10 +244,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { List snames; - k = nullptr; - - while ((k = t->signal_map.next(k))) { - snames.push_back(*k); + for (const KeyValue &F : t->signal_map) { + snames.push_back(F.key); } snames.sort_custom(); @@ -280,10 +263,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { List snames; - k = nullptr; - - while ((k = t->property_setget.next(k))) { - snames.push_back(*k); + for (const KeyValue &F : t->property_setget) { + snames.push_back(F.key); } snames.sort_custom(); @@ -474,10 +455,8 @@ void ClassDB::get_method_list(const StringName &p_class, List *p_met #else - const StringName *K = nullptr; - - while ((K = type->method_map.next(K))) { - MethodBind *m = type->method_map[*K]; + for (KeyValue &E : type->method_map) { + MethodBind *m = E.value; MethodInfo minfo = info_from_bind(m); p_methods->push_back(minfo); } @@ -603,10 +582,9 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List p_constants->push_back(E); } #else - const StringName *K = nullptr; - while ((K = type->constant_map.next(K))) { - p_constants->push_back(*K); + for (const KeyValue &E : type->constant_map) { + p_constants->push_back(E.key); } #endif @@ -667,12 +645,11 @@ StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const S ClassInfo *type = classes.getptr(p_class); while (type) { - const StringName *k = nullptr; - while ((k = type->enum_map.next(k))) { - List &constants_list = type->enum_map.get(*k); + for (KeyValue> &E : type->enum_map) { + List &constants_list = E.value; const List::Element *found = constants_list.find(p_name); if (found) { - return *k; + return E.key; } } @@ -692,9 +669,8 @@ void ClassDB::get_enum_list(const StringName &p_class, List *p_enums ClassInfo *type = classes.getptr(p_class); while (type) { - const StringName *k = nullptr; - while ((k = type->enum_map.next(k))) { - p_enums->push_back(*k); + for (KeyValue> &E : type->enum_map) { + p_enums->push_back(E.key); } if (p_no_inheritance) { @@ -800,9 +776,8 @@ void ClassDB::get_signal_list(const StringName &p_class, List *p_sig ClassInfo *check = type; while (check) { - const StringName *S = nullptr; - while ((S = check->signal_map.next(S))) { - p_signals->push_back(check->signal_map[*S]); + for (KeyValue &E : check->signal_map) { + p_signals->push_back(E.value); } if (p_no_inheritance) { @@ -1397,10 +1372,8 @@ void ClassDB::add_resource_base_extension(const StringName &p_extension, const S } void ClassDB::get_resource_base_extensions(List *p_extensions) { - const StringName *K = nullptr; - - while ((K = resource_base_extensions.next(K))) { - p_extensions->push_back(*K); + for (const KeyValue &E : resource_base_extensions) { + p_extensions->push_back(E.key); } } @@ -1409,12 +1382,9 @@ bool ClassDB::is_resource_extension(const StringName &p_extension) { } void ClassDB::get_extensions_for_type(const StringName &p_class, List *p_extensions) { - const StringName *K = nullptr; - - while ((K = resource_base_extensions.next(K))) { - StringName cmp = resource_base_extensions[*K]; - if (is_parent_class(p_class, cmp) || is_parent_class(cmp, p_class)) { - p_extensions->push_back(*K); + for (const KeyValue &E : resource_base_extensions) { + if (is_parent_class(p_class, E.value) || is_parent_class(E.value, p_class)) { + p_extensions->push_back(E.key); } } } @@ -1556,14 +1526,11 @@ void ClassDB::cleanup_defaults() { void ClassDB::cleanup() { //OBJTYPE_LOCK; hah not here - const StringName *k = nullptr; + for (KeyValue &E : classes) { + ClassInfo &ti = E.value; - while ((k = classes.next(k))) { - ClassInfo &ti = classes[*k]; - - const StringName *m = nullptr; - while ((m = ti.method_map.next(m))) { - memdelete(ti.method_map[*m]); + for (KeyValue &F : ti.method_map) { + memdelete(F.value); } } classes.clear(); diff --git a/core/object/object.cpp b/core/object/object.cpp index 2b620415331..797eecd3122 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -417,9 +417,9 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid return; } else { - OrderedHashMap::Element *E = metadata_properties.getptr(p_name); - if (E) { - E->get() = p_value; + Variant **V = metadata_properties.getptr(p_name); + if (V) { + **V = p_value; if (r_valid) { *r_valid = true; } @@ -508,10 +508,10 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { return ret; } - const OrderedHashMap::Element *E = metadata_properties.getptr(p_name); + const Variant *const *V = metadata_properties.getptr(p_name); - if (E) { - ret = E->get(); + if (V) { + ret = **V; if (r_valid) { *r_valid = true; } @@ -666,9 +666,9 @@ void Object::get_property_list(List *p_list, bool p_reversed) cons script_instance->get_property_list(p_list); } - for (OrderedHashMap::ConstElement K = metadata.front(); K; K = K.next()) { - PropertyInfo pi = PropertyInfo(K.value().get_type(), "metadata/" + K.key().operator String()); - if (K.value().get_type() == Variant::OBJECT) { + for (const KeyValue &K : metadata) { + PropertyInfo pi = PropertyInfo(K.value.get_type(), "metadata/" + K.key.operator String()); + if (K.value.get_type() == Variant::OBJECT) { pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Resource"; } @@ -944,13 +944,13 @@ void Object::set_meta(const StringName &p_name, const Variant &p_value) { return; } - OrderedHashMap::Element E = metadata.find(p_name); + HashMap::Iterator E = metadata.find(p_name); if (E) { - E.value() = p_value; + E->value = p_value; } else { ERR_FAIL_COND(!p_name.operator String().is_valid_identifier()); - E = metadata.insert(p_name, p_value); - metadata_properties["metadata/" + p_name.operator String()] = E; + Variant *V = &metadata.insert(p_name, p_value)->value; + metadata_properties["metadata/" + p_name.operator String()] = V; notify_property_list_changed(); } } @@ -993,16 +993,16 @@ Array Object::_get_method_list_bind() const { Vector Object::_get_meta_list_bind() const { Vector _metaret; - for (OrderedHashMap::ConstElement K = metadata.front(); K; K = K.next()) { - _metaret.push_back(K.key()); + for (const KeyValue &K : metadata) { + _metaret.push_back(K.key); } return _metaret; } void Object::get_meta_list(List *p_list) const { - for (OrderedHashMap::ConstElement K = metadata.front(); K; K = K.next()) { - p_list->push_back(K.key()); + for (const KeyValue &K : metadata) { + p_list->push_back(K.key); } } @@ -1250,21 +1250,18 @@ void Object::get_signal_list(List *p_signals) const { ClassDB::get_signal_list(get_class_name(), p_signals); //find maybe usersignals? - const StringName *S = nullptr; - while ((S = signal_map.next(S))) { - if (!signal_map[*S].user.name.is_empty()) { + for (const KeyValue &E : signal_map) { + if (!E.value.user.name.is_empty()) { //user signal - p_signals->push_back(signal_map[*S].user); + p_signals->push_back(E.value.user); } } } void Object::get_all_signal_connections(List *p_connections) const { - const StringName *S = nullptr; - - while ((S = signal_map.next(S))) { - const SignalData *s = &signal_map[*S]; + for (const KeyValue &E : signal_map) { + const SignalData *s = &E.value; for (int i = 0; i < s->slot_map.size(); i++) { p_connections->push_back(s->slot_map.getv(i).conn); @@ -1285,10 +1282,9 @@ void Object::get_signal_connection_list(const StringName &p_signal, List &E : signal_map) { + const SignalData *s = &E.value; for (int i = 0; i < s->slot_map.size(); i++) { if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) { @@ -1866,15 +1862,15 @@ Object::~Object() { _extension_instance = nullptr; } - const StringName *S = nullptr; - if (_emitting) { //@todo this may need to actually reach the debugger prioritarily somehow because it may crash before ERR_PRINT("Object " + to_string() + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes."); } - while ((S = signal_map.next(nullptr))) { - SignalData *s = &signal_map[*S]; + while (signal_map.size()) { + // Avoid regular iteration so erasing is safe. + KeyValue &E = *signal_map.begin(); + SignalData *s = &E.value; //brute force disconnect for performance int slot_count = s->slot_map.size(); @@ -1884,7 +1880,7 @@ Object::~Object() { slot_list[i].value.conn.callable.get_object()->connections.erase(slot_list[i].value.cE); } - signal_map.erase(*S); + signal_map.erase(E.key); } //signals from nodes that connect to this node diff --git a/core/object/object.h b/core/object/object.h index c3e3c68b593..00cb73593bb 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -39,7 +39,6 @@ #include "core/templates/hash_map.h" #include "core/templates/list.h" #include "core/templates/map.h" -#include "core/templates/ordered_hash_map.h" #include "core/templates/safe_refcount.h" #include "core/templates/set.h" #include "core/templates/vmap.h" @@ -515,8 +514,8 @@ private: #endif ScriptInstance *script_instance = nullptr; Variant script; // Reference does not exist yet, store it in a Variant. - OrderedHashMap metadata; - HashMap::Element> metadata_properties; + HashMap metadata; + HashMap metadata_properties; mutable StringName _class_name; mutable const StringName *_class_ptr = nullptr; diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index a5d25bf5336..c1036e3413c 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -253,10 +253,9 @@ StringName ScriptServer::get_global_class_native_base(const String &p_class) { } void ScriptServer::get_global_class_list(List *r_global_classes) { - const StringName *K = nullptr; List classes; - while ((K = global_classes.next(K))) { - classes.push_back(*K); + for (const KeyValue &E : global_classes) { + classes.push_back(E.key); } classes.sort_custom(); for (const StringName &E : classes) { diff --git a/core/os/memory.h b/core/os/memory.h index baa96ef3e97..42ba9634e26 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -197,4 +197,12 @@ struct _GlobalNilClass { static _GlobalNil _nil; }; +template +class DefaultTypedAllocator { +public: + template + _FORCE_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); } + _FORCE_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); } +}; + #endif // MEMORY_H diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index 3f94e064ecf..fa656b634d4 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -70,21 +70,14 @@ Dictionary TranslationPO::_get_messages() const { Dictionary d; - List context_l; - translation_map.get_key_list(&context_l); - for (const StringName &ctx : context_l) { - const HashMap> &id_str_map = translation_map[ctx]; - + for (const KeyValue>> &E : translation_map) { Dictionary d2; - List id_l; - id_str_map.get_key_list(&id_l); - // Save list of id and strs associated with a context in a temporary dictionary. - for (List::Element *E2 = id_l.front(); E2; E2 = E2->next()) { - StringName id = E2->get(); - d2[id] = id_str_map[id]; + + for (const KeyValue> &E2 : E.value) { + d2[E2.key] = E2.value; } - d[ctx] = d2; + d[E.key] = d2; } return d; @@ -274,31 +267,24 @@ void TranslationPO::get_message_list(List *r_messages) const { // OptimizedTranslation uses this function to get the list of msgid. // Return all the keys of translation_map under "" context. - List context_l; - translation_map.get_key_list(&context_l); - - for (const StringName &E : context_l) { - if (String(E) != "") { + for (const KeyValue>> &E : translation_map) { + if (E.key != StringName()) { continue; } - List msgid_l; - translation_map[E].get_key_list(&msgid_l); - - for (List::Element *E2 = msgid_l.front(); E2; E2 = E2->next()) { - r_messages->push_back(E2->get()); + for (const KeyValue> &E2 : E.value) { + r_messages->push_back(E2.key); } } } int TranslationPO::get_message_count() const { - List context_l; - translation_map.get_key_list(&context_l); - int count = 0; - for (const StringName &E : context_l) { - count += translation_map[E].size(); + + for (const KeyValue>> &E : translation_map) { + count += E.value.size(); } + return count; } diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index fa5677cc70f..55292d3eb54 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -31,524 +31,553 @@ #ifndef HASH_MAP_H #define HASH_MAP_H -#include "core/error/error_macros.h" #include "core/math/math_funcs.h" #include "core/os/memory.h" -#include "core/string/ustring.h" #include "core/templates/hashfuncs.h" -#include "core/templates/list.h" +#include "core/templates/paged_allocator.h" +#include "core/templates/pair.h" /** - * @class HashMap + * A HashMap implementation that uses open addressing with Robin Hood hashing. + * Robin Hood hashing swaps out entries that have a smaller probing distance + * than the to-be-inserted entry, that evens out the average probing distance + * and enables faster lookups. Backward shift deletion is employed to further + * improve the performance and to avoid infinite loops in rare cases. * - * Implementation of a standard Hashing HashMap, for quick lookups of Data associated with a Key. - * The implementation provides hashers for the default types, if you need a special kind of hasher, provide - * your own. - * @param TKey Key, search is based on it, needs to be hasheable. It is unique in this container. - * @param TData Data, data associated with the key - * @param Hasher Hasher object, needs to provide a valid static hash function for TKey - * @param Comparator comparator object, needs to be able to safely compare two TKey values. - * It needs to ensure that x == x for any items inserted in the map. Bear in mind that nan != nan when implementing an equality check. - * @param MIN_HASH_TABLE_POWER Miminum size of the hash table, as a power of two. You rarely need to change this parameter. - * @param RELATIONSHIP Relationship at which the hash table is resized. if amount of elements is RELATIONSHIP - * times bigger than the hash table, table is resized to solve this condition. if RELATIONSHIP is zero, table is always MIN_HASH_TABLE_POWER. + * Keys and values are stored in a double linked list by insertion order. This + * has a slight performance overhead on lookup, which can be mostly compensated + * using a paged allocator if required. * + * The assignment operator copy the pairs from one map to the other. */ -template , uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8> +template +struct HashMapElement { + HashMapElement *next = nullptr; + HashMapElement *prev = nullptr; + KeyValue data; + HashMapElement() {} + HashMapElement(const TKey &p_key, const TValue &p_value) : + data(p_key, p_value) {} +}; + +template , + class Allocator = DefaultTypedAllocator>> class HashMap { public: - struct Pair { - TKey key; - TData data; - - Pair(const TKey &p_key) : - key(p_key), - data() {} - Pair(const TKey &p_key, const TData &p_data) : - key(p_key), - data(p_data) { - } - }; - - struct Element { - private: - friend class HashMap; - - uint32_t hash = 0; - Element *next = nullptr; - Element() {} - Pair pair; - - public: - const TKey &key() const { - return pair.key; - } - - TData &value() { - return pair.data; - } - - const TData &value() const { - return pair.value(); - } - - Element(const TKey &p_key) : - pair(p_key) {} - Element(const Element &p_other) : - hash(p_other.hash), - pair(p_other.pair.key, p_other.pair.data) {} - }; + const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. + const float MAX_OCCUPANCY = 0.75; + const uint32_t EMPTY_HASH = 0; private: - Element **hash_table = nullptr; - uint8_t hash_table_power = 0; - uint32_t elements = 0; + Allocator element_alloc; + HashMapElement **elements = nullptr; + uint32_t *hashes = nullptr; + HashMapElement *head_element = nullptr; + HashMapElement *tail_element = nullptr; - void make_hash_table() { - ERR_FAIL_COND(hash_table); + uint32_t capacity_index = 0; + uint32_t num_elements = 0; - hash_table = memnew_arr(Element *, (1 << MIN_HASH_TABLE_POWER)); - - hash_table_power = MIN_HASH_TABLE_POWER; - elements = 0; - for (int i = 0; i < (1 << MIN_HASH_TABLE_POWER); i++) { - hash_table[i] = nullptr; - } - } - - void erase_hash_table() { - ERR_FAIL_COND_MSG(elements, "Cannot erase hash table if there are still elements inside."); - - memdelete_arr(hash_table); - hash_table = nullptr; - hash_table_power = 0; - elements = 0; - } - - void check_hash_table() { - int new_hash_table_power = -1; - - if ((int)elements > ((1 << hash_table_power) * RELATIONSHIP)) { - /* rehash up */ - new_hash_table_power = hash_table_power + 1; - - while ((int)elements > ((1 << new_hash_table_power) * RELATIONSHIP)) { - new_hash_table_power++; - } - - } else if ((hash_table_power > (int)MIN_HASH_TABLE_POWER) && ((int)elements < ((1 << (hash_table_power - 1)) * RELATIONSHIP))) { - /* rehash down */ - new_hash_table_power = hash_table_power - 1; - - while ((int)elements < ((1 << (new_hash_table_power - 1)) * RELATIONSHIP)) { - new_hash_table_power--; - } - - if (new_hash_table_power < (int)MIN_HASH_TABLE_POWER) { - new_hash_table_power = MIN_HASH_TABLE_POWER; - } - } - - if (new_hash_table_power == -1) { - return; - } - - Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power)); - ERR_FAIL_COND_MSG(!new_hash_table, "Out of memory."); - - for (int i = 0; i < (1 << new_hash_table_power); i++) { - new_hash_table[i] = nullptr; - } - - if (hash_table) { - for (int i = 0; i < (1 << hash_table_power); i++) { - while (hash_table[i]) { - Element *se = hash_table[i]; - hash_table[i] = se->next; - int new_pos = se->hash & ((1 << new_hash_table_power) - 1); - se->next = new_hash_table[new_pos]; - new_hash_table[new_pos] = se; - } - } - - memdelete_arr(hash_table); - } - hash_table = new_hash_table; - hash_table_power = new_hash_table_power; - } - - /* I want to have only one function.. */ - _FORCE_INLINE_ const Element *get_element(const TKey &p_key) const { + _FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const { uint32_t hash = Hasher::hash(p_key); - uint32_t index = hash & ((1 << hash_table_power) - 1); - Element *e = hash_table[index]; + if (unlikely(hash == EMPTY_HASH)) { + hash = EMPTY_HASH + 1; + } - while (e) { - /* checking hash first avoids comparing key, which may take longer */ - if (e->hash == hash && Comparator::compare(e->pair.key, p_key)) { - /* the pair exists in this hashtable, so just update data */ - return e; + 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 (elements == 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; } - e = e->next; - } - - return nullptr; - } - - Element *create_element(const TKey &p_key) { - /* if element doesn't exist, create it */ - Element *e = memnew(Element(p_key)); - ERR_FAIL_COND_V_MSG(!e, nullptr, "Out of memory."); - uint32_t hash = Hasher::hash(p_key); - uint32_t index = hash & ((1 << hash_table_power) - 1); - e->next = hash_table[index]; - e->hash = hash; - - hash_table[index] = e; - elements++; - - return e; - } - - void copy_from(const HashMap &p_t) { - if (&p_t == this) { - return; /* much less bother with that */ - } - - clear(); - - if (!p_t.hash_table || p_t.hash_table_power == 0) { - return; /* not copying from empty table */ - } - - hash_table = memnew_arr(Element *, (uint64_t)1 << p_t.hash_table_power); - hash_table_power = p_t.hash_table_power; - elements = p_t.elements; - - for (int i = 0; i < (1 << p_t.hash_table_power); i++) { - hash_table[i] = nullptr; - - const Element *e = p_t.hash_table[i]; - - while (e) { - Element *le = memnew(Element(*e)); /* local element */ - - /* add to list and reassign pointers */ - le->next = hash_table[i]; - hash_table[i] = le; - - e = e->next; - } - } - } - -public: - Element *set(const TKey &p_key, const TData &p_data) { - return set(Pair(p_key, p_data)); - } - - Element *set(const Pair &p_pair) { - Element *e = nullptr; - if (!hash_table) { - make_hash_table(); // if no table, make one - } else { - e = const_cast(get_element(p_pair.key)); - } - - /* if we made it up to here, the pair doesn't exist, create and assign */ - - if (!e) { - e = create_element(p_pair.key); - if (!e) { - return nullptr; - } - check_hash_table(); // perform mantenience routine - } - - e->pair.data = p_pair.data; - return e; - } - - bool has(const TKey &p_key) const { - return getptr(p_key) != nullptr; - } - - /** - * Get a key from data, return a const reference. - * WARNING: this doesn't check errors, use either getptr and check nullptr, or check - * first with has(key) - */ - - const TData &get(const TKey &p_key) const { - const TData *res = getptr(p_key); - CRASH_COND_MSG(!res, "Map key not found."); - return *res; - } - - TData &get(const TKey &p_key) { - TData *res = getptr(p_key); - CRASH_COND_MSG(!res, "Map key not found."); - return *res; - } - - /** - * Same as get, except it can return nullptr when item was not found. - * This is mainly used for speed purposes. - */ - - _FORCE_INLINE_ TData *getptr(const TKey &p_key) { - if (unlikely(!hash_table)) { - return nullptr; - } - - Element *e = const_cast(get_element(p_key)); - - if (e) { - return &e->pair.data; - } - - return nullptr; - } - - _FORCE_INLINE_ const TData *getptr(const TKey &p_key) const { - if (unlikely(!hash_table)) { - return nullptr; - } - - const Element *e = const_cast(get_element(p_key)); - - if (e) { - return &e->pair.data; - } - - return nullptr; - } - - /** - * Same as get, except it can return nullptr when item was not found. - * This version is custom, will take a hash and a custom key (that should support operator==() - */ - - template - _FORCE_INLINE_ TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) { - if (unlikely(!hash_table)) { - return nullptr; - } - - uint32_t hash = p_custom_hash; - uint32_t index = hash & ((1 << hash_table_power) - 1); - - Element *e = hash_table[index]; - - while (e) { - /* checking hash first avoids comparing key, which may take longer */ - if (e->hash == hash && Comparator::compare(e->pair.key, p_custom_key)) { - /* the pair exists in this hashtable, so just update data */ - return &e->pair.data; + if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + return false; } - e = e->next; - } - - return nullptr; - } - - template - _FORCE_INLINE_ const TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) const { - if (unlikely(!hash_table)) { - return nullptr; - } - - uint32_t hash = p_custom_hash; - uint32_t index = hash & ((1 << hash_table_power) - 1); - - const Element *e = hash_table[index]; - - while (e) { - /* checking hash first avoids comparing key, which may take longer */ - if (e->hash == hash && Comparator::compare(e->pair.key, p_custom_key)) { - /* the pair exists in this hashtable, so just update data */ - return &e->pair.data; - } - - e = e->next; - } - - return nullptr; - } - - /** - * Erase an item, return true if erasing was successful - */ - - bool erase(const TKey &p_key) { - if (unlikely(!hash_table)) { - return false; - } - - uint32_t hash = Hasher::hash(p_key); - uint32_t index = hash & ((1 << hash_table_power) - 1); - - Element *e = hash_table[index]; - Element *p = nullptr; - while (e) { - /* checking hash first avoids comparing key, which may take longer */ - if (e->hash == hash && Comparator::compare(e->pair.key, p_key)) { - if (p) { - p->next = e->next; - } else { - //begin of list - hash_table[index] = e->next; - } - - memdelete(e); - elements--; - - if (elements == 0) { - erase_hash_table(); - } else { - check_hash_table(); - } + if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) { + r_pos = pos; return true; } - p = e; - e = e->next; + pos = (pos + 1) % capacity; + distance++; + } + } + + void _insert_with_hash(uint32_t p_hash, HashMapElement *p_value) { + uint32_t capacity = hash_table_size_primes[capacity_index]; + uint32_t hash = p_hash; + HashMapElement *value = p_value; + uint32_t distance = 0; + uint32_t pos = hash % capacity; + + while (true) { + if (hashes[pos] == EMPTY_HASH) { + elements[pos] = value; + hashes[pos] = hash; + + num_elements++; + + return; + } + + // 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) { + SWAP(hash, hashes[pos]); + SWAP(value, elements[pos]); + distance = existing_probe_len; + } + + pos = (pos + 1) % capacity; + distance++; + } + } + + void _resize_and_rehash(uint32_t p_new_capacity_index) { + uint32_t old_capacity = hash_table_size_primes[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]; + + HashMapElement **old_elements = elements; + uint32_t *old_hashes = hashes; + + num_elements = 0; + hashes = reinterpret_cast(Memory::alloc_static(sizeof(uint32_t) * capacity)); + elements = reinterpret_cast **>(Memory::alloc_static(sizeof(HashMapElement *) * capacity)); + + for (uint32_t i = 0; i < capacity; i++) { + hashes[i] = 0; + elements[i] = nullptr; } - return false; + if (old_capacity == 0) { + // Nothing to do. + return; + } + + for (uint32_t i = 0; i < old_capacity; i++) { + if (old_hashes[i] == EMPTY_HASH) { + continue; + } + + _insert_with_hash(old_hashes[i], old_elements[i]); + } + + Memory::free_static(old_elements); + Memory::free_static(old_hashes); } - inline const TData &operator[](const TKey &p_key) const { //constref + _FORCE_INLINE_ HashMapElement *_insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) { + uint32_t capacity = hash_table_size_primes[capacity_index]; + if (unlikely(elements == nullptr)) { + // Allocate on demand to save memory. - return get(p_key); - } - inline TData &operator[](const TKey &p_key) { //assignment + hashes = reinterpret_cast(Memory::alloc_static(sizeof(uint32_t) * capacity)); + elements = reinterpret_cast **>(Memory::alloc_static(sizeof(HashMapElement *) * capacity)); - Element *e = nullptr; - if (!hash_table) { - make_hash_table(); // if no table, make one + for (uint32_t i = 0; i < capacity; i++) { + hashes[i] = EMPTY_HASH; + elements[i] = nullptr; + } + } + + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + + if (exists) { + elements[pos]->data.value = p_value; + return elements[pos]; } else { - e = const_cast(get_element(p_key)); - } - - /* if we made it up to here, the pair doesn't exist, create */ - if (!e) { - e = create_element(p_key); - CRASH_COND(!e); - check_hash_table(); // perform mantenience routine - } - - return e->pair.data; - } - - /** - * Get the next key to p_key, and the first key if p_key is null. - * Returns a pointer to the next key if found, nullptr otherwise. - * Adding/Removing elements while iterating will, of course, have unexpected results, don't do it. - * - * Example: - * - * const TKey *k=nullptr; - * - * while( (k=table.next(k)) ) { - * - * print( *k ); - * } - * - */ - const TKey *next(const TKey *p_key) const { - if (unlikely(!hash_table)) { - return nullptr; - } - - if (!p_key) { /* get the first key */ - - for (int i = 0; i < (1 << hash_table_power); i++) { - if (hash_table[i]) { - return &hash_table[i]->pair.key; - } + if (num_elements + 1 > MAX_OCCUPANCY * capacity) { + ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, nullptr, "Hash table maximum capacity reached, aborting insertion."); + _resize_and_rehash(capacity_index + 1); } - } else { /* get the next key */ + HashMapElement *elem = element_alloc.new_allocation(HashMapElement(p_key, p_value)); - const Element *e = get_element(*p_key); - ERR_FAIL_COND_V_MSG(!e, nullptr, "Invalid key supplied."); - if (e->next) { - /* if there is a "next" in the list, return that */ - return &e->next->pair.key; + if (tail_element == nullptr) { + head_element = elem; + tail_element = elem; + } else if (p_front_insert) { + head_element->prev = elem; + elem->next = head_element; + head_element = elem; } else { - /* go to next elements */ - uint32_t index = e->hash & ((1 << hash_table_power) - 1); - index++; - for (int i = index; i < (1 << hash_table_power); i++) { - if (hash_table[i]) { - return &hash_table[i]->pair.key; - } - } + tail_element->next = elem; + elem->prev = tail_element; + tail_element = elem; } - /* nothing found, was at end */ + uint32_t hash = _hash(p_key); + _insert_with_hash(hash, elem); + return elem; } - - return nullptr; /* nothing found */ } - inline unsigned int size() const { - return elements; - } +public: + _FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; } + _FORCE_INLINE_ uint32_t size() const { return num_elements; } - inline bool is_empty() const { - return elements == 0; + /* Standard Godot Container API */ + + bool is_empty() const { + return num_elements == 0; } void clear() { - /* clean up */ - if (hash_table) { - for (int i = 0; i < (1 << hash_table_power); i++) { - while (hash_table[i]) { - Element *e = hash_table[i]; - hash_table[i] = e->next; - memdelete(e); - } - } - - memdelete_arr(hash_table); - } - - hash_table = nullptr; - hash_table_power = 0; - elements = 0; - } - - void operator=(const HashMap &p_table) { - copy_from(p_table); - } - - void get_key_list(List *r_keys) const { - if (unlikely(!hash_table)) { + if (elements == nullptr) { return; } - for (int i = 0; i < (1 << hash_table_power); i++) { - Element *e = hash_table[i]; - while (e) { - r_keys->push_back(e->pair.key); - e = e->next; + uint32_t capacity = hash_table_size_primes[capacity_index]; + for (uint32_t i = 0; i < capacity; i++) { + if (hashes[i] == EMPTY_HASH) { + continue; } + + hashes[i] = EMPTY_HASH; + element_alloc.delete_allocation(elements[i]); + elements[i] = nullptr; + } + + tail_element = nullptr; + head_element = nullptr; + num_elements = 0; + } + + TValue &get(const TKey &p_key) { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + CRASH_COND_MSG(!exists, "HashMap key not found."); + return elements[pos]->data.value; + } + + const TValue &get(const TKey &p_key) const { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + CRASH_COND_MSG(!exists, "HashMap key not found."); + return elements[pos]->data.value; + } + + const TValue *getptr(const TKey &p_key) const { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + + if (exists) { + return &elements[pos]->data.value; + } + return nullptr; + } + + TValue *getptr(const TKey &p_key) { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + + if (exists) { + return &elements[pos]->data.value; + } + return nullptr; + } + + _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 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) { + SWAP(hashes[next_pos], hashes[pos]); + SWAP(elements[next_pos], elements[pos]); + pos = next_pos; + next_pos = (pos + 1) % capacity; + } + + hashes[pos] = EMPTY_HASH; + + if (head_element == elements[pos]) { + head_element = elements[pos]->next; + } + + if (tail_element == elements[pos]) { + tail_element = elements[pos]->prev; + } + + if (elements[pos]->prev) { + elements[pos]->prev->next = elements[pos]->next; + } + + if (elements[pos]->next) { + elements[pos]->next->prev = elements[pos]->prev; + } + + element_alloc.delete_allocation(elements[pos]); + elements[pos] = nullptr; + + num_elements--; + 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 (elements == nullptr) { + capacity_index = new_index; + return; // Unallocated yet. + } + _resize_and_rehash(new_index); + } + + /** Iterator API **/ + + struct Iterator { + _FORCE_INLINE_ KeyValue &operator*() const { + return E->data; + } + _FORCE_INLINE_ KeyValue *operator->() const { return &E->data; } + _FORCE_INLINE_ Iterator &operator++() { + if (E) { + E = E->next; + } + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + if (E) { + E = E->prev; + } + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + _FORCE_INLINE_ operator bool() const { + return E != nullptr; + } + + _FORCE_INLINE_ Iterator(HashMapElement *p_E) { E = p_E; } + _FORCE_INLINE_ Iterator() {} + _FORCE_INLINE_ Iterator(const Iterator &p_it) { E = p_it.E; } + _FORCE_INLINE_ void operator=(const Iterator &p_it) { + E = p_it.E; + } + + private: + HashMapElement *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const KeyValue &operator*() const { + return E->data; + } + _FORCE_INLINE_ const KeyValue *operator->() const { return &E->data; } + _FORCE_INLINE_ ConstIterator &operator++() { + if (E) { + E = E->next; + } + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + if (E) { + E = E->prev; + } + return *this; + } + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; } + + _FORCE_INLINE_ operator bool() const { + return E != nullptr; + } + + _FORCE_INLINE_ ConstIterator(const HashMapElement *p_E) { E = p_E; } + _FORCE_INLINE_ ConstIterator() {} + _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + _FORCE_INLINE_ void operator=(const ConstIterator &p_it) { + E = p_it.E; + } + + private: + const HashMapElement *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(head_element); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + _FORCE_INLINE_ Iterator last() { + return Iterator(tail_element); + } + + _FORCE_INLINE_ Iterator find(const TKey &p_key) { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + if (!exists) { + return end(); + } + return Iterator(elements[pos]); + } + + _FORCE_INLINE_ void remove(const Iterator &p_iter) { + if (p_iter) { + erase(p_iter->key); } } - HashMap() {} + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(head_element); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } + _FORCE_INLINE_ ConstIterator last() const { + return ConstIterator(tail_element); + } - HashMap(const HashMap &p_table) { - copy_from(p_table); + _FORCE_INLINE_ ConstIterator find(const TKey &p_key) const { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + if (!exists) { + return end(); + } + return ConstIterator(elements[pos]); + } + + /* Indexing */ + + const TValue &operator[](const TKey &p_key) const { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + CRASH_COND(!exists); + return elements[pos]->data.value; + } + + TValue &operator[](const TKey &p_key) { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + if (!exists) { + return _insert(p_key, TValue())->data.value; + } else { + return elements[pos]->data.value; + } + } + + /* Insert */ + + Iterator insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) { + return Iterator(_insert(p_key, p_value, p_front_insert)); + } + + /* Constructors */ + + HashMap(const HashMap &p_other) { + reserve(hash_table_size_primes[p_other.capacity_index]); + + if (p_other.num_elements == 0) { + return; + } + + for (const KeyValue &E : p_other) { + insert(E.key, E.value); + } + } + + void operator=(const HashMap &p_other) { + if (this == &p_other) { + return; // Ignore self assignment. + } + if (num_elements != 0) { + clear(); + } + + reserve(hash_table_size_primes[p_other.capacity_index]); + + if (p_other.elements == nullptr) { + return; // Nothing to copy. + } + + for (const KeyValue &E : p_other) { + insert(E.key, E.value); + } + } + + HashMap(uint32_t p_initial_capacity) { + // Capacity can't be 0. + capacity_index = 0; + reserve(p_initial_capacity); + } + HashMap() { + capacity_index = MIN_CAPACITY_INDEX; + } + + uint32_t debug_get_hash(uint32_t p_index) { + if (num_elements == 0) { + return 0; + } + ERR_FAIL_INDEX_V(p_index, get_capacity(), 0); + return hashes[p_index]; + } + Iterator debug_get_element(uint32_t p_index) { + if (num_elements == 0) { + return Iterator(); + } + ERR_FAIL_INDEX_V(p_index, get_capacity(), Iterator()); + return Iterator(elements[p_index]); } ~HashMap() { clear(); + + if (elements != nullptr) { + Memory::free_static(elements); + Memory::free_static(hashes); + } } }; diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index 2a129f97d57..eb73ff4edee 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -31,14 +31,22 @@ #ifndef HASHFUNCS_H #define HASHFUNCS_H +#include "core/math/aabb.h" #include "core/math/math_defs.h" #include "core/math/math_funcs.h" +#include "core/math/rect2.h" +#include "core/math/rect2i.h" +#include "core/math/vector2.h" +#include "core/math/vector2i.h" +#include "core/math/vector3.h" +#include "core/math/vector3i.h" #include "core/object/object_id.h" #include "core/string/node_path.h" #include "core/string/string_name.h" #include "core/string/ustring.h" #include "core/templates/rid.h" #include "core/typedefs.h" + /** * Hashing functions */ @@ -178,6 +186,49 @@ struct HashMapHasherDefault { static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } + static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) { + uint32_t h = hash_djb2_one_32(p_vec.x); + return hash_djb2_one_32(p_vec.y, h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) { + uint32_t h = hash_djb2_one_32(p_vec.x); + h = hash_djb2_one_32(p_vec.y, h); + return hash_djb2_one_32(p_vec.z, h); + } + + static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) { + uint32_t h = hash_djb2_one_float(p_vec.x); + return hash_djb2_one_float(p_vec.y, h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) { + uint32_t h = hash_djb2_one_float(p_vec.x); + h = hash_djb2_one_float(p_vec.y, h); + return hash_djb2_one_float(p_vec.z, h); + } + + static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) { + uint32_t h = hash_djb2_one_32(p_rect.position.x); + h = hash_djb2_one_32(p_rect.position.y, h); + h = hash_djb2_one_32(p_rect.size.x, h); + return hash_djb2_one_32(p_rect.size.y, h); + } + + static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) { + uint32_t h = hash_djb2_one_float(p_rect.position.x); + h = hash_djb2_one_float(p_rect.position.y, h); + h = hash_djb2_one_float(p_rect.size.x, h); + return hash_djb2_one_float(p_rect.size.y, h); + } + + static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) { + uint32_t h = hash_djb2_one_float(p_aabb.position.x); + h = hash_djb2_one_float(p_aabb.position.y, h); + h = hash_djb2_one_float(p_aabb.position.z, h); + h = hash_djb2_one_float(p_aabb.size.x, h); + h = hash_djb2_one_float(p_aabb.size.y, h); + return hash_djb2_one_float(p_aabb.size.z, h); + } + //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } }; @@ -196,4 +247,38 @@ struct HashMapComparatorDefault { } }; +constexpr uint32_t HASH_TABLE_SIZE_MAX = 29; + +const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { + 5, + 13, + 23, + 47, + 97, + 193, + 389, + 769, + 1543, + 3079, + 6151, + 12289, + 24593, + 49157, + 98317, + 196613, + 393241, + 786433, + 1572869, + 3145739, + 6291469, + 12582917, + 25165843, + 50331653, + 100663319, + 201326611, + 402653189, + 805306457, + 1610612741, +}; + #endif // HASHFUNCS_H diff --git a/core/templates/ordered_hash_map.h b/core/templates/ordered_hash_map.h deleted file mode 100644 index 3d1f3a08ecc..00000000000 --- a/core/templates/ordered_hash_map.h +++ /dev/null @@ -1,301 +0,0 @@ -/*************************************************************************/ -/* ordered_hash_map.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 ORDERED_HASH_MAP_H -#define ORDERED_HASH_MAP_H - -#include "core/templates/hash_map.h" -#include "core/templates/list.h" -#include "core/templates/pair.h" - -/** - * A hash map which allows to iterate elements in insertion order. - * Insertion, lookup, deletion have O(1) complexity. - * The API aims to be consistent with Map rather than HashMap, because the - * former is more frequently used and is more coherent with the rest of the - * codebase. - * Deletion during iteration is safe and will preserve the order. - */ -template , uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8> -class OrderedHashMap { - typedef List> InternalList; - typedef HashMap InternalMap; - - InternalList list; - InternalMap map; - -public: - class Element { - friend class OrderedHashMap; - - typename InternalList::Element *list_element = nullptr; - typename InternalList::Element *prev_element = nullptr; - typename InternalList::Element *next_element = nullptr; - - Element(typename InternalList::Element *p_element) { - list_element = p_element; - - if (list_element) { - next_element = list_element->next(); - prev_element = list_element->prev(); - } - } - - public: - _FORCE_INLINE_ Element() {} - - Element next() const { - return Element(next_element); - } - - Element prev() const { - return Element(prev_element); - } - - Element(const Element &other) : - list_element(other.list_element), - prev_element(other.prev_element), - next_element(other.next_element) { - } - - void operator=(const Element &other) { - list_element = other.list_element; - next_element = other.next_element; - prev_element = other.prev_element; - } - - _FORCE_INLINE_ bool operator==(const Element &p_other) const { - return this->list_element == p_other.list_element; - } - _FORCE_INLINE_ bool operator!=(const Element &p_other) const { - return this->list_element != p_other.list_element; - } - - operator bool() const { - return (list_element != nullptr); - } - - const K &key() const { - CRASH_COND(!list_element); - return *(list_element->get().first); - } - - V &value() { - CRASH_COND(!list_element); - return list_element->get().second; - } - - const V &value() const { - CRASH_COND(!list_element); - return list_element->get().second; - } - - V &get() { - CRASH_COND(!list_element); - return list_element->get().second; - } - - const V &get() const { - CRASH_COND(!list_element); - return list_element->get().second; - } - }; - - class ConstElement { - friend class OrderedHashMap; - - const typename InternalList::Element *list_element = nullptr; - - ConstElement(const typename InternalList::Element *p_element) : - list_element(p_element) { - } - - public: - _FORCE_INLINE_ ConstElement() {} - - ConstElement(const ConstElement &other) : - list_element(other.list_element) { - } - - void operator=(const ConstElement &other) { - list_element = other.list_element; - } - - ConstElement next() const { - return ConstElement(list_element ? list_element->next() : nullptr); - } - - ConstElement prev() const { - return ConstElement(list_element ? list_element->prev() : nullptr); - } - - _FORCE_INLINE_ bool operator==(const ConstElement &p_other) const { - return this->list_element == p_other.list_element; - } - _FORCE_INLINE_ bool operator!=(const ConstElement &p_other) const { - return this->list_element != p_other.list_element; - } - - operator bool() const { - return (list_element != nullptr); - } - - const K &key() const { - CRASH_COND(!list_element); - return *(list_element->get().first); - } - - const V &value() const { - CRASH_COND(!list_element); - return list_element->get().second; - } - - const V &get() const { - CRASH_COND(!list_element); - return list_element->get().second; - } - }; - - ConstElement find(const K &p_key) const { - typename InternalList::Element *const *list_element = map.getptr(p_key); - if (list_element) { - return ConstElement(*list_element); - } - return ConstElement(nullptr); - } - - Element find(const K &p_key) { - typename InternalList::Element **list_element = map.getptr(p_key); - if (list_element) { - return Element(*list_element); - } - return Element(nullptr); - } - - Element insert(const K &p_key, const V &p_value) { - typename InternalList::Element **list_element = map.getptr(p_key); - if (list_element) { - (*list_element)->get().second = p_value; - return Element(*list_element); - } - // Incorrectly set the first value of the pair with a value that will - // be invalid as soon as we leave this function... - typename InternalList::Element *new_element = list.push_back(Pair(&p_key, p_value)); - // ...this is needed here in case the hashmap recursively reference itself... - typename InternalMap::Element *e = map.set(p_key, new_element); - // ...now we can set the right value ! - new_element->get().first = &e->key(); - - return Element(new_element); - } - - void erase(Element &p_element) { - map.erase(p_element.key()); - list.erase(p_element.list_element); - p_element.list_element = nullptr; - } - - bool erase(const K &p_key) { - typename InternalList::Element **list_element = map.getptr(p_key); - if (list_element) { - list.erase(*list_element); - map.erase(p_key); - return true; - } - return false; - } - - inline bool has(const K &p_key) const { - return map.has(p_key); - } - - const V &operator[](const K &p_key) const { - ConstElement e = find(p_key); - CRASH_COND(!e); - return e.value(); - } - - V &operator[](const K &p_key) { - Element e = find(p_key); - if (!e) { - // consistent with Map behaviour - e = insert(p_key, V()); - } - return e.value(); - } - - inline Element front() { - return Element(list.front()); - } - - inline Element back() { - return Element(list.back()); - } - - inline ConstElement front() const { - return ConstElement(list.front()); - } - - inline ConstElement back() const { - return ConstElement(list.back()); - } - - inline bool is_empty() const { return list.is_empty(); } - inline int size() const { return list.size(); } - - const void *id() const { - return list.id(); - } - - void clear() { - map.clear(); - list.clear(); - } - -private: - void _copy_from(const OrderedHashMap &p_map) { - for (ConstElement E = p_map.front(); E; E = E.next()) { - insert(E.key(), E.value()); - } - } - -public: - void operator=(const OrderedHashMap &p_map) { - _copy_from(p_map); - } - - OrderedHashMap(const OrderedHashMap &p_map) { - _copy_from(p_map); - } - - _FORCE_INLINE_ OrderedHashMap() {} -}; - -#endif // ORDERED_HASH_MAP_H diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h index b9067e2edda..cf5911a8471 100644 --- a/core/templates/paged_allocator.h +++ b/core/templates/paged_allocator.h @@ -50,6 +50,10 @@ class PagedAllocator { SpinLock spin_lock; public: + enum { + DEFAULT_PAGE_SIZE = 4096 + }; + template T *alloc(const Args &&...p_args) { if (thread_safe) { @@ -121,7 +125,9 @@ public: page_shift = get_shift_from_power_of_2(page_size); } - PagedAllocator(uint32_t p_page_size = 4096) { // power of 2 recommended because of alignment with OS page sizes. Even if element is bigger, its still a multiple and get rounded amount of pages + // Power of 2 recommended because of alignment with OS page sizes. + // Even if element is bigger, it's still a multiple and gets rounded to amount of pages. + PagedAllocator(uint32_t p_page_size = DEFAULT_PAGE_SIZE) { configure(p_page_size); } diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index 0f2f8fc8ed1..46543da2c24 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -30,7 +30,7 @@ #include "dictionary.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" #include "core/templates/safe_refcount.h" #include "core/variant/variant.h" // required in this order by VariantInternal, do not remove this comment. @@ -41,7 +41,7 @@ struct DictionaryPrivate { SafeRefCount refcount; - OrderedHashMap variant_map; + HashMap variant_map; }; void Dictionary::get_key_list(List *p_keys) const { @@ -49,16 +49,16 @@ void Dictionary::get_key_list(List *p_keys) const { return; } - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - p_keys->push_back(E.key()); + for (const KeyValue &E : _p->variant_map) { + p_keys->push_back(E.key); } } Variant Dictionary::get_key_at_index(int p_index) const { int index = 0; - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + for (const KeyValue &E : _p->variant_map) { if (index == p_index) { - return E.key(); + return E.key; } index++; } @@ -68,9 +68,9 @@ Variant Dictionary::get_key_at_index(int p_index) const { Variant Dictionary::get_value_at_index(int p_index) const { int index = 0; - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { + for (const KeyValue &E : _p->variant_map) { if (index == p_index) { - return E.value(); + return E.value; } index++; } @@ -97,50 +97,50 @@ const Variant &Dictionary::operator[](const Variant &p_key) const { } const Variant *Dictionary::getptr(const Variant &p_key) const { - OrderedHashMap::ConstElement E; + HashMap::ConstIterator E; if (p_key.get_type() == Variant::STRING_NAME) { const StringName *sn = VariantInternal::get_string_name(&p_key); - E = ((const OrderedHashMap *)&_p->variant_map)->find(sn->operator String()); + E = ((const HashMap *)&_p->variant_map)->find(sn->operator String()); } else { - E = ((const OrderedHashMap *)&_p->variant_map)->find(p_key); + E = ((const HashMap *)&_p->variant_map)->find(p_key); } if (!E) { return nullptr; } - return &E.get(); + return &E->value; } Variant *Dictionary::getptr(const Variant &p_key) { - OrderedHashMap::Element E; + HashMap::Iterator E; if (p_key.get_type() == Variant::STRING_NAME) { const StringName *sn = VariantInternal::get_string_name(&p_key); - E = ((OrderedHashMap *)&_p->variant_map)->find(sn->operator String()); + E = ((HashMap *)&_p->variant_map)->find(sn->operator String()); } else { - E = ((OrderedHashMap *)&_p->variant_map)->find(p_key); + E = ((HashMap *)&_p->variant_map)->find(p_key); } if (!E) { return nullptr; } - return &E.get(); + return &E->value; } Variant Dictionary::get_valid(const Variant &p_key) const { - OrderedHashMap::ConstElement E; + HashMap::ConstIterator E; if (p_key.get_type() == Variant::STRING_NAME) { const StringName *sn = VariantInternal::get_string_name(&p_key); - E = ((const OrderedHashMap *)&_p->variant_map)->find(sn->operator String()); + E = ((const HashMap *)&_p->variant_map)->find(sn->operator String()); } else { - E = ((const OrderedHashMap *)&_p->variant_map)->find(p_key); + E = ((const HashMap *)&_p->variant_map)->find(p_key); } if (!E) { return Variant(); } - return E.get(); + return E->value; } Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const { @@ -210,9 +210,9 @@ bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_c return true; } recursion_count++; - for (OrderedHashMap::ConstElement this_E = ((const OrderedHashMap *)&_p->variant_map)->front(); this_E; this_E = this_E.next()) { - OrderedHashMap::ConstElement other_E = ((const OrderedHashMap *)&p_dictionary._p->variant_map)->find(this_E.key()); - if (!other_E || !this_E.value().hash_compare(other_E.value(), recursion_count)) { + for (const KeyValue &this_E : _p->variant_map) { + HashMap::ConstIterator other_E = ((const HashMap *)&p_dictionary._p->variant_map)->find(this_E.key); + if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count)) { return false; } } @@ -261,9 +261,9 @@ uint32_t Dictionary::recursive_hash(int recursion_count) const { uint32_t h = hash_djb2_one_32(Variant::DICTIONARY); recursion_count++; - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - h = hash_djb2_one_32(E.key().recursive_hash(recursion_count), h); - h = hash_djb2_one_32(E.value().recursive_hash(recursion_count), h); + for (const KeyValue &E : _p->variant_map) { + h = hash_djb2_one_32(E.key.recursive_hash(recursion_count), h); + h = hash_djb2_one_32(E.value.recursive_hash(recursion_count), h); } return h; @@ -278,8 +278,8 @@ Array Dictionary::keys() const { varr.resize(size()); int i = 0; - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - varr[i] = E.key(); + for (const KeyValue &E : _p->variant_map) { + varr[i] = E.key; i++; } @@ -295,8 +295,8 @@ Array Dictionary::values() const { varr.resize(size()); int i = 0; - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - varr[i] = E.get(); + for (const KeyValue &E : _p->variant_map) { + varr[i] = E.value; i++; } @@ -306,16 +306,23 @@ Array Dictionary::values() const { const Variant *Dictionary::next(const Variant *p_key) const { if (p_key == nullptr) { // caller wants to get the first element - if (_p->variant_map.front()) { - return &_p->variant_map.front().key(); + if (_p->variant_map.begin()) { + return &_p->variant_map.begin()->key; } return nullptr; } - OrderedHashMap::Element E = _p->variant_map.find(*p_key); + HashMap::Iterator E = _p->variant_map.find(*p_key); - if (E && E.next()) { - return &E.next().key(); + if (!E) { + return nullptr; } + + ++E; + + if (E) { + return &E->key; + } + return nullptr; } @@ -333,12 +340,12 @@ Dictionary Dictionary::recursive_duplicate(bool p_deep, int recursion_count) con if (p_deep) { recursion_count++; - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - n[E.key().recursive_duplicate(true, recursion_count)] = E.value().recursive_duplicate(true, recursion_count); + for (const KeyValue &E : _p->variant_map) { + n[E.key.recursive_duplicate(true, recursion_count)] = E.value.recursive_duplicate(true, recursion_count); } } else { - for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - n[E.key()] = E.value(); + for (const KeyValue &E : _p->variant_map) { + n[E.key] = E.value; } } diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml index 754518239c0..9c943b8c8bb 100644 --- a/doc/classes/DirectionalLight3D.xml +++ b/doc/classes/DirectionalLight3D.xml @@ -34,7 +34,6 @@ The distance from shadow split 2 to split 3. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [constant SHADOW_PARALLEL_4_SPLITS]. - Set whether this [DirectionalLight3D] is visible in the sky, in the scene, or both in the sky and in the scene. See [enum SkyMode] for options. diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index b7822f1bb0f..4d8fd63257d 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -80,7 +80,7 @@ The intensity of the specular blob in objects affected by the light. At [code]0[/code], the light becomes a pure diffuse light. When not baking emission, this can be used to avoid unrealistic reflections when placing lights above an emissive surface. - + Used to adjust shadow appearance. Too small a value results in self-shadowing ("shadow acne"), while too large a value causes shadows to separate from casters ("peter-panning"). Adjust as needed. diff --git a/doc/classes/OmniLight3D.xml b/doc/classes/OmniLight3D.xml index f83d31a9b5b..ce63dbdbc14 100644 --- a/doc/classes/OmniLight3D.xml +++ b/doc/classes/OmniLight3D.xml @@ -19,6 +19,7 @@ See [enum ShadowMode]. + diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index d14d26346c2..d4bb551704f 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -2077,10 +2077,9 @@ Vector MaterialStorage::global_variable_get_list() const { ERR_FAIL_V_MSG(Vector(), "This function should never be used outside the editor, it can severely damage performance."); } - const StringName *K = nullptr; Vector names; - while ((K = global_variables.variables.next(K))) { - names.push_back(*K); + for (const KeyValue &E : global_variables.variables) { + names.push_back(E.key); } names.sort_custom(); return names; diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index c821561ca64..87cbd9423c3 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -97,9 +97,9 @@ void EditorPerformanceProfiler::_monitor_select() { void EditorPerformanceProfiler::_monitor_draw() { Vector active; - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { - if (i.value().item->is_checked(0)) { - active.push_back(i.key()); + for (const KeyValue &E : monitors) { + if (E.value.item->is_checked(0)) { + active.push_back(E.key); } } @@ -204,22 +204,22 @@ void EditorPerformanceProfiler::_monitor_draw() { void EditorPerformanceProfiler::_build_monitor_tree() { Set monitor_checked; - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { - if (i.value().item && i.value().item->is_checked(0)) { - monitor_checked.insert(i.key()); + for (KeyValue &E : monitors) { + if (E.value.item && E.value.item->is_checked(0)) { + monitor_checked.insert(E.key); } } base_map.clear(); monitor_tree->get_root()->clear_children(); - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { - TreeItem *base = _get_monitor_base(i.value().base); - TreeItem *item = _create_monitor_item(i.value().name, base); - item->set_checked(0, monitor_checked.has(i.key())); - i.value().item = item; - if (!i.value().history.is_empty()) { - i.value().update_value(i.value().history.front()->get()); + for (KeyValue &E : monitors) { + TreeItem *base = _get_monitor_base(E.value.base); + TreeItem *item = _create_monitor_item(E.value.name, base); + item->set_checked(0, monitor_checked.has(E.key)); + E.value.item = item; + if (!E.value.history.is_empty()) { + E.value.update_value(E.value.history.front()->get()); } } } @@ -252,9 +252,9 @@ void EditorPerformanceProfiler::_marker_input(const Ref &p_event) { Ref mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { Vector active; - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { - if (i.value().item->is_checked(0)) { - active.push_back(i.key()); + for (KeyValue &E : monitors) { + if (E.value.item->is_checked(0)) { + active.push_back(E.key); } } if (active.size() > 0) { @@ -293,12 +293,16 @@ void EditorPerformanceProfiler::_marker_input(const Ref &p_event) { } void EditorPerformanceProfiler::reset() { - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { - if (String(i.key()).begins_with("custom:")) { - monitors.erase(i); + HashMap::Iterator E = monitors.begin(); + while (E != monitors.end()) { + HashMap::Iterator N = E; + ++N; + if (String(E->key).begins_with("custom:")) { + monitors.remove(E); } else { - i.value().reset(); + E->value.reset(); } + E = N; } _build_monitor_tree(); @@ -308,43 +312,49 @@ void EditorPerformanceProfiler::reset() { } void EditorPerformanceProfiler::update_monitors(const Vector &p_names) { - OrderedHashMap names; + HashMap names; for (int i = 0; i < p_names.size(); i++) { names.insert("custom:" + p_names[i], Performance::MONITOR_MAX + i); } - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { - if (String(i.key()).begins_with("custom:")) { - if (!names.has(i.key())) { - monitors.erase(i); - } else { - i.value().frame_index = names[i.key()]; - names.erase(i.key()); + { + HashMap::Iterator E = monitors.begin(); + while (E != monitors.end()) { + HashMap::Iterator N = E; + ++N; + if (String(E->key).begins_with("custom:")) { + if (!names.has(E->key)) { + monitors.remove(E); + } else { + E->value.frame_index = names[E->key]; + names.erase(E->key); + } } + E = N; } } - for (OrderedHashMap::Element i = names.front(); i; i = i.next()) { - String name = String(i.key()).replace_first("custom:", ""); + for (const KeyValue &E : names) { + String name = String(E.key).replace_first("custom:", ""); String base = "Custom"; if (name.get_slice_count("/") == 2) { base = name.get_slicec('/', 0); name = name.get_slicec('/', 1); } - monitors.insert(i.key(), Monitor(name, base, i.value(), Performance::MONITOR_TYPE_QUANTITY, nullptr)); + monitors.insert(E.key, Monitor(name, base, E.value, Performance::MONITOR_TYPE_QUANTITY, nullptr)); } _build_monitor_tree(); } void EditorPerformanceProfiler::add_profile_frame(const Vector &p_values) { - for (OrderedHashMap::Element i = monitors.front(); i; i = i.next()) { + for (KeyValue &E : monitors) { float data = 0.0f; - if (i.value().frame_index >= 0 && i.value().frame_index < p_values.size()) { - data = p_values[i.value().frame_index]; + if (E.value.frame_index >= 0 && E.value.frame_index < p_values.size()) { + data = p_values[E.value.frame_index]; } - i.value().history.push_front(data); - i.value().update_value(data); + E.value.history.push_front(data); + E.value.update_value(data); } marker_frame++; monitor_draw->update(); diff --git a/editor/debugger/editor_performance_profiler.h b/editor/debugger/editor_performance_profiler.h index ab0e43de2f4..21d2a528206 100644 --- a/editor/debugger/editor_performance_profiler.h +++ b/editor/debugger/editor_performance_profiler.h @@ -31,8 +31,8 @@ #ifndef EDITOR_PERFORMANCE_PROFILER_H #define EDITOR_PERFORMANCE_PROFILER_H +#include "core/templates/hash_map.h" #include "core/templates/map.h" -#include "core/templates/ordered_hash_map.h" #include "main/performance.h" #include "scene/gui/control.h" #include "scene/gui/label.h" @@ -59,7 +59,7 @@ private: void reset(); }; - OrderedHashMap monitors; + HashMap monitors; Map base_map; Tree *monitor_tree = nullptr; diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index d13d1a6c680..bb82da66664 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -57,20 +57,19 @@ float EditorCommandPalette::_score_path(const String &p_search, const String &p_ } void EditorCommandPalette::_update_command_search(const String &search_text) { - commands.get_key_list(&command_keys); - ERR_FAIL_COND(command_keys.is_empty()); + ERR_FAIL_COND(commands.size() == 0); Map sections; TreeItem *first_section = nullptr; // Filter possible candidates. Vector entries; - for (int i = 0; i < command_keys.size(); i++) { + for (const KeyValue &E : commands) { CommandEntry r; - r.key_name = command_keys[i]; - r.display_name = commands[r.key_name].name; - r.shortcut_text = commands[r.key_name].shortcut; - r.last_used = commands[r.key_name].last_used; + r.key_name = E.key; + r.display_name = E.value.name; + r.shortcut_text = E.value.shortcut; + r.last_used = E.value.last_used; if (search_text.is_subsequence_ofn(r.display_name)) { if (!search_text.is_empty()) { @@ -180,7 +179,9 @@ void EditorCommandPalette::open_popup() { } void EditorCommandPalette::get_actions_list(List *p_list) const { - commands.get_key_list(p_list); + for (const KeyValue &E : commands) { + p_list->push_back(E.key); + } } void EditorCommandPalette::remove_command(String p_key_name) { @@ -229,17 +230,14 @@ void EditorCommandPalette::execute_command(String &p_command_key) { } void EditorCommandPalette::register_shortcuts_as_command() { - const String *key = nullptr; - key = unregistered_shortcuts.next(key); - while (key != nullptr) { - String command_name = unregistered_shortcuts[*key].first; - Ref shortcut = unregistered_shortcuts[*key].second; + for (const KeyValue>> &E : unregistered_shortcuts) { + String command_name = E.value.first; + Ref shortcut = E.value.second; Ref ev; ev.instantiate(); ev->set_shortcut(shortcut); String shortcut_text = String(shortcut->get_as_text()); - add_command(command_name, *key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_unhandled_input), varray(ev, false), shortcut_text); - key = unregistered_shortcuts.next(key); + add_command(command_name, E.key, callable_mp(EditorNode::get_singleton()->get_viewport(), &Viewport::push_unhandled_input), varray(ev, false), shortcut_text); } unregistered_shortcuts.clear(); @@ -276,12 +274,10 @@ void EditorCommandPalette::_theme_changed() { void EditorCommandPalette::_save_history() const { Dictionary command_history; - List command_keys; - commands.get_key_list(&command_keys); - for (const String &key : command_keys) { - if (commands[key].last_used > 0) { - command_history[key] = commands[key].last_used; + for (const KeyValue &E : commands) { + if (E.value.last_used > 0) { + command_history[E.key] = E.value.last_used; } } EditorSettings::get_singleton()->set_project_metadata("command_palette", "command_history", command_history); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 7ce483d7884..f770af8100c 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -945,13 +945,10 @@ void EditorData::script_class_set_name(const String &p_path, const StringName &p } void EditorData::script_class_save_icon_paths() { - List keys; - _script_class_icon_paths.get_key_list(&keys); - Dictionary d; - for (const StringName &E : keys) { - if (ScriptServer::is_global_class(E)) { - d[E] = _script_class_icon_paths[E]; + for (const KeyValue &E : _script_class_icon_paths) { + if (ScriptServer::is_global_class(E.key)) { + d[E.key] = E.value; } } diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index d89bb0959c0..14a8c46a795 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -31,7 +31,7 @@ #ifndef EDITOR_HELP_SEARCH_H #define EDITOR_HELP_SEARCH_H -#include "core/templates/ordered_hash_map.h" +#include "core/templates/map.h" #include "editor/code_editor.h" #include "editor/editor_help.h" #include "editor/editor_plugin.h" diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index bdabff20f99..5d846028c51 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -141,7 +141,7 @@ bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "shortcuts") { Array save_array; - const OrderedHashMap>> &builtin_list = InputMap::get_singleton()->get_builtins(); + const HashMap>> &builtin_list = InputMap::get_singleton()->get_builtins(); for (const KeyValue> &shortcut_definition : shortcuts) { Ref sc = shortcut_definition.value; @@ -244,18 +244,17 @@ struct _EVCSort { void EditorSettings::_get_property_list(List *p_list) const { _THREAD_SAFE_METHOD_ - const String *k = nullptr; Set<_EVCSort> vclist; - while ((k = props.next(k))) { - const VariantContainer *v = props.getptr(*k); + for (const KeyValue &E : props) { + const VariantContainer *v = &E.value; if (v->hide_from_editor) { continue; } _EVCSort vc; - vc.name = *k; + vc.name = E.key; vc.order = v->order; vc.type = v->variant.get_type(); vc.save = v->save; @@ -789,7 +788,11 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { Ref cf = memnew(ConfigFile); // hex is better? List keys; - props.get_key_list(&keys); + + for (const KeyValue &E : props) { + keys.push_back(E.key); + } + keys.sort(); for (const String &key : keys) { @@ -1421,10 +1424,10 @@ Ref EditorSettings::get_shortcut(const String &p_name) const { // If there was no override, check the default builtins to see if it has an InputEvent for the provided name. if (sc.is_null()) { - const OrderedHashMap>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name); + const HashMap>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name); if (builtin_default) { sc.instantiate(); - sc->set_events_list(&builtin_default.get()); + sc->set_events_list(&builtin_default->value); sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name)); } } @@ -1562,9 +1565,9 @@ void EditorSettings::set_builtin_action_override(const String &p_name, const Arr // Check if the provided event array is same as built-in. If it is, it does not need to be added to the overrides. // Note that event order must also be the same. bool same_as_builtin = true; - OrderedHashMap>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name); + HashMap>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name); if (builtin_default) { - List> builtin_events = builtin_default.get(); + const List> &builtin_events = builtin_default->value; // In the editor we only care about key events. List> builtin_key_events; diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index ab029c1d306..94775f8c763 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -248,11 +248,11 @@ void EditorSettingsDialog::_update_shortcut_events(const String &p_path, const A undo_redo->commit_action(); } -Array EditorSettingsDialog::_event_list_to_array_helper(List> &p_events) { +Array EditorSettingsDialog::_event_list_to_array_helper(const List> &p_events) { Array events; // Convert the list to an array, and only keep key events as this is for the editor. - for (List>::Element *E = p_events.front(); E; E = E->next()) { + for (const List>::Element *E = p_events.front(); E; E = E->next()) { Ref k = E->get(); if (k.is_valid()) { events.append(E->get()); @@ -374,10 +374,9 @@ void EditorSettingsDialog::_update_shortcuts() { common_section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); // Get the action map for the editor, and add each item to the "Common" section. - OrderedHashMap action_map = InputMap::get_singleton()->get_action_map(); - for (OrderedHashMap::Element E = action_map.front(); E; E = E.next()) { - String action_name = E.key(); - InputMap::Action action = E.get(); + for (const KeyValue &E : InputMap::get_singleton()->get_action_map()) { + const String &action_name = E.key; + const InputMap::Action &action = E.value; Array events; // Need to get the list of events into an array so it can be set as metadata on the item. Vector event_strings; @@ -387,10 +386,10 @@ void EditorSettingsDialog::_update_shortcuts() { continue; } - List> all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name).value(); + const List> &all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name)->value; List> key_default_events; // Remove all non-key events from the defaults. Only check keys, since we are in the editor. - for (List>::Element *I = all_default_events.front(); I; I = I->next()) { + for (const List>::Element *I = all_default_events.front(); I; I = I->next()) { Ref k = I->get(); if (k.is_valid()) { key_default_events.push_back(k); diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h index 9a34eac7ef1..294186a5094 100644 --- a/editor/editor_settings_dialog.h +++ b/editor/editor_settings_dialog.h @@ -89,7 +89,7 @@ class EditorSettingsDialog : public AcceptDialog { void _event_config_confirmed(); void _create_shortcut_treeitem(TreeItem *p_parent, const String &p_shortcut_identifier, const String &p_display, Array &p_events, bool p_allow_revert, bool p_is_common, bool p_is_collapsed); - Array _event_list_to_array_helper(List> &p_events); + Array _event_list_to_array_helper(const List> &p_events); void _update_builtin_action(const String &p_name, const Array &p_events); void _update_shortcut_events(const String &p_path, const Array &p_events); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index ddde6bf1440..43b52177c65 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1737,7 +1737,7 @@ void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, Ani p_player->get_animation_list(&anims); Node *parent = p_player->get_parent(); ERR_FAIL_COND(parent == nullptr); - OrderedHashMap used_tracks[TRACK_CHANNEL_MAX]; + HashMap used_tracks[TRACK_CHANNEL_MAX]; bool tracks_to_add = false; static const Animation::TrackType track_types[TRACK_CHANNEL_MAX] = { Animation::TYPE_POSITION_3D, Animation::TYPE_ROTATION_3D, Animation::TYPE_SCALE_3D, Animation::TYPE_BLEND_SHAPE }; for (const StringName &I : anims) { @@ -1790,12 +1790,12 @@ void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, Ani used_tracks[j][path] = pass; } - for (OrderedHashMap::Element J = used_tracks[j].front(); J; J = J.next()) { - if (J.get() == pass) { + for (const KeyValue &J : used_tracks[j]) { + if (J.value == pass) { continue; } - NodePath path = J.key(); + NodePath path = J.key; Node *n = parent->get_node(path); if (j == TRACK_CHANNEL_BLEND_SHAPE) { diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index f859ceda3b8..4df329a2c55 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -31,8 +31,8 @@ #ifndef NODE_3D_EDITOR_GIZMOS_H #define NODE_3D_EDITOR_GIZMOS_H +#include "core/templates/hash_map.h" #include "core/templates/local_vector.h" -#include "core/templates/ordered_hash_map.h" #include "scene/3d/camera_3d.h" #include "scene/3d/node_3d.h" #include "scene/3d/skeleton_3d.h" diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 5240fdf8363..8d29e04eec6 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -119,9 +119,9 @@ void EditorStandardSyntaxHighlighter::_update_cache() { } /* Autoloads. */ - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.value(); + HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + for (const KeyValue &E : autoloads) { + const ProjectSettings::AutoloadInfo &info = E.value; if (info.is_singleton) { highlighter->add_keyword_color(info.name, usertype_color); } diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 87f8c4b165b..41a599e933d 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -2339,8 +2339,8 @@ void ThemeTypeEditor::_update_type_list_debounced() { update_debounce_timer->start(); } -OrderedHashMap ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List *) const, bool include_default) { - OrderedHashMap items; +HashMap ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List *) const, bool include_default) { + HashMap items; List names; if (include_default) { @@ -2367,12 +2367,12 @@ OrderedHashMap ThemeTypeEditor::_get_type_items(String p_type_ } List keys; - for (OrderedHashMap::Element E = items.front(); E; E = E.next()) { - keys.push_back(E.key()); + for (const KeyValue &E : items) { + keys.push_back(E.key); } keys.sort_custom(); - OrderedHashMap ordered_items; + HashMap ordered_items; for (const StringName &E : keys) { ordered_items[E] = items[E]; } @@ -2464,18 +2464,18 @@ void ThemeTypeEditor::_update_type_items() { color_items_list->remove_child(node); } - OrderedHashMap color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default); - for (OrderedHashMap::Element E = color_items.front(); E; E = E.next()) { - HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key(), E.get()); + HashMap color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default); + for (const KeyValue &E : color_items) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key, E.value); ColorPickerButton *item_editor = memnew(ColorPickerButton); item_editor->set_h_size_flags(SIZE_EXPAND_FILL); item_control->add_child(item_editor); - if (E.get()) { - item_editor->set_pick_color(edited_theme->get_color(E.key(), edited_type)); - item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed), varray(E.key())); + if (E.value) { + item_editor->set_pick_color(edited_theme->get_color(E.key, edited_type)); + item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed), varray(E.key)); } else { - item_editor->set_pick_color(Theme::get_default()->get_color(E.key(), edited_type)); + item_editor->set_pick_color(Theme::get_default()->get_color(E.key, edited_type)); item_editor->set_disabled(true); } @@ -2492,9 +2492,9 @@ void ThemeTypeEditor::_update_type_items() { constant_items_list->remove_child(node); } - OrderedHashMap constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default); - for (OrderedHashMap::Element E = constant_items.front(); E; E = E.next()) { - HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key(), E.get()); + HashMap constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default); + for (const KeyValue &E : constant_items) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key, E.value); SpinBox *item_editor = memnew(SpinBox); item_editor->set_h_size_flags(SIZE_EXPAND_FILL); item_editor->set_min(-100000); @@ -2504,11 +2504,11 @@ void ThemeTypeEditor::_update_type_items() { item_editor->set_allow_greater(true); item_control->add_child(item_editor); - if (E.get()) { - item_editor->set_value(edited_theme->get_constant(E.key(), edited_type)); - item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed), varray(E.key())); + if (E.value) { + item_editor->set_value(edited_theme->get_constant(E.key, edited_type)); + item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed), varray(E.key)); } else { - item_editor->set_value(Theme::get_default()->get_constant(E.key(), edited_type)); + item_editor->set_value(Theme::get_default()->get_constant(E.key, edited_type)); item_editor->set_editable(false); } @@ -2525,25 +2525,25 @@ void ThemeTypeEditor::_update_type_items() { font_items_list->remove_child(node); } - OrderedHashMap font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default); - for (OrderedHashMap::Element E = font_items.front(); E; E = E.next()) { - HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key(), E.get()); + HashMap font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default); + for (const KeyValue &E : font_items) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key, E.value); EditorResourcePicker *item_editor = memnew(EditorResourcePicker); item_editor->set_h_size_flags(SIZE_EXPAND_FILL); item_editor->set_base_type("Font"); item_control->add_child(item_editor); - if (E.get()) { - if (edited_theme->has_font(E.key(), edited_type)) { - item_editor->set_edited_resource(edited_theme->get_font(E.key(), edited_type)); + if (E.value) { + if (edited_theme->has_font(E.key, edited_type)) { + item_editor->set_edited_resource(edited_theme->get_font(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); - item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed), varray(E.key())); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed), varray(E.key)); } else { - if (Theme::get_default()->has_font(E.key(), edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_font(E.key(), edited_type)); + if (Theme::get_default()->has_font(E.key, edited_type)) { + item_editor->set_edited_resource(Theme::get_default()->get_font(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } @@ -2563,9 +2563,9 @@ void ThemeTypeEditor::_update_type_items() { font_size_items_list->remove_child(node); } - OrderedHashMap font_size_items = _get_type_items(edited_type, &Theme::get_font_size_list, show_default); - for (OrderedHashMap::Element E = font_size_items.front(); E; E = E.next()) { - HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT_SIZE, E.key(), E.get()); + HashMap font_size_items = _get_type_items(edited_type, &Theme::get_font_size_list, show_default); + for (const KeyValue &E : font_size_items) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT_SIZE, E.key, E.value); SpinBox *item_editor = memnew(SpinBox); item_editor->set_h_size_flags(SIZE_EXPAND_FILL); item_editor->set_min(-100000); @@ -2575,11 +2575,11 @@ void ThemeTypeEditor::_update_type_items() { item_editor->set_allow_greater(true); item_control->add_child(item_editor); - if (E.get()) { - item_editor->set_value(edited_theme->get_font_size(E.key(), edited_type)); - item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed), varray(E.key())); + if (E.value) { + item_editor->set_value(edited_theme->get_font_size(E.key, edited_type)); + item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed), varray(E.key)); } else { - item_editor->set_value(Theme::get_default()->get_font_size(E.key(), edited_type)); + item_editor->set_value(Theme::get_default()->get_font_size(E.key, edited_type)); item_editor->set_editable(false); } @@ -2596,25 +2596,25 @@ void ThemeTypeEditor::_update_type_items() { icon_items_list->remove_child(node); } - OrderedHashMap icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default); - for (OrderedHashMap::Element E = icon_items.front(); E; E = E.next()) { - HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key(), E.get()); + HashMap icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default); + for (const KeyValue &E : icon_items) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key, E.value); EditorResourcePicker *item_editor = memnew(EditorResourcePicker); item_editor->set_h_size_flags(SIZE_EXPAND_FILL); item_editor->set_base_type("Texture2D"); item_control->add_child(item_editor); - if (E.get()) { - if (edited_theme->has_icon(E.key(), edited_type)) { - item_editor->set_edited_resource(edited_theme->get_icon(E.key(), edited_type)); + if (E.value) { + if (edited_theme->has_icon(E.key, edited_type)) { + item_editor->set_edited_resource(edited_theme->get_icon(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); - item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed), varray(E.key())); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed), varray(E.key)); } else { - if (Theme::get_default()->has_icon(E.key(), edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key(), edited_type)); + if (Theme::get_default()->has_icon(E.key, edited_type)) { + item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } @@ -2664,26 +2664,26 @@ void ThemeTypeEditor::_update_type_items() { stylebox_items_list->add_child(memnew(HSeparator)); } - OrderedHashMap stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default); - for (OrderedHashMap::Element E = stylebox_items.front(); E; E = E.next()) { - if (leading_stylebox.pinned && leading_stylebox.item_name == E.key()) { + HashMap stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default); + for (const KeyValue &E : stylebox_items) { + if (leading_stylebox.pinned && leading_stylebox.item_name == E.key) { continue; } - HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key(), E.get()); + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key, E.value); EditorResourcePicker *item_editor = memnew(EditorResourcePicker); item_editor->set_h_size_flags(SIZE_EXPAND_FILL); item_editor->set_stretch_ratio(1.5); item_editor->set_base_type("StyleBox"); - if (E.get()) { - if (edited_theme->has_stylebox(E.key(), edited_type)) { - item_editor->set_edited_resource(edited_theme->get_stylebox(E.key(), edited_type)); + if (E.value) { + if (edited_theme->has_stylebox(E.key, edited_type)) { + item_editor->set_edited_resource(edited_theme->get_stylebox(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); - item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(E.key())); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(E.key)); Button *pin_leader_button = memnew(Button); pin_leader_button->set_flat(true); @@ -2691,10 +2691,10 @@ void ThemeTypeEditor::_update_type_items() { pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"))); pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type.")); item_control->add_child(pin_leader_button); - pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed), varray(item_editor, E.key())); + pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed), varray(item_editor, E.key)); } else { - if (Theme::get_default()->has_stylebox(E.key(), edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key(), edited_type)); + if (Theme::get_default()->has_stylebox(E.key, edited_type)) { + item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index 3894ca31e5c..6debf00e90b 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -363,7 +363,7 @@ class ThemeTypeEditor : public MarginContainer { VBoxContainer *_create_item_list(Theme::DataType p_data_type); void _update_type_list(); void _update_type_list_debounced(); - OrderedHashMap _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List *) const, bool include_default); + HashMap _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List *) const, bool include_default); HBoxContainer *_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable); void _add_focusable(Control *p_control); void _update_type_items(); diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp index 0835d0212fc..e684d9a5e67 100644 --- a/editor/pot_generator.cpp +++ b/editor/pot_generator.cpp @@ -39,7 +39,7 @@ POTGenerator *POTGenerator::singleton = nullptr; #ifdef DEBUG_POT void POTGenerator::_print_all_translation_strings() { - for (OrderedHashMap>::Element E = all_translation_strings.front(); E; E = E.next()) { + for (HashMap>::Element E = all_translation_strings.front(); E; E = E.next()) { Vector v_md = all_translation_strings[E.key()]; for (int i = 0; i < v_md.size(); i++) { print_line("++++++"); @@ -121,9 +121,9 @@ void POTGenerator::_write_to_pot(const String &p_file) { file->store_string(header); - for (OrderedHashMap>::Element E_pair = all_translation_strings.front(); E_pair; E_pair = E_pair.next()) { - String msgid = E_pair.key(); - Vector v_msgid_data = E_pair.value(); + for (const KeyValue> &E_pair : all_translation_strings) { + String msgid = E_pair.key; + const Vector &v_msgid_data = E_pair.value; for (int i = 0; i < v_msgid_data.size(); i++) { String context = v_msgid_data[i].ctx; String plural = v_msgid_data[i].plural; diff --git a/editor/pot_generator.h b/editor/pot_generator.h index e7a5f90cee4..05d1903dd6e 100644 --- a/editor/pot_generator.h +++ b/editor/pot_generator.h @@ -32,7 +32,7 @@ #define POT_GENERATOR_H #include "core/io/file_access.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" #include "core/templates/set.h" //#define DEBUG_POT @@ -46,7 +46,7 @@ class POTGenerator { Set locations; }; // Store msgid as key and the additional data around the msgid - if it's under a context, has plurals and its file locations. - OrderedHashMap> all_translation_strings; + HashMap> all_translation_strings; void _write_to_pot(const String &p_file); void _write_msgid(Ref r_file, const String &p_id, bool p_plural); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index f684c0e0c94..48cd975715b 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -420,7 +420,7 @@ void ProjectSettingsEditor::_action_reordered(const String &p_action_name, const Variant target_value = ps->get(target_name); List props; - OrderedHashMap action_values; + HashMap action_values; ProjectSettings::get_singleton()->get_property_list(&props); undo_redo->create_action(TTR("Update Input Action Order")); @@ -437,9 +437,9 @@ void ProjectSettingsEditor::_action_reordered(const String &p_action_name, const undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", prop.name); } - for (OrderedHashMap::Element E = action_values.front(); E; E = E.next()) { - String name = E.key(); - Variant value = E.get(); + for (const KeyValue &E : action_values) { + String name = E.key; + const Variant &value = E.value; if (name == target_name) { if (p_before) { diff --git a/main/main.cpp b/main/main.cpp index 75c4433b41e..9747f5aa11f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2329,11 +2329,11 @@ bool Main::start() { if (!project_manager && !editor) { // game if (!game_path.is_empty() || !script.is_empty()) { //autoload - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); //first pass, add the constants so they exist before any script is loaded - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + for (const KeyValue &E : autoloads) { + const ProjectSettings::AutoloadInfo &info = E.value; if (info.is_singleton) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { @@ -2344,8 +2344,8 @@ bool Main::start() { //second pass, load into global constants List to_add; - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + for (const KeyValue &E : autoloads) { + const ProjectSettings::AutoloadInfo &info = E.value; Ref res = ResourceLoader::load(info.path); ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path); diff --git a/main/performance.cpp b/main/performance.cpp index e80906b4a72..25659b999f0 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -247,8 +247,8 @@ Array Performance::get_custom_monitor_names() { Array return_array; return_array.resize(_monitor_map.size()); int index = 0; - for (OrderedHashMap::Element i = _monitor_map.front(); i; i = i.next()) { - return_array.set(index, i.key()); + for (KeyValue i : _monitor_map) { + return_array.set(index, i.key); index++; } return return_array; diff --git a/main/performance.h b/main/performance.h index 927b5b0389e..2837d8f512b 100644 --- a/main/performance.h +++ b/main/performance.h @@ -32,7 +32,7 @@ #define PERFORMANCE_H #include "core/object/class_db.h" -#include "core/templates/ordered_hash_map.h" +#include "core/templates/hash_map.h" #define PERF_WARN_OFFLINE_FUNCTION #define PERF_WARN_PROCESS_SYNC @@ -58,7 +58,7 @@ class Performance : public Object { Variant call(bool &r_error, String &r_error_message); }; - OrderedHashMap _monitor_map; + HashMap _monitor_map; uint64_t _monitor_modification_time; public: diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index e3f0ddfc35f..191568661d0 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -510,9 +510,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { } /* Autoloads. */ - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.value(); + for (const KeyValue &E : ProjectSettings::get_singleton()->get_autoload_list()) { + const ProjectSettings::AutoloadInfo &info = E.value; if (info.is_singleton) { keywords[info.name] = usertype_color; } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index d3462649338..85ad08ea4f9 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -4218,13 +4218,11 @@ Error GDScriptAnalyzer::resolve_program() { resolve_class_interface(parser->head); resolve_class_body(parser->head); - List parser_keys; - depended_parsers.get_key_list(&parser_keys); - for (const String &E : parser_keys) { - if (depended_parsers[E].is_null()) { + for (KeyValue> &K : depended_parsers) { + if (K.value.is_null()) { return ERR_PARSE_ERROR; } - depended_parsers[E]->raise_status(GDScriptParserRef::FULLY_SOLVED); + K.value->raise_status(GDScriptParserRef::FULLY_SOLVED); } return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR; } diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index e72069bcd5b..3d5a39bf381 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -196,10 +196,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { function->_constant_count = constant_map.size(); function->constants.resize(constant_map.size()); function->_constants_ptr = function->constants.ptrw(); - const Variant *K = nullptr; - while ((K = constant_map.next(K))) { - int idx = constant_map[*K]; - function->constants.write[idx] = *K; + for (const KeyValue &K : constant_map) { + function->constants.write[K.value] = K.key; } } else { function->_constants_ptr = nullptr; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 37a988ee4cc..c194fbf9b8f 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -336,7 +336,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { // If it's an autoload singleton, we postpone to load it at runtime. // This is so one autoload doesn't try to load another before it's compiled. - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); if (autoloads.has(identifier) && autoloads[identifier].is_singleton) { GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype())); int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 0197bf9ea37..7021f0aa1e3 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -851,9 +851,10 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio } // Autoload singletons - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + + for (const KeyValue &E : autoloads) { + const ProjectSettings::AutoloadInfo &info = E.value; if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") { continue; } @@ -1219,12 +1220,11 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context r_result.insert(option.display, option); } - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - if (!E.value().is_singleton) { + for (const KeyValue &E : ProjectSettings::get_singleton()->get_autoload_list()) { + if (!E.value.is_singleton) { continue; } - ScriptLanguage::CodeCompletionOption option(E.key(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + ScriptLanguage::CodeCompletionOption option(E.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); r_result.insert(option.display, option); } @@ -1517,12 +1517,10 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]); found = true; } else { - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - String name = E.key(); + for (const KeyValue &E : ProjectSettings::get_singleton()->get_autoload_list()) { + String name = E.key; if (name == which) { - String script = E.value().path; + String script = E.value.path; if (!script.begins_with("res://")) { script = "res://" + script; @@ -2882,10 +2880,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } // Get autoloads. - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - String path = "/root/" + E.key(); + for (const KeyValue &E : ProjectSettings::get_singleton()->get_autoload_list()) { + String path = "/root/" + E.key; ScriptLanguage::CodeCompletionOption option(path.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH); options.insert(option.display, option); } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a2dc9bb8a85..b6bf523a67e 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -100,10 +100,8 @@ void GDScriptParser::cleanup() { } void GDScriptParser::get_annotation_list(List *r_annotations) const { - List keys; - valid_annotations.get_key_list(&keys); - for (const StringName &E : keys) { - r_annotations->push_back(valid_annotations[E].info); + for (const KeyValue &E : valid_annotations) { + r_annotations->push_back(E.value.info); } } @@ -1894,11 +1892,8 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { SuiteNode *suite = alloc_node(); if (branch->patterns.size() > 0) { - List binds; - branch->patterns[0]->binds.get_key_list(&binds); - - for (const StringName &E : binds) { - SuiteNode::Local local(branch->patterns[0]->binds[E], current_function); + for (const KeyValue &E : branch->patterns[0]->binds) { + SuiteNode::Local local(E.value, current_function); local.type = SuiteNode::Local::PATTERN_BIND; suite->add_local(local); } @@ -3566,14 +3561,15 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint = PROPERTY_HINT_ENUM; String enum_hint_string; - for (OrderedHashMap::Element E = export_type.enum_values.front(); E; E = E.next()) { - enum_hint_string += E.key().operator String().capitalize().xml_escape(); - enum_hint_string += ":"; - enum_hint_string += String::num_int64(E.value()).xml_escape(); - - if (E.next()) { + bool first = true; + for (const KeyValue &E : export_type.enum_values) { + if (!first) { enum_hint_string += ","; + first = false; } + enum_hint_string += E.key.operator String().capitalize().xml_escape(); + enum_hint_string += ":"; + enum_hint_string += String::num_int64(E.value).xml_escape(); } variable->export_info.hint_string = enum_hint_string; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index ab05ac5f515..857e06440cc 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -132,7 +132,7 @@ public: ClassNode *class_type = nullptr; MethodInfo method_info; // For callable/signals. - OrderedHashMap enum_values; // For enums. + HashMap enum_values; // For enums. _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; } _FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; } diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 5516f59fe9d..bc1f001d861 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -89,16 +89,16 @@ void ExtendGDScriptParser::update_symbols() { for (int i = 0; i < class_symbol.children.size(); i++) { const lsp::DocumentSymbol &symbol = class_symbol.children[i]; - members.set(symbol.name, &symbol); + members.insert(symbol.name, &symbol); // cache level one inner classes if (symbol.kind == lsp::SymbolKind::Class) { ClassMembers inner_class; for (int j = 0; j < symbol.children.size(); j++) { const lsp::DocumentSymbol &s = symbol.children[j]; - inner_class.set(s.name, &s); + inner_class.insert(s.name, &s); } - inner_classes.set(symbol.name, inner_class); + inner_classes.insert(symbol.name, inner_class); } } } @@ -661,30 +661,22 @@ const List &ExtendGDScriptParser::get_document_links() const const Array &ExtendGDScriptParser::get_member_completions() { if (member_completions.is_empty()) { - const String *name = members.next(nullptr); - while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); + for (const KeyValue &E : members) { + const lsp::DocumentSymbol *symbol = E.value; lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(path, *name); + item.data = JOIN_SYMBOLS(path, E.key); member_completions.push_back(item.to_json()); - - name = members.next(name); } - const String *_class = inner_classes.next(nullptr); - while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); - const String *member_name = inner_class->next(nullptr); - while (member_name) { - const lsp::DocumentSymbol *symbol = inner_class->get(*member_name); + for (const KeyValue &E : inner_classes) { + const ClassMembers *inner_class = &E.value; + + for (const KeyValue &F : *inner_class) { + const lsp::DocumentSymbol *symbol = F.value; lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(*_class, *member_name)); + item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(E.key, F.key)); member_completions.push_back(item.to_json()); - - member_name = inner_class->next(member_name); } - - _class = inner_classes.next(_class); } } diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index cdddab319d6..7460f8edff7 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -126,7 +126,7 @@ Error GDScriptLanguageProtocol::on_client_connected() { ERR_FAIL_COND_V_MSG(clients.size() >= LSP_MAX_CLIENTS, FAILED, "Max client limits reached"); Ref peer = memnew(LSPeer); peer->connection = tcp_peer; - clients.set(next_client_id, peer); + clients.insert(next_client_id, peer); next_client_id++; EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR); return OK; @@ -229,28 +229,33 @@ void GDScriptLanguageProtocol::poll() { if (server->is_connection_available()) { on_client_connected(); } - const int *id = nullptr; - while ((id = clients.next(id))) { - Ref peer = clients.get(*id); + + HashMap>::Iterator E = clients.begin(); + while (E != clients.end()) { + Ref peer = E->value; StreamPeerTCP::Status status = peer->connection->get_status(); if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) { - on_client_disconnected(*id); - id = nullptr; + on_client_disconnected(E->key); + E = clients.begin(); + continue; } else { if (peer->connection->get_available_bytes() > 0) { - latest_client_id = *id; + latest_client_id = E->key; Error err = peer->handle_data(); if (err != OK && err != ERR_BUSY) { - on_client_disconnected(*id); - id = nullptr; + on_client_disconnected(E->key); + E = clients.begin(); + continue; } } Error err = peer->send_data(); if (err != OK && err != ERR_BUSY) { - on_client_disconnected(*id); - id = nullptr; + on_client_disconnected(E->key); + E = clients.begin(); + continue; } } + ++E; } } @@ -259,9 +264,8 @@ Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) { } void GDScriptLanguageProtocol::stop() { - const int *id = nullptr; - while ((id = clients.next(id))) { - Ref peer = clients.get(*id); + for (const KeyValue> &E : clients) { + Ref peer = clients.get(E.key); peer->connection->disconnect_from_host(); } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index c42bd58aeb9..1f029434801 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -109,23 +109,15 @@ void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol * void GDScriptTextDocument::initialize() { if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - const HashMap &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members; + for (const KeyValue &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members) { + const ClassMembers &members = E.value; - const StringName *class_ptr = native_members.next(nullptr); - while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); - - const String *name = members.next(nullptr); - while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); + for (const KeyValue &F : members) { + const lsp::DocumentSymbol *symbol = members.get(F.key); lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(String(*class_ptr), *name); + item.data = JOIN_SYMBOLS(String(E.key), F.key); native_member_completions.push_back(item.to_json()); - - name = members.next(name); } - - class_ptr = native_members.next(class_ptr); } } } diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 89ee6b35e5d..378dc6d04bb 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -404,9 +404,9 @@ Error GDScriptWorkspace::initialize() { const lsp::DocumentSymbol &class_symbol = E.value; for (int i = 0; i < class_symbol.children.size(); i++) { const lsp::DocumentSymbol &symbol = class_symbol.children[i]; - members.set(symbol.name, &symbol); + members.insert(symbol.name, &symbol); } - native_members.set(E.key, members); + native_members.insert(E.key, members); } // cache member completions @@ -682,13 +682,11 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP Vector2i offset; symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset); - const StringName *class_ptr = native_members.next(nullptr); - while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); + for (const KeyValue &E : native_members) { + const ClassMembers &members = native_members.get(E.key); if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) { r_list.push_back(*symbol); } - class_ptr = native_members.next(class_ptr); } for (const KeyValue &E : scripts) { @@ -698,15 +696,11 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP r_list.push_back(*symbol); } - const HashMap &inner_classes = script->get_inner_classes(); - const String *_class = inner_classes.next(nullptr); - while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); + for (const KeyValue &F : script->get_inner_classes()) { + const ClassMembers *inner_class = &F.value; if (const lsp::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) { r_list.push_back(*symbol); } - - _class = inner_classes.next(_class); } } } diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index ea519902378..71dc5de7e4c 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -48,11 +48,11 @@ namespace GDScriptTests { void init_autoloads() { - OrderedHashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list(); // First pass, add the constants so they exist before any script is loaded. - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + for (const KeyValue &E : ProjectSettings::get_singleton()->get_autoload_list()) { + const ProjectSettings::AutoloadInfo &info = E.value; if (info.is_singleton) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { @@ -62,8 +62,8 @@ void init_autoloads() { } // Second pass, load into global constants. - for (OrderedHashMap::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + for (const KeyValue &E : ProjectSettings::get_singleton()->get_autoload_list()) { + const ProjectSettings::AutoloadInfo &info = E.value; if (!info.is_singleton) { // Skip non-singletons since we don't have a scene tree here anyway. diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 9253f105bb5..3afde1e8d37 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -40,17 +40,12 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Dictionary classes_dict; - List names; + List class_list; + ClassDB::get_class_list(&class_list); + // Must be alphabetically sorted for hash to compute. + class_list.sort_custom(); - const StringName *k = nullptr; - - while ((k = ClassDB::classes.next(k))) { - names.push_back(*k); - } - //must be alphabetically sorted for hash to compute - names.sort_custom(); - - for (const StringName &E : names) { + for (const StringName &E : class_list) { ClassDB::ClassInfo *t = ClassDB::classes.getptr(E); ERR_FAIL_COND(!t); if (t->api != p_api || !t->exposed) { @@ -66,10 +61,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List snames; - k = nullptr; - - while ((k = t->method_map.next(k))) { - String name = k->operator String(); + for (const KeyValue &F : t->method_map) { + String name = F.key.operator String(); ERR_CONTINUE(name.is_empty()); @@ -77,7 +70,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { continue; // Ignore non-virtual methods that start with an underscore } - snames.push_back(*k); + snames.push_back(F.key); } snames.sort_custom(); @@ -131,10 +124,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List snames; - k = nullptr; - - while ((k = t->constant_map.next(k))) { - snames.push_back(*k); + for (const KeyValue &F : t->constant_map) { + snames.push_back(F.key); } snames.sort_custom(); @@ -158,10 +149,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List snames; - k = nullptr; - - while ((k = t->signal_map.next(k))) { - snames.push_back(*k); + for (const KeyValue &F : t->signal_map) { + snames.push_back(F.key); } snames.sort_custom(); @@ -193,10 +182,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List snames; - k = nullptr; - - while ((k = t->property_setget.next(k))) { - snames.push_back(*k); + for (const KeyValue &F : t->property_setget) { + snames.push_back(F.key); } snames.sort_custom(); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 5875a0fbd41..31257ac33a7 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1798,8 +1798,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List *p_properties) const { List props; - for (OrderedHashMap::ConstElement E = script->member_info.front(); E; E = E.next()) { - props.push_front(E.value()); + for (const KeyValue &E : script->member_info) { + props.push_front(E.value); } // Call _get_property_list @@ -3491,8 +3491,8 @@ Ref