소스 검색

Merge pull request #60881 from reduz/new-hash-map

Rémi Verschelde 3 년 전
부모
커밋
edda6ee9f8
95개의 변경된 파일1345개의 추가작업 그리고 1785개의 파일을 삭제
  1. 5 5
      core/config/project_settings.cpp
  2. 3 3
      core/config/project_settings.h
  3. 8 8
      core/input/input.cpp
  4. 20 20
      core/input/input_map.cpp
  5. 7 7
      core/input/input_map.h
  6. 15 12
      core/io/config_file.cpp
  7. 2 2
      core/io/config_file.h
  8. 2 2
      core/io/missing_resource.cpp
  9. 1 1
      core/io/missing_resource.h
  10. 6 11
      core/io/resource.cpp
  11. 11 11
      core/io/resource_uid.cpp
  12. 2 2
      core/io/resource_uid.h
  13. 42 75
      core/object/class_db.cpp
  14. 29 33
      core/object/object.cpp
  15. 2 3
      core/object/object.h
  16. 2 3
      core/object/script_language.cpp
  17. 8 0
      core/os/memory.h
  18. 13 27
      core/string/translation_po.cpp
  19. 402 373
      core/templates/hash_map.h
  20. 85 0
      core/templates/hashfuncs.h
  21. 0 301
      core/templates/ordered_hash_map.h
  22. 7 1
      core/templates/paged_allocator.h
  23. 46 39
      core/variant/dictionary.cpp
  24. 0 1
      doc/classes/DirectionalLight3D.xml
  25. 1 1
      doc/classes/Light3D.xml
  26. 1 0
      doc/classes/OmniLight3D.xml
  27. 2 3
      drivers/gles3/storage/material_storage.cpp
  28. 46 36
      editor/debugger/editor_performance_profiler.cpp
  29. 2 2
      editor/debugger/editor_performance_profiler.h
  30. 16 20
      editor/editor_command_palette.cpp
  31. 3 6
      editor/editor_data.cpp
  32. 1 1
      editor/editor_help_search.h
  33. 13 10
      editor/editor_settings.cpp
  34. 7 8
      editor/editor_settings_dialog.cpp
  35. 1 1
      editor/editor_settings_dialog.h
  36. 4 4
      editor/import/resource_importer_scene.cpp
  37. 1 1
      editor/plugins/node_3d_editor_gizmos.h
  38. 3 3
      editor/plugins/script_editor_plugin.cpp
  39. 55 55
      editor/plugins/theme_editor_plugin.cpp
  40. 1 1
      editor/plugins/theme_editor_plugin.h
  41. 4 4
      editor/pot_generator.cpp
  42. 2 2
      editor/pot_generator.h
  43. 4 4
      editor/project_settings_editor.cpp
  44. 5 5
      main/main.cpp
  45. 2 2
      main/performance.cpp
  46. 2 2
      main/performance.h
  47. 2 3
      modules/gdscript/editor/gdscript_highlighter.cpp
  48. 3 5
      modules/gdscript/gdscript_analyzer.cpp
  49. 2 4
      modules/gdscript/gdscript_byte_codegen.cpp
  50. 1 1
      modules/gdscript/gdscript_compiler.cpp
  51. 12 16
      modules/gdscript/gdscript_editor.cpp
  52. 11 15
      modules/gdscript/gdscript_parser.cpp
  53. 1 1
      modules/gdscript/gdscript_parser.h
  54. 12 20
      modules/gdscript/language_server/gdscript_extend_parser.cpp
  55. 18 14
      modules/gdscript/language_server/gdscript_language_protocol.cpp
  56. 5 13
      modules/gdscript/language_server/gdscript_text_document.cpp
  57. 6 12
      modules/gdscript/language_server/gdscript_workspace.cpp
  58. 5 5
      modules/gdscript/tests/gdscript_test_runner.cpp
  59. 14 27
      modules/mono/class_db_api_json.cpp
  60. 4 4
      modules/mono/csharp_script.cpp
  61. 1 1
      modules/mono/csharp_script.h
  62. 20 22
      modules/mono/editor/bindings_generator.cpp
  63. 1 1
      modules/mono/editor/bindings_generator.h
  64. 3 3
      modules/mono/editor/code_completion.cpp
  65. 10 15
      modules/mono/mono_gd/gd_mono.cpp
  66. 8 11
      modules/mono/mono_gd/gd_mono_class.cpp
  67. 7 10
      modules/raycast/raycast_occlusion_cull.cpp
  68. 4 6
      modules/text_server_adv/text_server_adv.cpp
  69. 4 6
      modules/text_server_fb/text_server_fb.cpp
  70. 5 7
      modules/visual_script/editor/visual_script_editor.cpp
  71. 66 93
      modules/visual_script/visual_script.cpp
  72. 10 15
      platform/iphone/export/export_plugin.cpp
  73. 14 20
      scene/animation/animation_tree.cpp
  74. 3 1
      scene/gui/code_edit.cpp
  75. 11 11
      scene/gui/graph_edit.cpp
  76. 2 2
      scene/main/missing_node.cpp
  77. 1 1
      scene/main/missing_node.h
  78. 5 7
      scene/main/scene_tree.cpp
  79. 9 11
      scene/main/shader_globals_override.cpp
  80. 3 3
      scene/multiplayer/multiplayer_spawner.cpp
  81. 2 4
      scene/multiplayer/scene_cache_interface.cpp
  82. 2 3
      scene/multiplayer/scene_replication_interface.cpp
  83. 8 12
      scene/multiplayer/scene_replication_state.cpp
  84. 2 2
      scene/multiplayer/scene_replication_state.h
  85. 4 4
      scene/resources/packed_scene.cpp
  86. 1 1
      scene/resources/surface_tool.cpp
  87. 88 194
      scene/resources/theme.cpp
  88. 2 3
      servers/rendering/renderer_rd/storage_rd/material_storage.cpp
  89. 7 8
      servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
  90. 3 3
      servers/rendering/rendering_server_default.cpp
  91. 2 2
      servers/rendering/rendering_server_default.h
  92. 1 1
      servers/rendering/shader_types.h
  93. 13 16
      tests/core/object/test_class_db.h
  94. 32 34
      tests/core/templates/test_hash_map.h
  95. 1 1
      tests/test_main.cpp

+ 5 - 5
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<StringName, ProjectSettings::AutoloadInfo> ProjectSettings::get_autoload_list() const {
+const HashMap<StringName, ProjectSettings::AutoloadInfo> &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<String, List<Ref<InputEvent>>> builtins = InputMap::get_singleton()->get_builtins();
+		HashMap<String, List<Ref<InputEvent>>> builtins = InputMap::get_singleton()->get_builtins();
 
-		for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+		for (KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
 			Array events;
 
 			// Convert list of input events into array
-			for (List<Ref<InputEvent>>::Element *I = E.get().front(); I; I = I->next()) {
+			for (List<Ref<InputEvent>>::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);
 		}

+ 3 - 3
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<String> custom_features;
 	Map<StringName, StringName> feature_overrides;
 
-	OrderedHashMap<StringName, AutoloadInfo> autoloads;
+	HashMap<StringName, AutoloadInfo> autoloads;
 
 	String project_data_dir_name;
 
@@ -181,7 +181,7 @@ public:
 
 	bool has_custom_feature(const String &p_feature) const;
 
-	OrderedHashMap<StringName, AutoloadInfo> get_autoload_list() const;
+	const HashMap<StringName, AutoloadInfo> &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;

+ 8 - 8
core/input/input.cpp

@@ -636,21 +636,21 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
 		}
 	}
 
-	for (OrderedHashMap<StringName, InputMap::Action>::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<StringName, InputMap::Action> &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);
 		}
 	}
 

+ 20 - 20
core/input/input_map.cpp

@@ -119,8 +119,8 @@ List<StringName> InputMap::get_actions() const {
 		return actions;
 	}
 
-	for (OrderedHashMap<StringName, Action>::Element E = input_map.front(); E; E = E.next()) {
-		actions.push_back(E.key());
+	for (const KeyValue<StringName, Action> &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<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) {
-	const OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
+	HashMap<StringName, Action>::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<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
@@ -216,7 +216,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
 }
 
 bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
-	OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
+	HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
 	ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
 
 	Ref<InputEventAction> input_event_action = p_event;
@@ -235,11 +235,11 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
 		return input_event_action->get_action() == p_action;
 	}
 
-	List<Ref<InputEvent>>::Element *event = _find_event(E.get(), p_event, p_exact_match, r_pressed, r_strength, r_raw_strength);
+	List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength);
 	return event != nullptr;
 }
 
-const OrderedHashMap<StringName, InputMap::Action> &InputMap::get_action_map() const {
+const HashMap<StringName, InputMap::Action> &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<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
+const HashMap<String, List<Ref<InputEvent>>> &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<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
 	return default_builtin_cache;
 }
 
-const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_feature_overrides_applied() {
+const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with_feature_overrides_applied() {
 	if (default_builtin_with_overrides_cache.size() > 0) {
 		return default_builtin_with_overrides_cache;
 	}
 
-	OrderedHashMap<String, List<Ref<InputEvent>>> builtins = get_builtins();
+	HashMap<String, List<Ref<InputEvent>>> 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<String, Vector<String>> builtins_with_overrides;
-	for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
-		String fullname = E.key();
+	for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
+		String fullname = E.key;
 
 		Vector<String> split = fullname.split(".");
 		String name = split[0];
@@ -709,8 +709,8 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins_with
 		}
 	}
 
-	for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
-		String fullname = E.key();
+	for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
+		String fullname = E.key;
 
 		Vector<String> split = fullname.split(".");
 		String name = split[0];
@@ -726,22 +726,22 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &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<String, List<Ref<InputEvent>>> builtins = get_builtins_with_feature_overrides_applied();
+	HashMap<String, List<Ref<InputEvent>>> builtins = get_builtins_with_feature_overrides_applied();
 
-	for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
-		String name = E.key();
+	for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
+		String name = E.key;
 
 		add_action(name);
 
-		List<Ref<InputEvent>> inputs = E.get();
-		for (List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
+		const List<Ref<InputEvent>> &inputs = E.value;
+		for (const List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
 			Ref<InputEventKey> iek = I->get();
 
 			// For the editor, only add keyboard actions.

+ 7 - 7
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<StringName, Action> input_map;
-	OrderedHashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
-	OrderedHashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
+	mutable HashMap<StringName, Action> input_map;
+	HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
+	HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
 
 	List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &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<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
 	bool event_get_action_status(const Ref<InputEvent> &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<StringName, Action> &get_action_map() const;
+	const HashMap<StringName, Action> &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<String, List<Ref<InputEvent>>> &get_builtins();
-	const OrderedHashMap<String, List<Ref<InputEvent>>> &get_builtins_with_feature_overrides_applied();
+	const HashMap<String, List<Ref<InputEvent>>> &get_builtins();
+	const HashMap<String, List<Ref<InputEvent>>> &get_builtins_with_feature_overrides_applied();
 
 	InputMap();
 	~InputMap();

+ 15 - 12
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<String, Variant>();
+			values[p_section] = HashMap<String, Variant>();
 		}
 
 		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<String> *r_sections) const {
-	for (OrderedHashMap<String, OrderedHashMap<String, Variant>>::ConstElement E = values.front(); E; E = E.next()) {
-		r_sections->push_back(E.key());
+	for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
+		r_sections->push_back(E.key);
 	}
 }
 
 void ConfigFile::get_section_keys(const String &p_section, List<String> *r_keys) const {
 	ERR_FAIL_COND_MSG(!values.has(p_section), vformat("Cannot get keys from nonexistent section \"%s\".", p_section));
 
-	for (OrderedHashMap<String, Variant>::ConstElement E = values[p_section].front(); E; E = E.next()) {
-		r_keys->push_back(E.key());
+	for (const KeyValue<String, Variant> &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<FileAccess> file) {
-	for (OrderedHashMap<String, OrderedHashMap<String, Variant>>::Element E = values.front(); E; E = E.next()) {
-		if (E != values.front()) {
+	bool first = true;
+	for (const KeyValue<String, HashMap<String, Variant>> &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<String, Variant>::Element F = E.get().front(); F; F = F.next()) {
+		for (const KeyValue<String, Variant> &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");
 		}
 	}
 

+ 2 - 2
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<String, OrderedHashMap<String, Variant>> values;
+	HashMap<String, HashMap<String, Variant>> values;
 
 	PackedStringArray _get_sections() const;
 	PackedStringArray _get_section_keys(const String &p_section) const;

+ 2 - 2
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<PropertyInfo> *p_list) const {
-	for (OrderedHashMap<StringName, Variant>::ConstElement E = properties.front(); E; E = E.next()) {
-		p_list->push_back(PropertyInfo(E.value().get_type(), E.key()));
+	for (const KeyValue<StringName, Variant> &E : properties) {
+		p_list->push_back(PropertyInfo(E.value.get_type(), E.key));
 	}
 }
 

+ 1 - 1
core/io/missing_resource.h

@@ -38,7 +38,7 @@
 
 class MissingResource : public Resource {
 	GDCLASS(MissingResource, Resource)
-	OrderedHashMap<StringName, Variant> properties;
+	HashMap<StringName, Variant> properties;
 
 	String original_class;
 	bool recording_properties = false;

+ 6 - 11
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<String, Resource *> &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<Ref<Resource>> *p_resources) {
 	lock.read_lock();
-	const String *K = nullptr;
-	while ((K = resources.next(K))) {
-		Resource *r = resources[*K];
-		p_resources->push_back(Ref<Resource>(r));
+	for (KeyValue<String, Resource *> &E : resources) {
+		p_resources->push_back(Ref<Resource>(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<String, Resource *> &E : resources) {
+		Resource *r = E.value;
 
 		if (!type_count.has(r->get_class())) {
 			type_count[r->get_class()] = 0;

+ 11 - 11
core/io/resource_uid.cpp

@@ -149,12 +149,12 @@ Error ResourceUID::save_to_cache() {
 
 	cache_entries = 0;
 
-	for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) {
-		f->store_64(E.key());
-		uint32_t s = E.get().cs.length();
+	for (KeyValue<ID, Cache> &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<FileAccess> f;
-	for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) {
-		if (!E.get().saved_to_cache) {
+	for (KeyValue<ID, Cache> &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++;
 		}
 	}

+ 2 - 2
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<ID, Cache> unique_ids; //unique IDs and utf8 paths (less memory used)
+	HashMap<ID, Cache> unique_ids; //unique IDs and utf8 paths (less memory used)
 	static ResourceUID *singleton;
 
 	uint32_t cache_entries = 0;

+ 42 - 75
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<StringName> *p_classes) {
 	OBJTYPE_RLOCK;
 
-	const StringName *k = nullptr;
-
-	while ((k = classes.next(k))) {
-		p_classes->push_back(*k);
+	for (const KeyValue<StringName, ClassInfo> &E : classes) {
+		p_classes->push_back(E.key);
 	}
 
 	p_classes->sort();
@@ -102,11 +100,9 @@ void ClassDB::get_class_list(List<StringName> *p_classes) {
 void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *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<StringName, ClassInfo> &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<StringNa
 void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *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<StringName, ClassInfo> &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<StringName> names;
-
-	const StringName *k = nullptr;
+	List<StringName> class_list;
+	ClassDB::get_class_list(&class_list);
+	// Must be alphabetically sorted for hash to compute.
+	class_list.sort_custom<StringName::AlphCompare>();
 
-	while ((k = classes.next(k))) {
-		names.push_back(*k);
-	}
-	//must be alphabetically sorted for hash to compute
-	names.sort_custom<StringName::AlphCompare>();
-
-	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<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->method_map.next(k))) {
-				String name = k->operator String();
+			for (const KeyValue<StringName, MethodBind *> &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<StringName::AlphCompare>();
@@ -241,10 +228,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
 
 			List<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->constant_map.next(k))) {
-				snames.push_back(*k);
+			for (const KeyValue<StringName, int> &F : t->constant_map) {
+				snames.push_back(F.key);
 			}
 
 			snames.sort_custom<StringName::AlphCompare>();
@@ -259,10 +244,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
 
 			List<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->signal_map.next(k))) {
-				snames.push_back(*k);
+			for (const KeyValue<StringName, MethodInfo> &F : t->signal_map) {
+				snames.push_back(F.key);
 			}
 
 			snames.sort_custom<StringName::AlphCompare>();
@@ -280,10 +263,8 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
 
 			List<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->property_setget.next(k))) {
-				snames.push_back(*k);
+			for (const KeyValue<StringName, PropertySetGet> &F : t->property_setget) {
+				snames.push_back(F.key);
 			}
 
 			snames.sort_custom<StringName::AlphCompare>();
@@ -474,10 +455,8 @@ void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_met
 
 #else
 
-		const StringName *K = nullptr;
-
-		while ((K = type->method_map.next(K))) {
-			MethodBind *m = type->method_map[*K];
+		for (KeyValue<StringName, MethodBind *> &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<String>
 			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<StringName, int> &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<StringName> &constants_list = type->enum_map.get(*k);
+		for (KeyValue<StringName, List<StringName>> &E : type->enum_map) {
+			List<StringName> &constants_list = E.value;
 			const List<StringName>::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<StringName> *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<StringName, List<StringName>> &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<MethodInfo> *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<StringName, MethodInfo> &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<String> *p_extensions) {
-	const StringName *K = nullptr;
-
-	while ((K = resource_base_extensions.next(K))) {
-		p_extensions->push_back(*K);
+	for (const KeyValue<StringName, StringName> &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<String> *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<StringName, StringName> &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;
-
-	while ((k = classes.next(k))) {
-		ClassInfo &ti = classes[*k];
+	for (KeyValue<StringName, ClassInfo> &E : classes) {
+		ClassInfo &ti = E.value;
 
-		const StringName *m = nullptr;
-		while ((m = ti.method_map.next(m))) {
-			memdelete(ti.method_map[*m]);
+		for (KeyValue<StringName, MethodBind *> &F : ti.method_map) {
+			memdelete(F.value);
 		}
 	}
 	classes.clear();

+ 29 - 33
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<StringName, Variant>::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<StringName, Variant>::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<PropertyInfo> *p_list, bool p_reversed) cons
 		script_instance->get_property_list(p_list);
 	}
 
-	for (OrderedHashMap<StringName, Variant>::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<StringName, Variant> &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<StringName, Variant>::Element E = metadata.find(p_name);
+	HashMap<StringName, Variant>::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<StringName> Object::_get_meta_list_bind() const {
 	Vector<StringName> _metaret;
 
-	for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
-		_metaret.push_back(K.key());
+	for (const KeyValue<StringName, Variant> &K : metadata) {
+		_metaret.push_back(K.key);
 	}
 
 	return _metaret;
 }
 
 void Object::get_meta_list(List<StringName> *p_list) const {
-	for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
-		p_list->push_back(K.key());
+	for (const KeyValue<StringName, Variant> &K : metadata) {
+		p_list->push_back(K.key);
 	}
 }
 
@@ -1250,21 +1250,18 @@ void Object::get_signal_list(List<MethodInfo> *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<StringName, SignalData> &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<Connection> *p_connections) const {
-	const StringName *S = nullptr;
-
-	while ((S = signal_map.next(S))) {
-		const SignalData *s = &signal_map[*S];
+	for (const KeyValue<StringName, SignalData> &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<Connect
 
 int Object::get_persistent_signal_connection_count() const {
 	int count = 0;
-	const StringName *S = nullptr;
 
-	while ((S = signal_map.next(S))) {
-		const SignalData *s = &signal_map[*S];
+	for (const KeyValue<StringName, SignalData> &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<StringName, SignalData> &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

+ 2 - 3
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<StringName, Variant> metadata;
-	HashMap<StringName, OrderedHashMap<StringName, Variant>::Element> metadata_properties;
+	HashMap<StringName, Variant> metadata;
+	HashMap<StringName, Variant *> metadata_properties;
 	mutable StringName _class_name;
 	mutable const StringName *_class_ptr = nullptr;
 

+ 2 - 3
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<StringName> *r_global_classes) {
-	const StringName *K = nullptr;
 	List<StringName> classes;
-	while ((K = global_classes.next(K))) {
-		classes.push_back(*K);
+	for (const KeyValue<StringName, GlobalScriptClass> &E : global_classes) {
+		classes.push_back(E.key);
 	}
 	classes.sort_custom<StringName::AlphCompare>();
 	for (const StringName &E : classes) {

+ 8 - 0
core/os/memory.h

@@ -197,4 +197,12 @@ struct _GlobalNilClass {
 	static _GlobalNil _nil;
 };
 
+template <class T>
+class DefaultTypedAllocator {
+public:
+	template <class... Args>
+	_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

+ 13 - 27
core/string/translation_po.cpp

@@ -70,21 +70,14 @@ Dictionary TranslationPO::_get_messages() const {
 
 	Dictionary d;
 
-	List<StringName> context_l;
-	translation_map.get_key_list(&context_l);
-	for (const StringName &ctx : context_l) {
-		const HashMap<StringName, Vector<StringName>> &id_str_map = translation_map[ctx];
-
+	for (const KeyValue<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) {
 		Dictionary d2;
-		List<StringName> 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<StringName>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
-			StringName id = E2->get();
-			d2[id] = id_str_map[id];
+
+		for (const KeyValue<StringName, Vector<StringName>> &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<StringName> *r_messages) const {
 	// OptimizedTranslation uses this function to get the list of msgid.
 	// Return all the keys of translation_map under "" context.
 
-	List<StringName> context_l;
-	translation_map.get_key_list(&context_l);
-
-	for (const StringName &E : context_l) {
-		if (String(E) != "") {
+	for (const KeyValue<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) {
+		if (E.key != StringName()) {
 			continue;
 		}
 
-		List<StringName> msgid_l;
-		translation_map[E].get_key_list(&msgid_l);
-
-		for (List<StringName>::Element *E2 = msgid_l.front(); E2; E2 = E2->next()) {
-			r_messages->push_back(E2->get());
+		for (const KeyValue<StringName, Vector<StringName>> &E2 : E.value) {
+			r_messages->push_back(E2.key);
 		}
 	}
 }
 
 int TranslationPO::get_message_count() const {
-	List<StringName> 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<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) {
+		count += E.value.size();
 	}
+
 	return count;
 }
 

+ 402 - 373
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 <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
+template <class TKey, class TValue>
+struct HashMapElement {
+	HashMapElement *next = nullptr;
+	HashMapElement *prev = nullptr;
+	KeyValue<TKey, TValue> data;
+	HashMapElement() {}
+	HashMapElement(const TKey &p_key, const TValue &p_value) :
+			data(p_key, p_value) {}
+};
+
+template <class TKey, class TValue,
+		class Hasher = HashMapHasherDefault,
+		class Comparator = HashMapComparatorDefault<TKey>,
+		class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
 class HashMap {
 public:
-	struct Pair {
-		TKey key;
-		TData data;
+	const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
+	const float MAX_OCCUPANCY = 0.75;
+	const uint32_t EMPTY_HASH = 0;
 
-		Pair(const TKey &p_key) :
-				key(p_key),
-				data() {}
-		Pair(const TKey &p_key, const TData &p_data) :
-				key(p_key),
-				data(p_data) {
-		}
-	};
+private:
+	Allocator element_alloc;
+	HashMapElement<TKey, TValue> **elements = nullptr;
+	uint32_t *hashes = nullptr;
+	HashMapElement<TKey, TValue> *head_element = nullptr;
+	HashMapElement<TKey, TValue> *tail_element = nullptr;
 
-	struct Element {
-	private:
-		friend class HashMap;
+	uint32_t capacity_index = 0;
+	uint32_t num_elements = 0;
 
-		uint32_t hash = 0;
-		Element *next = nullptr;
-		Element() {}
-		Pair pair;
+	_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
+		uint32_t hash = Hasher::hash(p_key);
 
-	public:
-		const TKey &key() const {
-			return pair.key;
+		if (unlikely(hash == EMPTY_HASH)) {
+			hash = EMPTY_HASH + 1;
 		}
 
-		TData &value() {
-			return pair.data;
-		}
+		return hash;
+	}
 
-		const TData &value() const {
-			return pair.value();
+	_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
 		}
 
-		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) {}
-	};
+		uint32_t capacity = hash_table_size_primes[capacity_index];
+		uint32_t hash = _hash(p_key);
+		uint32_t pos = hash % capacity;
+		uint32_t distance = 0;
 
-private:
-	Element **hash_table = nullptr;
-	uint8_t hash_table_power = 0;
-	uint32_t elements = 0;
+		while (true) {
+			if (hashes[pos] == EMPTY_HASH) {
+				return false;
+			}
 
-	void make_hash_table() {
-		ERR_FAIL_COND(hash_table);
+			if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
+				return false;
+			}
 
-		hash_table = memnew_arr(Element *, (1 << MIN_HASH_TABLE_POWER));
+			if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) {
+				r_pos = pos;
+				return true;
+			}
 
-		hash_table_power = MIN_HASH_TABLE_POWER;
-		elements = 0;
-		for (int i = 0; i < (1 << MIN_HASH_TABLE_POWER); i++) {
-			hash_table[i] = nullptr;
+			pos = (pos + 1) % capacity;
+			distance++;
 		}
 	}
 
-	void erase_hash_table() {
-		ERR_FAIL_COND_MSG(elements, "Cannot erase hash table if there are still elements inside.");
+	void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
+		uint32_t capacity = hash_table_size_primes[capacity_index];
+		uint32_t hash = p_hash;
+		HashMapElement<TKey, TValue> *value = p_value;
+		uint32_t distance = 0;
+		uint32_t pos = hash % capacity;
 
-		memdelete_arr(hash_table);
-		hash_table = nullptr;
-		hash_table_power = 0;
-		elements = 0;
-	}
+		while (true) {
+			if (hashes[pos] == EMPTY_HASH) {
+				elements[pos] = value;
+				hashes[pos] = hash;
 
-	void check_hash_table() {
-		int new_hash_table_power = -1;
+				num_elements++;
 
-		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++;
+				return;
 			}
 
-		} 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--;
+			// 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;
 			}
 
-			if (new_hash_table_power < (int)MIN_HASH_TABLE_POWER) {
-				new_hash_table_power = MIN_HASH_TABLE_POWER;
-			}
+			pos = (pos + 1) % capacity;
+			distance++;
 		}
+	}
 
-		if (new_hash_table_power == -1) {
-			return;
-		}
+	void _resize_and_rehash(uint32_t p_new_capacity_index) {
+		uint32_t old_capacity = hash_table_size_primes[capacity_index];
 
-		Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power));
-		ERR_FAIL_COND_MSG(!new_hash_table, "Out of memory.");
+		// Capacity can't be 0.
+		capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
 
-		for (int i = 0; i < (1 << new_hash_table_power); i++) {
-			new_hash_table[i] = nullptr;
-		}
+		uint32_t capacity = hash_table_size_primes[capacity_index];
 
-		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;
-				}
-			}
+		HashMapElement<TKey, TValue> **old_elements = elements;
+		uint32_t *old_hashes = hashes;
 
-			memdelete_arr(hash_table);
-		}
-		hash_table = new_hash_table;
-		hash_table_power = new_hash_table_power;
-	}
+		num_elements = 0;
+		hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+		elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
 
-	/* I want to have only one function.. */
-	_FORCE_INLINE_ const Element *get_element(const TKey &p_key) const {
-		uint32_t hash = Hasher::hash(p_key);
-		uint32_t index = hash & ((1 << hash_table_power) - 1);
+		for (uint32_t i = 0; i < capacity; i++) {
+			hashes[i] = 0;
+			elements[i] = nullptr;
+		}
 
-		Element *e = hash_table[index];
+		if (old_capacity == 0) {
+			// Nothing to do.
+			return;
+		}
 
-		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;
+		for (uint32_t i = 0; i < old_capacity; i++) {
+			if (old_hashes[i] == EMPTY_HASH) {
+				continue;
 			}
 
-			e = e->next;
+			_insert_with_hash(old_hashes[i], old_elements[i]);
 		}
 
-		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;
+		Memory::free_static(old_elements);
+		Memory::free_static(old_hashes);
 	}
 
-	void copy_from(const HashMap &p_t) {
-		if (&p_t == this) {
-			return; /* much less bother with that */
-		}
+	_FORCE_INLINE_ HashMapElement<TKey, TValue> *_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.
 
-		clear();
+			hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
+			elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
 
-		if (!p_t.hash_table || p_t.hash_table_power == 0) {
-			return; /* not copying from empty table */
+			for (uint32_t i = 0; i < capacity; i++) {
+				hashes[i] = EMPTY_HASH;
+				elements[i] = nullptr;
+			}
 		}
 
-		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;
+		uint32_t pos = 0;
+		bool exists = _lookup_pos(p_key, pos);
 
-			const Element *e = p_t.hash_table[i];
-
-			while (e) {
-				Element *le = memnew(Element(*e)); /* local element */
+		if (exists) {
+			elements[pos]->data.value = p_value;
+			return elements[pos];
+		} else {
+			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);
+			}
 
-				/* add to list and reassign pointers */
-				le->next = hash_table[i];
-				hash_table[i] = le;
+			HashMapElement<TKey, TValue> *elem = element_alloc.new_allocation(HashMapElement<TKey, TValue>(p_key, p_value));
 
-				e = e->next;
+			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 {
+				tail_element->next = elem;
+				elem->prev = tail_element;
+				tail_element = elem;
 			}
+
+			uint32_t hash = _hash(p_key);
+			_insert_with_hash(hash, elem);
+			return elem;
 		}
 	}
 
 public:
-	Element *set(const TKey &p_key, const TData &p_data) {
-		return set(Pair(p_key, p_data));
-	}
+	_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
+	_FORCE_INLINE_ uint32_t size() const { return num_elements; }
 
-	Element *set(const Pair &p_pair) {
-		Element *e = nullptr;
-		if (!hash_table) {
-			make_hash_table(); // if no table, make one
-		} else {
-			e = const_cast<Element *>(get_element(p_pair.key));
-		}
+	/* Standard Godot Container API */
 
-		/* if we made it up to here, the pair doesn't exist, create and assign */
+	bool is_empty() const {
+		return num_elements == 0;
+	}
 
-		if (!e) {
-			e = create_element(p_pair.key);
-			if (!e) {
-				return nullptr;
-			}
-			check_hash_table(); // perform mantenience routine
+	void clear() {
+		if (elements == nullptr) {
+			return;
 		}
+		uint32_t capacity = hash_table_size_primes[capacity_index];
+		for (uint32_t i = 0; i < capacity; i++) {
+			if (hashes[i] == EMPTY_HASH) {
+				continue;
+			}
 
-		e->pair.data = p_pair.data;
-		return e;
-	}
+			hashes[i] = EMPTY_HASH;
+			element_alloc.delete_allocation(elements[i]);
+			elements[i] = nullptr;
+		}
 
-	bool has(const TKey &p_key) const {
-		return getptr(p_key) != nullptr;
+		tail_element = nullptr;
+		head_element = nullptr;
+		num_elements = 0;
 	}
 
-	/**
-	 * 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;
+	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;
 	}
 
-	TData &get(const TKey &p_key) {
-		TData *res = getptr(p_key);
-		CRASH_COND_MSG(!res, "Map key not found.");
-		return *res;
+	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;
 	}
 
-	/**
-	 * Same as get, except it can return nullptr when item was not found.
-	 * This is mainly used for speed purposes.
-	 */
+	const TValue *getptr(const TKey &p_key) const {
+		uint32_t pos = 0;
+		bool exists = _lookup_pos(p_key, pos);
 
-	_FORCE_INLINE_ TData *getptr(const TKey &p_key) {
-		if (unlikely(!hash_table)) {
-			return nullptr;
+		if (exists) {
+			return &elements[pos]->data.value;
 		}
+		return nullptr;
+	}
 
-		Element *e = const_cast<Element *>(get_element(p_key));
+	TValue *getptr(const TKey &p_key) {
+		uint32_t pos = 0;
+		bool exists = _lookup_pos(p_key, pos);
 
-		if (e) {
-			return &e->pair.data;
+		if (exists) {
+			return &elements[pos]->data.value;
 		}
-
 		return nullptr;
 	}
 
-	_FORCE_INLINE_ const TData *getptr(const TKey &p_key) const {
-		if (unlikely(!hash_table)) {
-			return nullptr;
-		}
+	_FORCE_INLINE_ bool has(const TKey &p_key) const {
+		uint32_t _pos = 0;
+		return _lookup_pos(p_key, _pos);
+	}
 
-		const Element *e = const_cast<Element *>(get_element(p_key));
+	bool erase(const TKey &p_key) {
+		uint32_t pos = 0;
+		bool exists = _lookup_pos(p_key, pos);
 
-		if (e) {
-			return &e->pair.data;
+		if (!exists) {
+			return false;
 		}
 
-		return nullptr;
-	}
+		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;
+		}
 
-	/**
-	 * 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==()
-	 */
+		hashes[pos] = EMPTY_HASH;
 
-	template <class C>
-	_FORCE_INLINE_ TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) {
-		if (unlikely(!hash_table)) {
-			return nullptr;
+		if (head_element == elements[pos]) {
+			head_element = elements[pos]->next;
 		}
 
-		uint32_t hash = p_custom_hash;
-		uint32_t index = hash & ((1 << hash_table_power) - 1);
-
-		Element *e = hash_table[index];
+		if (tail_element == elements[pos]) {
+			tail_element = elements[pos]->prev;
+		}
 
-		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 (elements[pos]->prev) {
+			elements[pos]->prev->next = elements[pos]->next;
+		}
 
-			e = e->next;
+		if (elements[pos]->next) {
+			elements[pos]->next->prev = elements[pos]->prev;
 		}
 
-		return nullptr;
+		element_alloc.delete_allocation(elements[pos]);
+		elements[pos] = nullptr;
+
+		num_elements--;
+		return true;
 	}
 
-	template <class C>
-	_FORCE_INLINE_ const TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) const {
-		if (unlikely(!hash_table)) {
-			return nullptr;
+	// 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++;
 		}
 
-		uint32_t hash = p_custom_hash;
-		uint32_t index = hash & ((1 << hash_table_power) - 1);
+		if (new_index == capacity_index) {
+			return;
+		}
+
+		if (elements == nullptr) {
+			capacity_index = new_index;
+			return; // Unallocated yet.
+		}
+		_resize_and_rehash(new_index);
+	}
 
-		const Element *e = hash_table[index];
+	/** Iterator API **/
 
-		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;
+	struct Iterator {
+		_FORCE_INLINE_ KeyValue<TKey, TValue> &operator*() const {
+			return E->data;
+		}
+		_FORCE_INLINE_ KeyValue<TKey, TValue> *operator->() const { return &E->data; }
+		_FORCE_INLINE_ Iterator &operator++() {
+			if (E) {
+				E = E->next;
 			}
-
-			e = e->next;
+			return *this;
+		}
+		_FORCE_INLINE_ Iterator &operator--() {
+			if (E) {
+				E = E->prev;
+			}
+			return *this;
 		}
 
-		return nullptr;
-	}
+		_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
 
-	/**
-	 * Erase an item, return true if erasing was successful
-	 */
+		_FORCE_INLINE_ operator bool() const {
+			return E != nullptr;
+		}
 
-	bool erase(const TKey &p_key) {
-		if (unlikely(!hash_table)) {
-			return false;
+		_FORCE_INLINE_ Iterator(HashMapElement<TKey, TValue> *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;
 		}
 
-		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();
-				}
-				return true;
+	private:
+		HashMapElement<TKey, TValue> *E = nullptr;
+	};
+
+	struct ConstIterator {
+		_FORCE_INLINE_ const KeyValue<TKey, TValue> &operator*() const {
+			return E->data;
+		}
+		_FORCE_INLINE_ const KeyValue<TKey, TValue> *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; }
 
-			p = e;
-			e = e->next;
+		_FORCE_INLINE_ operator bool() const {
+			return E != nullptr;
 		}
 
-		return false;
-	}
+		_FORCE_INLINE_ ConstIterator(const HashMapElement<TKey, TValue> *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;
+		}
 
-	inline const TData &operator[](const TKey &p_key) const { //constref
+	private:
+		const HashMapElement<TKey, TValue> *E = nullptr;
+	};
 
-		return get(p_key);
+	_FORCE_INLINE_ Iterator begin() {
+		return Iterator(head_element);
+	}
+	_FORCE_INLINE_ Iterator end() {
+		return Iterator(nullptr);
+	}
+	_FORCE_INLINE_ Iterator last() {
+		return Iterator(tail_element);
 	}
-	inline TData &operator[](const TKey &p_key) { //assignment
 
-		Element *e = nullptr;
-		if (!hash_table) {
-			make_hash_table(); // if no table, make one
-		} else {
-			e = const_cast<Element *>(get_element(p_key));
+	_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]);
+	}
 
-		/* 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
+	_FORCE_INLINE_ void remove(const Iterator &p_iter) {
+		if (p_iter) {
+			erase(p_iter->key);
 		}
+	}
 
-		return e->pair.data;
+	_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);
 	}
 
-	/**
-	 * 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;
+	_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]);
+	}
 
-		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;
-				}
-			}
-
-		} else { /* get the next key */
+	/* Indexing */
 
-			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;
-			} 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;
-					}
-				}
-			}
+	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;
+	}
 
-			/* nothing found, was at end */
+	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;
 		}
-
-		return nullptr; /* nothing found */
 	}
 
-	inline unsigned int size() const {
-		return elements;
-	}
+	/* Insert */
 
-	inline bool is_empty() const {
-		return elements == 0;
+	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));
 	}
 
-	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);
-				}
-			}
+	/* Constructors */
 
-			memdelete_arr(hash_table);
+	HashMap(const HashMap &p_other) {
+		reserve(hash_table_size_primes[p_other.capacity_index]);
+
+		if (p_other.num_elements == 0) {
+			return;
 		}
 
-		hash_table = nullptr;
-		hash_table_power = 0;
-		elements = 0;
+		for (const KeyValue<TKey, TValue> &E : p_other) {
+			insert(E.key, E.value);
+		}
 	}
 
-	void operator=(const HashMap &p_table) {
-		copy_from(p_table);
-	}
+	void operator=(const HashMap &p_other) {
+		if (this == &p_other) {
+			return; // Ignore self assignment.
+		}
+		if (num_elements != 0) {
+			clear();
+		}
 
-	void get_key_list(List<TKey> *r_keys) const {
-		if (unlikely(!hash_table)) {
-			return;
+		reserve(hash_table_size_primes[p_other.capacity_index]);
+
+		if (p_other.elements == nullptr) {
+			return; // Nothing to copy.
 		}
-		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;
-			}
+
+		for (const KeyValue<TKey, TValue> &E : p_other) {
+			insert(E.key, E.value);
 		}
 	}
 
-	HashMap() {}
+	HashMap(uint32_t p_initial_capacity) {
+		// Capacity can't be 0.
+		capacity_index = 0;
+		reserve(p_initial_capacity);
+	}
+	HashMap() {
+		capacity_index = MIN_CAPACITY_INDEX;
+	}
 
-	HashMap(const HashMap &p_table) {
-		copy_from(p_table);
+	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);
+		}
 	}
 };
 

+ 85 - 0
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

+ 0 - 301
core/templates/ordered_hash_map.h

@@ -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 <class K, class V, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<K>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
-class OrderedHashMap {
-	typedef List<Pair<const K *, V>> InternalList;
-	typedef HashMap<K, typename InternalList::Element *, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP> InternalMap;
-
-	InternalList list;
-	InternalMap map;
-
-public:
-	class Element {
-		friend class OrderedHashMap<K, V, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP>;
-
-		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<K, V, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP>;
-
-		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<const K *, V>(&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

+ 7 - 1
core/templates/paged_allocator.h

@@ -50,6 +50,10 @@ class PagedAllocator {
 	SpinLock spin_lock;
 
 public:
+	enum {
+		DEFAULT_PAGE_SIZE = 4096
+	};
+
 	template <class... Args>
 	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);
 	}
 

+ 46 - 39
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, Variant, VariantHasher, VariantComparator> variant_map;
+	HashMap<Variant, Variant, VariantHasher, VariantComparator> variant_map;
 };
 
 void Dictionary::get_key_list(List<Variant> *p_keys) const {
@@ -49,16 +49,16 @@ void Dictionary::get_key_list(List<Variant> *p_keys) const {
 		return;
 	}
 
-	for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
-		p_keys->push_back(E.key());
+	for (const KeyValue<Variant, Variant> &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<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+	for (const KeyValue<Variant, Variant> &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<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+	for (const KeyValue<Variant, Variant> &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<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E;
+	HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E;
 
 	if (p_key.get_type() == Variant::STRING_NAME) {
 		const StringName *sn = VariantInternal::get_string_name(&p_key);
-		E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
+		E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
 	} else {
-		E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
+		E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
 	}
 
 	if (!E) {
 		return nullptr;
 	}
-	return &E.get();
+	return &E->value;
 }
 
 Variant *Dictionary::getptr(const Variant &p_key) {
-	OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E;
+	HashMap<Variant, Variant, VariantHasher, VariantComparator>::Iterator E;
 
 	if (p_key.get_type() == Variant::STRING_NAME) {
 		const StringName *sn = VariantInternal::get_string_name(&p_key);
-		E = ((OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
+		E = ((HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
 	} else {
-		E = ((OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
+		E = ((HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_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<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E;
+	HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator E;
 
 	if (p_key.get_type() == Variant::STRING_NAME) {
 		const StringName *sn = VariantInternal::get_string_name(&p_key);
-		E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
+		E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String());
 	} else {
-		E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
+		E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_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<Variant, Variant, VariantHasher, VariantComparator>::ConstElement this_E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->front(); this_E; this_E = this_E.next()) {
-		OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement other_E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&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<Variant, Variant> &this_E : _p->variant_map) {
+		HashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstIterator other_E = ((const HashMap<Variant, Variant, VariantHasher, VariantComparator> *)&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<Variant, Variant, VariantHasher, VariantComparator>::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<Variant, Variant> &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<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
-		varr[i] = E.key();
+	for (const KeyValue<Variant, Variant> &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<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
-		varr[i] = E.get();
+	for (const KeyValue<Variant, Variant> &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<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(*p_key);
+	HashMap<Variant, Variant, VariantHasher, VariantComparator>::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<Variant, Variant, VariantHasher, VariantComparator>::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<Variant, Variant> &E : _p->variant_map) {
+			n[E.key.recursive_duplicate(true, recursion_count)] = E.value.recursive_duplicate(true, recursion_count);
 		}
 	} else {
-		for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
-			n[E.key()] = E.value();
+		for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
+			n[E.key] = E.value;
 		}
 	}
 

+ 0 - 1
doc/classes/DirectionalLight3D.xml

@@ -34,7 +34,6 @@
 		<member name="directional_shadow_split_3" type="float" setter="set_param" getter="get_param" default="0.5">
 			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].
 		</member>
-		<member name="shadow_bias" type="float" setter="set_param" getter="get_param" overrides="Light3D" default="0.1" />
 		<member name="sky_mode" type="int" setter="set_sky_mode" getter="get_sky_mode" enum="DirectionalLight3D.SkyMode" default="0">
 			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.
 		</member>

+ 1 - 1
doc/classes/Light3D.xml

@@ -80,7 +80,7 @@
 		<member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
 			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.
 		</member>
-		<member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.2">
+		<member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.1">
 			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.
 		</member>
 		<member name="shadow_blur" type="float" setter="set_param" getter="get_param" default="1.0">

+ 1 - 0
doc/classes/OmniLight3D.xml

@@ -19,6 +19,7 @@
 		<member name="omni_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="OmniLight3D.ShadowMode" default="1">
 			See [enum ShadowMode].
 		</member>
+		<member name="shadow_bias" type="float" setter="set_param" getter="get_param" overrides="Light3D" default="0.2" />
 	</members>
 	<constants>
 		<constant name="SHADOW_DUAL_PARABOLOID" value="0" enum="ShadowMode">

+ 2 - 3
drivers/gles3/storage/material_storage.cpp

@@ -2077,10 +2077,9 @@ Vector<StringName> MaterialStorage::global_variable_get_list() const {
 		ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
 	}
 
-	const StringName *K = nullptr;
 	Vector<StringName> names;
-	while ((K = global_variables.variables.next(K))) {
-		names.push_back(*K);
+	for (const KeyValue<StringName, GlobalVariables::Variable> &E : global_variables.variables) {
+		names.push_back(E.key);
 	}
 	names.sort_custom<StringName::AlphCompare>();
 	return names;

+ 46 - 36
editor/debugger/editor_performance_profiler.cpp

@@ -97,9 +97,9 @@ void EditorPerformanceProfiler::_monitor_select() {
 
 void EditorPerformanceProfiler::_monitor_draw() {
 	Vector<StringName> active;
-	for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
-		if (i.value().item->is_checked(0)) {
-			active.push_back(i.key());
+	for (const KeyValue<StringName, Monitor> &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<StringName> monitor_checked;
-	for (OrderedHashMap<StringName, Monitor>::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<StringName, Monitor> &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<StringName, Monitor>::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<StringName, Monitor> &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<InputEvent> &p_event) {
 	Ref<InputEventMouseButton> mb = p_event;
 	if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
 		Vector<StringName> active;
-		for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
-			if (i.value().item->is_checked(0)) {
-				active.push_back(i.key());
+		for (KeyValue<StringName, Monitor> &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<InputEvent> &p_event) {
 }
 
 void EditorPerformanceProfiler::reset() {
-	for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
-		if (String(i.key()).begins_with("custom:")) {
-			monitors.erase(i);
+	HashMap<StringName, Monitor>::Iterator E = monitors.begin();
+	while (E != monitors.end()) {
+		HashMap<StringName, Monitor>::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<StringName> &p_names) {
-	OrderedHashMap<StringName, int> names;
+	HashMap<StringName, int> names;
 	for (int i = 0; i < p_names.size(); i++) {
 		names.insert("custom:" + p_names[i], Performance::MONITOR_MAX + i);
 	}
 
-	for (OrderedHashMap<StringName, Monitor>::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<StringName, Monitor>::Iterator E = monitors.begin();
+		while (E != monitors.end()) {
+			HashMap<StringName, Monitor>::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<StringName, int>::Element i = names.front(); i; i = i.next()) {
-		String name = String(i.key()).replace_first("custom:", "");
+	for (const KeyValue<StringName, int> &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<float> &p_values) {
-	for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+	for (KeyValue<StringName, Monitor> &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();

+ 2 - 2
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<StringName, Monitor> monitors;
+	HashMap<StringName, Monitor> monitors;
 
 	Map<StringName, TreeItem *> base_map;
 	Tree *monitor_tree = nullptr;

+ 16 - 20
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<String, TreeItem *> sections;
 	TreeItem *first_section = nullptr;
 
 	// Filter possible candidates.
 	Vector<CommandEntry> entries;
-	for (int i = 0; i < command_keys.size(); i++) {
+	for (const KeyValue<String, Command> &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<String> *p_list) const {
-	commands.get_key_list(p_list);
+	for (const KeyValue<String, Command> &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> shortcut = unregistered_shortcuts[*key].second;
+	for (const KeyValue<String, Pair<String, Ref<Shortcut>>> &E : unregistered_shortcuts) {
+		String command_name = E.value.first;
+		Ref<Shortcut> shortcut = E.value.second;
 		Ref<InputEventShortcut> 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<String> 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<String, Command> &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);

+ 3 - 6
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<StringName> 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<StringName, String> &E : _script_class_icon_paths) {
+		if (ScriptServer::is_global_class(E.key)) {
+			d[E.key] = E.value;
 		}
 	}
 

+ 1 - 1
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"

+ 13 - 10
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<String, List<Ref<InputEvent>>> &builtin_list = InputMap::get_singleton()->get_builtins();
+		const HashMap<String, List<Ref<InputEvent>>> &builtin_list = InputMap::get_singleton()->get_builtins();
 		for (const KeyValue<String, Ref<Shortcut>> &shortcut_definition : shortcuts) {
 			Ref<Shortcut> sc = shortcut_definition.value;
 
@@ -244,18 +244,17 @@ struct _EVCSort {
 void EditorSettings::_get_property_list(List<PropertyInfo> *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<String, VariantContainer> &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<ConfigFile> cf = memnew(ConfigFile); // hex is better?
 
 	List<String> keys;
-	props.get_key_list(&keys);
+
+	for (const KeyValue<String, VariantContainer> &E : props) {
+		keys.push_back(E.key);
+	}
+
 	keys.sort();
 
 	for (const String &key : keys) {
@@ -1421,10 +1424,10 @@ Ref<Shortcut> 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<String, List<Ref<InputEvent>>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name);
+		const HashMap<String, List<Ref<InputEvent>>>::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<String, List<Ref<InputEvent>>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name);
+	HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name);
 	if (builtin_default) {
-		List<Ref<InputEvent>> builtin_events = builtin_default.get();
+		const List<Ref<InputEvent>> &builtin_events = builtin_default->value;
 
 		// In the editor we only care about key events.
 		List<Ref<InputEventKey>> builtin_key_events;

+ 7 - 8
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<Ref<InputEvent>> &p_events) {
+Array EditorSettingsDialog::_event_list_to_array_helper(const List<Ref<InputEvent>> &p_events) {
 	Array events;
 
 	// Convert the list to an array, and only keep key events as this is for the editor.
-	for (List<Ref<InputEvent>>::Element *E = p_events.front(); E; E = E->next()) {
+	for (const List<Ref<InputEvent>>::Element *E = p_events.front(); E; E = E->next()) {
 		Ref<InputEventKey> 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<StringName, InputMap::Action> action_map = InputMap::get_singleton()->get_action_map();
-	for (OrderedHashMap<StringName, InputMap::Action>::Element E = action_map.front(); E; E = E.next()) {
-		String action_name = E.key();
-		InputMap::Action action = E.get();
+	for (const KeyValue<StringName, InputMap::Action> &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<String> event_strings;
@@ -387,10 +386,10 @@ void EditorSettingsDialog::_update_shortcuts() {
 			continue;
 		}
 
-		List<Ref<InputEvent>> all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name).value();
+		const List<Ref<InputEvent>> &all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name)->value;
 		List<Ref<InputEventKey>> key_default_events;
 		// Remove all non-key events from the defaults. Only check keys, since we are in the editor.
-		for (List<Ref<InputEvent>>::Element *I = all_default_events.front(); I; I = I->next()) {
+		for (const List<Ref<InputEvent>>::Element *I = all_default_events.front(); I; I = I->next()) {
 			Ref<InputEventKey> k = I->get();
 			if (k.is_valid()) {
 				key_default_events.push_back(k);

+ 1 - 1
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<Ref<InputEvent>> &p_events);
+	Array _event_list_to_array_helper(const List<Ref<InputEvent>> &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);
 

+ 4 - 4
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<NodePath, uint32_t> used_tracks[TRACK_CHANNEL_MAX];
+	HashMap<NodePath, uint32_t> 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<NodePath, uint32_t>::Element J = used_tracks[j].front(); J; J = J.next()) {
-				if (J.get() == pass) {
+			for (const KeyValue<NodePath, uint32_t> &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) {

+ 1 - 1
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"

+ 3 - 3
editor/plugins/script_editor_plugin.cpp

@@ -119,9 +119,9 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
 	}
 
 	/* Autoloads. */
-	OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-	for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-		const ProjectSettings::AutoloadInfo &info = E.value();
+	HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+	for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
+		const ProjectSettings::AutoloadInfo &info = E.value;
 		if (info.is_singleton) {
 			highlighter->add_keyword_color(info.name, usertype_color);
 		}

+ 55 - 55
editor/plugins/theme_editor_plugin.cpp

@@ -2339,8 +2339,8 @@ void ThemeTypeEditor::_update_type_list_debounced() {
 	update_debounce_timer->start();
 }
 
-OrderedHashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) {
-	OrderedHashMap<StringName, bool> items;
+HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) {
+	HashMap<StringName, bool> items;
 	List<StringName> names;
 
 	if (include_default) {
@@ -2367,12 +2367,12 @@ OrderedHashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_
 	}
 
 	List<StringName> keys;
-	for (OrderedHashMap<StringName, bool>::Element E = items.front(); E; E = E.next()) {
-		keys.push_back(E.key());
+	for (const KeyValue<StringName, bool> &E : items) {
+		keys.push_back(E.key);
 	}
 	keys.sort_custom<StringName::AlphCompare>();
 
-	OrderedHashMap<StringName, bool> ordered_items;
+	HashMap<StringName, bool> 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<StringName, bool> color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default);
-		for (OrderedHashMap<StringName, bool>::Element E = color_items.front(); E; E = E.next()) {
-			HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key(), E.get());
+		HashMap<StringName, bool> color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default);
+		for (const KeyValue<StringName, bool> &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<StringName, bool> constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default);
-		for (OrderedHashMap<StringName, bool>::Element E = constant_items.front(); E; E = E.next()) {
-			HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key(), E.get());
+		HashMap<StringName, bool> constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default);
+		for (const KeyValue<StringName, bool> &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<StringName, bool> font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default);
-		for (OrderedHashMap<StringName, bool>::Element E = font_items.front(); E; E = E.next()) {
-			HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key(), E.get());
+		HashMap<StringName, bool> font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default);
+		for (const KeyValue<StringName, bool> &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<Resource>());
 				}
 				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<Resource>());
 				}
@@ -2563,9 +2563,9 @@ void ThemeTypeEditor::_update_type_items() {
 			font_size_items_list->remove_child(node);
 		}
 
-		OrderedHashMap<StringName, bool> font_size_items = _get_type_items(edited_type, &Theme::get_font_size_list, show_default);
-		for (OrderedHashMap<StringName, bool>::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<StringName, bool> font_size_items = _get_type_items(edited_type, &Theme::get_font_size_list, show_default);
+		for (const KeyValue<StringName, bool> &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<StringName, bool> icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default);
-		for (OrderedHashMap<StringName, bool>::Element E = icon_items.front(); E; E = E.next()) {
-			HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key(), E.get());
+		HashMap<StringName, bool> icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default);
+		for (const KeyValue<StringName, bool> &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<Resource>());
 				}
 				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<Resource>());
 				}
@@ -2664,26 +2664,26 @@ void ThemeTypeEditor::_update_type_items() {
 			stylebox_items_list->add_child(memnew(HSeparator));
 		}
 
-		OrderedHashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default);
-		for (OrderedHashMap<StringName, bool>::Element E = stylebox_items.front(); E; E = E.next()) {
-			if (leading_stylebox.pinned && leading_stylebox.item_name == E.key()) {
+		HashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default);
+		for (const KeyValue<StringName, bool> &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<Resource>());
 				}
 				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<Resource>());
 				}

+ 1 - 1
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<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default);
+	HashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) 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();

+ 4 - 4
editor/pot_generator.cpp

@@ -39,7 +39,7 @@ POTGenerator *POTGenerator::singleton = nullptr;
 
 #ifdef DEBUG_POT
 void POTGenerator::_print_all_translation_strings() {
-	for (OrderedHashMap<String, Vector<POTGenerator::MsgidData>>::Element E = all_translation_strings.front(); E; E = E.next()) {
+	for (HashMap<String, Vector<POTGenerator::MsgidData>>::Element E = all_translation_strings.front(); E; E = E.next()) {
 		Vector<MsgidData> 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<String, Vector<MsgidData>>::Element E_pair = all_translation_strings.front(); E_pair; E_pair = E_pair.next()) {
-		String msgid = E_pair.key();
-		Vector<MsgidData> v_msgid_data = E_pair.value();
+	for (const KeyValue<String, Vector<MsgidData>> &E_pair : all_translation_strings) {
+		String msgid = E_pair.key;
+		const Vector<MsgidData> &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;

+ 2 - 2
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<String> 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<String, Vector<MsgidData>> all_translation_strings;
+	HashMap<String, Vector<MsgidData>> all_translation_strings;
 
 	void _write_to_pot(const String &p_file);
 	void _write_msgid(Ref<FileAccess> r_file, const String &p_id, bool p_plural);

+ 4 - 4
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<PropertyInfo> props;
-	OrderedHashMap<String, Variant> action_values;
+	HashMap<String, Variant> 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<String, Variant>::Element E = action_values.front(); E; E = E.next()) {
-		String name = E.key();
-		Variant value = E.get();
+	for (const KeyValue<String, Variant> &E : action_values) {
+		String name = E.key;
+		const Variant &value = E.value;
 
 		if (name == target_name) {
 			if (p_before) {

+ 5 - 5
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<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+				HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
 
 				//first pass, add the constants so they exist before any script is loaded
-				for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-					const ProjectSettings::AutoloadInfo &info = E.get();
+				for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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<Node *> to_add;
-				for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-					const ProjectSettings::AutoloadInfo &info = E.get();
+				for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
+					const ProjectSettings::AutoloadInfo &info = E.value;
 
 					Ref<Resource> res = ResourceLoader::load(info.path);
 					ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);

+ 2 - 2
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<StringName, MonitorCall>::Element i = _monitor_map.front(); i; i = i.next()) {
-		return_array.set(index, i.key());
+	for (KeyValue<StringName, MonitorCall> i : _monitor_map) {
+		return_array.set(index, i.key);
 		index++;
 	}
 	return return_array;

+ 2 - 2
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<StringName, MonitorCall> _monitor_map;
+	HashMap<StringName, MonitorCall> _monitor_map;
 	uint64_t _monitor_modification_time;
 
 public:

+ 2 - 3
modules/gdscript/editor/gdscript_highlighter.cpp

@@ -510,9 +510,8 @@ void GDScriptSyntaxHighlighter::_update_cache() {
 	}
 
 	/* Autoloads. */
-	OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-	for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-		const ProjectSettings::AutoloadInfo &info = E.value();
+	for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+		const ProjectSettings::AutoloadInfo &info = E.value;
 		if (info.is_singleton) {
 			keywords[info.name] = usertype_color;
 		}

+ 3 - 5
modules/gdscript/gdscript_analyzer.cpp

@@ -4218,13 +4218,11 @@ Error GDScriptAnalyzer::resolve_program() {
 	resolve_class_interface(parser->head);
 	resolve_class_body(parser->head);
 
-	List<String> parser_keys;
-	depended_parsers.get_key_list(&parser_keys);
-	for (const String &E : parser_keys) {
-		if (depended_parsers[E].is_null()) {
+	for (KeyValue<String, Ref<GDScriptParserRef>> &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;
 }

+ 2 - 4
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<Variant, int> &K : constant_map) {
+			function->constants.write[K.value] = K.key;
 		}
 	} else {
 		function->_constants_ptr = nullptr;

+ 1 - 1
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<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+				HashMap<StringName, ProjectSettings::AutoloadInfo> 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];

+ 12 - 16
modules/gdscript/gdscript_editor.cpp

@@ -851,9 +851,10 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
 	}
 
 	// Autoload singletons
-	OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-	for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-		const ProjectSettings::AutoloadInfo &info = E.get();
+	HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+
+	for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-	for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-		if (!E.value().is_singleton) {
+	for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-
-												for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-													String name = E.key();
+												for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-
-				for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-					String path = "/root/" + E.key();
+				for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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);
 				}

+ 11 - 15
modules/gdscript/gdscript_parser.cpp

@@ -100,10 +100,8 @@ void GDScriptParser::cleanup() {
 }
 
 void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
-	List<StringName> keys;
-	valid_annotations.get_key_list(&keys);
-	for (const StringName &E : keys) {
-		r_annotations->push_back(valid_annotations[E].info);
+	for (const KeyValue<StringName, AnnotationInfo> &E : valid_annotations) {
+		r_annotations->push_back(E.value.info);
 	}
 }
 
@@ -1894,11 +1892,8 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
 
 	SuiteNode *suite = alloc_node<SuiteNode>();
 	if (branch->patterns.size() > 0) {
-		List<StringName> 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<StringName, IdentifierNode *> &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<StringName, int>::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<StringName, int> &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;

+ 1 - 1
modules/gdscript/gdscript_parser.h

@@ -132,7 +132,7 @@ public:
 		ClassNode *class_type = nullptr;
 
 		MethodInfo method_info; // For callable/signals.
-		OrderedHashMap<StringName, int> enum_values; // For enums.
+		HashMap<StringName, int> enum_values; // For enums.
 
 		_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
 		_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }

+ 12 - 20
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<lsp::DocumentLink> &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<String, const lsp::DocumentSymbol *> &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<String, ClassMembers> &E : inner_classes) {
+			const ClassMembers *inner_class = &E.value;
+
+			for (const KeyValue<String, const lsp::DocumentSymbol *> &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);
 		}
 	}
 

+ 18 - 14
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<LSPeer> 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<LSPeer> peer = clients.get(*id);
+
+	HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin();
+	while (E != clients.end()) {
+		Ref<LSPeer> 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<LSPeer> peer = clients.get(*id);
+	for (const KeyValue<int, Ref<LSPeer>> &E : clients) {
+		Ref<LSPeer> peer = clients.get(E.key);
 		peer->connection->disconnect_from_host();
 	}
 

+ 5 - 13
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<StringName, ClassMembers> &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members;
+		for (const KeyValue<StringName, ClassMembers> &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<String, const lsp::DocumentSymbol *> &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);
 		}
 	}
 }

+ 6 - 12
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<StringName, ClassMembers> &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<String, ExtendGDScriptParser *> &E : scripts) {
@@ -698,15 +696,11 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
 				r_list.push_back(*symbol);
 			}
 
-			const HashMap<String, ClassMembers> &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<String, ClassMembers> &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);
 			}
 		}
 	}

+ 5 - 5
modules/gdscript/tests/gdscript_test_runner.cpp

@@ -48,11 +48,11 @@
 namespace GDScriptTests {
 
 void init_autoloads() {
-	OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+	HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
 
 	// First pass, add the constants so they exist before any script is loaded.
-	for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-		const ProjectSettings::AutoloadInfo &info = E.get();
+	for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-		const ProjectSettings::AutoloadInfo &info = E.get();
+	for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &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.

+ 14 - 27
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<StringName> names;
+	List<StringName> class_list;
+	ClassDB::get_class_list(&class_list);
+	// Must be alphabetically sorted for hash to compute.
+	class_list.sort_custom<StringName::AlphCompare>();
 
-	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<StringName::AlphCompare>();
-
-	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<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->method_map.next(k))) {
-				String name = k->operator String();
+			for (const KeyValue<StringName, MethodBind *> &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<StringName::AlphCompare>();
@@ -131,10 +124,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
 
 			List<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->constant_map.next(k))) {
-				snames.push_back(*k);
+			for (const KeyValue<StringName, int> &F : t->constant_map) {
+				snames.push_back(F.key);
 			}
 
 			snames.sort_custom<StringName::AlphCompare>();
@@ -158,10 +149,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
 
 			List<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->signal_map.next(k))) {
-				snames.push_back(*k);
+			for (const KeyValue<StringName, MethodInfo> &F : t->signal_map) {
+				snames.push_back(F.key);
 			}
 
 			snames.sort_custom<StringName::AlphCompare>();
@@ -193,10 +182,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
 
 			List<StringName> snames;
 
-			k = nullptr;
-
-			while ((k = t->property_setget.next(k))) {
-				snames.push_back(*k);
+			for (const KeyValue<StringName, ClassDB::PropertySetGet> &F : t->property_setget) {
+				snames.push_back(F.key);
 			}
 
 			snames.sort_custom<StringName::AlphCompare>();

+ 4 - 4
modules/mono/csharp_script.cpp

@@ -1798,8 +1798,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
 
 void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
 	List<PropertyInfo> props;
-	for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) {
-		props.push_front(E.value());
+	for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) {
+		props.push_front(E.value);
 	}
 
 	// Call _get_property_list
@@ -3491,8 +3491,8 @@ Ref<Script> CSharpScript::get_base_script() const {
 void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const {
 	List<PropertyInfo> props;
 
-	for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) {
-		props.push_front(E.value());
+	for (const KeyValue<StringName, PropertyInfo> &E : member_info) {
+		props.push_front(E.value);
 	}
 
 	for (const PropertyInfo &prop : props) {

+ 1 - 1
modules/mono/csharp_script.h

@@ -154,7 +154,7 @@ private:
 	Set<StringName> exported_members_names;
 #endif
 
-	OrderedHashMap<StringName, PropertyInfo> member_info;
+	HashMap<StringName, PropertyInfo> member_info;
 
 	void _clear();
 

+ 20 - 22
modules/mono/editor/bindings_generator.cpp

@@ -1078,8 +1078,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
 		compile_items.push_back(output_file);
 	}
 
-	for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
-		const TypeInterface &itype = E.get();
+	for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+		const TypeInterface &itype = E.value;
 
 		if (itype.api_type == ClassDB::API_EDITOR) {
 			continue;
@@ -1187,8 +1187,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
 
 	Vector<String> compile_items;
 
-	for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
-		const TypeInterface &itype = E.get();
+	for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+		const TypeInterface &itype = E.value;
 
 		if (itype.api_type != ClassDB::API_EDITOR) {
 			continue;
@@ -1573,9 +1573,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
 	// Search it in base types too
 	const TypeInterface *current_type = &p_itype;
 	while (!setter && current_type->base_name != StringName()) {
-		OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
+		HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name);
 		ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
-		current_type = &base_match.get();
+		current_type = &base_match->value;
 		setter = current_type->find_method_by_name(p_iprop.setter);
 	}
 
@@ -1584,9 +1584,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
 	// Search it in base types too
 	current_type = &p_itype;
 	while (!getter && current_type->base_name != StringName()) {
-		OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
+		HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name);
 		ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
-		current_type = &base_match.get();
+		current_type = &base_match->value;
 		getter = current_type->find_method_by_name(p_iprop.getter);
 	}
 
@@ -2096,8 +2096,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
 
 	generated_icall_funcs.clear();
 
-	for (OrderedHashMap<StringName, TypeInterface>::Element type_elem = obj_types.front(); type_elem; type_elem = type_elem.next()) {
-		const TypeInterface &itype = type_elem.get();
+	for (const KeyValue<StringName, TypeInterface> &type_elem : obj_types) {
+		const TypeInterface &itype = type_elem.value;
 
 		bool is_derived_type = itype.base_name != StringName();
 
@@ -2474,10 +2474,10 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(con
 		return &builtin_type_match->get();
 	}
 
-	const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_typeref.cname);
+	const HashMap<StringName, TypeInterface>::Iterator obj_type_match = obj_types.find(p_typeref.cname);
 
 	if (obj_type_match) {
-		return &obj_type_match.get();
+		return &obj_type_match->value;
 	}
 
 	if (p_typeref.is_enum) {
@@ -2942,12 +2942,11 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
 		// Populate signals
 
 		const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map;
-		const StringName *k = nullptr;
 
-		while ((k = signal_map.next(k))) {
+		for (const KeyValue<StringName, MethodInfo> &E : signal_map) {
 			SignalInterface isignal;
 
-			const MethodInfo &method_info = signal_map.get(*k);
+			const MethodInfo &method_info = E.value;
 
 			isignal.name = method_info.name;
 			isignal.cname = method_info.name;
@@ -3024,10 +3023,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
 		ClassDB::get_integer_constant_list(type_cname, &constants, true);
 
 		const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map;
-		k = nullptr;
 
-		while ((k = enum_map.next(k))) {
-			StringName enum_proxy_cname = *k;
+		for (const KeyValue<StringName, List<StringName>> &E : enum_map) {
+			StringName enum_proxy_cname = E.key;
 			String enum_proxy_name = enum_proxy_cname.operator String();
 			if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
 				// We have several conflicts between enums and PascalCase properties,
@@ -3036,7 +3034,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
 				enum_proxy_cname = StringName(enum_proxy_name);
 			}
 			EnumInterface ienum(enum_proxy_cname);
-			const List<StringName> &enum_constants = enum_map.get(*k);
+			const List<StringName> &enum_constants = E.value;
 			for (const StringName &constant_cname : enum_constants) {
 				String constant_name = constant_cname.operator String();
 				int *value = class_info->constant_map.getptr(constant_cname);
@@ -3066,7 +3064,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
 
 			TypeInterface enum_itype;
 			enum_itype.is_enum = true;
-			enum_itype.name = itype.name + "." + String(*k);
+			enum_itype.name = itype.name + "." + String(E.key);
 			enum_itype.cname = StringName(enum_itype.name);
 			enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
 			TypeInterface::postsetup_enum_type(enum_itype);
@@ -3715,8 +3713,8 @@ void BindingsGenerator::_initialize() {
 	core_custom_icalls.clear();
 	editor_custom_icalls.clear();
 
-	for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
-		_generate_method_icalls(E.get());
+	for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+		_generate_method_icalls(E.value);
 	}
 
 	initialized = true;

+ 1 - 1
modules/mono/editor/bindings_generator.h

@@ -533,7 +533,7 @@ class BindingsGenerator {
 	bool log_print_enabled = true;
 	bool initialized = false;
 
-	OrderedHashMap<StringName, TypeInterface> obj_types;
+	HashMap<StringName, TypeInterface> obj_types;
 
 	Map<StringName, TypeInterface> placeholder_types;
 	Map<StringName, TypeInterface> builtin_types;

+ 3 - 3
modules/mono/editor/code_completion.cpp

@@ -121,10 +121,10 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
 		case CompletionKind::NODE_PATHS: {
 			{
 				// Autoloads.
-				OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+				HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
 
-				for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
-					const ProjectSettings::AutoloadInfo &info = E.value();
+				for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
+					const ProjectSettings::AutoloadInfo &info = E.value;
 					suggestions.push_back(quoted("/root/" + String(info.name)));
 				}
 			}

+ 10 - 15
modules/mono/mono_gd/gd_mono.cpp

@@ -1167,9 +1167,8 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
 	int32_t domain_id = mono_domain_get_id(mono_domain_get());
 	HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
 
-	const String *k = nullptr;
-	while ((k = domain_assemblies.next(k))) {
-		GDMonoAssembly *assembly = domain_assemblies.get(*k);
+	for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+		GDMonoAssembly *assembly = E.value;
 		if (assembly->get_image() == image) {
 			GDMonoClass *klass = assembly->get_class(p_raw_class);
 			if (klass) {
@@ -1190,9 +1189,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &
 	int32_t domain_id = mono_domain_get_id(mono_domain_get());
 	HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
 
-	const String *k = nullptr;
-	while ((k = domain_assemblies.next(k))) {
-		GDMonoAssembly *assembly = domain_assemblies.get(*k);
+	for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+		GDMonoAssembly *assembly = E.value;
 		klass = assembly->get_class(p_namespace, p_name);
 		if (klass) {
 			return klass;
@@ -1205,9 +1203,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &
 void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
 	HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
 
-	const String *k = nullptr;
-	while ((k = domain_assemblies.next(k))) {
-		memdelete(domain_assemblies.get(*k));
+	for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+		memdelete(E.value);
 	}
 
 	assemblies.erase(p_domain_id);
@@ -1298,13 +1295,11 @@ GDMono::~GDMono() {
 		// Leave the rest to 'mono_jit_cleanup'
 #endif
 
-		const int32_t *k = nullptr;
-		while ((k = assemblies.next(k))) {
-			HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
+		for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) {
+			const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value;
 
-			const String *kk = nullptr;
-			while ((kk = domain_assemblies.next(kk))) {
-				memdelete(domain_assemblies.get(*kk));
+			for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) {
+				memdelete(F.value);
 			}
 		}
 		assemblies.clear();

+ 8 - 11
modules/mono/mono_gd/gd_mono_class.cpp

@@ -247,7 +247,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
 				if (existing_method) {
 					memdelete(*existing_method); // Must delete old one
 				}
-				methods.set(key, method);
+				methods.insert(key, method);
 
 				break;
 			}
@@ -266,11 +266,9 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
 GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) {
 	ERR_FAIL_COND_V(!methods_fetched, nullptr);
 
-	const MethodKey *k = nullptr;
-
-	while ((k = methods.next(k))) {
-		if (k->name == p_name) {
-			return methods.get(*k);
+	for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
+		if (E.key.name == p_name) {
+			return E.value;
 		}
 	}
 
@@ -307,7 +305,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_param
 
 	if (raw_method) {
 		GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
-		methods.set(key, method);
+		methods.insert(key, method);
 
 		return method;
 	}
@@ -342,7 +340,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName
 	}
 
 	GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
-	methods.set(key, method);
+	methods.insert(key, method);
 
 	return method;
 }
@@ -549,9 +547,8 @@ GDMonoClass::~GDMonoClass() {
 		Vector<GDMonoMethod *> deleted_methods;
 		deleted_methods.resize(methods.size());
 
-		const MethodKey *k = nullptr;
-		while ((k = methods.next(k))) {
-			GDMonoMethod *method = methods.get(*k);
+		for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
+			GDMonoMethod *method = E.value;
 
 			if (method) {
 				for (int i = 0; i < offset; i++) {

+ 7 - 10
modules/raycast/raycast_occlusion_cull.cpp

@@ -454,10 +454,9 @@ bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) {
 	next_scene = rtcNewScene(raycast_singleton->ebr_device);
 	rtcSetSceneBuildQuality(next_scene, RTCBuildQuality(raycast_singleton->build_quality));
 
-	const RID *inst_rid = nullptr;
-	while ((inst_rid = instances.next(inst_rid))) {
-		OccluderInstance *occ_inst = instances.getptr(*inst_rid);
-		Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder);
+	for (const KeyValue<RID, OccluderInstance> &E : instances) {
+		const OccluderInstance *occ_inst = &E.value;
+		const Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder);
 
 		if (!occ || !occ_inst->enabled) {
 			continue;
@@ -573,9 +572,8 @@ void RaycastOcclusionCull::set_build_quality(RS::ViewportOcclusionCullingBuildQu
 
 	build_quality = p_quality;
 
-	const RID *scenario_rid = nullptr;
-	while ((scenario_rid = scenarios.next(scenario_rid))) {
-		scenarios[*scenario_rid].dirty = true;
+	for (KeyValue<RID, Scenario> &K : scenarios) {
+		K.value.dirty = true;
 	}
 }
 
@@ -596,9 +594,8 @@ RaycastOcclusionCull::RaycastOcclusionCull() {
 }
 
 RaycastOcclusionCull::~RaycastOcclusionCull() {
-	const RID *scenario_rid = nullptr;
-	while ((scenario_rid = scenarios.next(scenario_rid))) {
-		Scenario &scenario = scenarios[*scenario_rid];
+	for (KeyValue<RID, Scenario> &K : scenarios) {
+		Scenario &scenario = K.value;
 		if (scenario.commit_thread) {
 			scenario.commit_thread->wait_to_finish();
 			memdelete(scenario.commit_thread);

+ 4 - 6
modules/text_server_adv/text_server_adv.cpp

@@ -2371,9 +2371,8 @@ Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vecto
 
 	Array ret;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
-	const int32_t *E = nullptr;
-	while ((E = gl.next(E))) {
-		ret.push_back(*E);
+	for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+		ret.push_back(E.key);
 	}
 	return ret;
 }
@@ -2864,9 +2863,8 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const
 #endif
 	if (at_size) {
 		const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
-		const int32_t *E = nullptr;
-		while ((E = gl.next(E))) {
-			chars = chars + String::chr(*E);
+		for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+			chars = chars + String::chr(E.key);
 		}
 	}
 	return chars;

+ 4 - 6
modules/text_server_fb/text_server_fb.cpp

@@ -1533,9 +1533,8 @@ Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vecto
 
 	Array ret;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
-	const int32_t *E = nullptr;
-	while ((E = gl.next(E))) {
-		ret.push_back(*E);
+	for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+		ret.push_back(E.key);
 	}
 	return ret;
 }
@@ -1994,9 +1993,8 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const
 #endif
 	if (at_size) {
 		const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
-		const int32_t *E = nullptr;
-		while ((E = gl.next(E))) {
-			chars = chars + String::chr(*E);
+		for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+			chars = chars + String::chr(E.key);
 		}
 	}
 	return chars;

+ 5 - 7
modules/visual_script/editor/visual_script_editor.cpp

@@ -1608,7 +1608,7 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
 		if (E.from_node == p_id && E.from_port == p_port) {
 			// Push into the connections map.
 			if (!conn_map.has(E.to_node)) {
-				conn_map.set(E.to_node, Set<int>());
+				conn_map.insert(E.to_node, Set<int>());
 			}
 			conn_map[E.to_node].insert(E.to_port);
 		}
@@ -1617,11 +1617,9 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
 	undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port);
 	undo_redo->add_do_method(this, "_update_graph", p_id);
 
-	List<int> keys;
-	conn_map.get_key_list(&keys);
-	for (const int &E : keys) {
-		for (const Set<int>::Element *F = conn_map[E].front(); F; F = F->next()) {
-			undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E, F->get());
+	for (const KeyValue<int, Set<int>> &E : conn_map) {
+		for (const Set<int>::Element *F = E.value.front(); F; F = F->next()) {
+			undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F->get());
 		}
 	}
 
@@ -1912,7 +1910,7 @@ void VisualScriptEditor::_on_nodes_duplicate() {
 		Ref<VisualScriptNode> dupe = node->duplicate(true);
 
 		int new_id = idc++;
-		remap.set(F->get(), new_id);
+		remap.insert(F->get(), new_id);
 
 		to_select.insert(new_id);
 		undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F->get()) + Vector2(20, 20));

+ 66 - 93
modules/visual_script/visual_script.cpp

@@ -209,8 +209,9 @@ Vector2 VisualScript::get_scroll() const {
 }
 
 void VisualScript::get_function_list(List<StringName> *r_functions) const {
-	functions.get_key_list(r_functions);
-	// r_functions->sort_custom<StringName::AlphCompare>(); // Don't force sorting.
+	for (const KeyValue<StringName, Function> &E : functions) {
+		r_functions->push_back(E.key);
+	}
 }
 
 int VisualScript::get_function_node_id(const StringName &p_name) const {
@@ -346,7 +347,9 @@ Point2 VisualScript::get_node_position(int p_id) const {
 }
 
 void VisualScript::get_node_list(List<int> *r_nodes) const {
-	nodes.get_key_list(r_nodes);
+	for (const KeyValue<int, NodeData> &E : nodes) {
+		r_nodes->push_back(E.key);
+	}
 }
 
 void VisualScript::sequence_connect(int p_from_node, int p_from_output, int p_to_node) {
@@ -563,8 +566,9 @@ Dictionary VisualScript::_get_variable_info(const StringName &p_name) const {
 }
 
 void VisualScript::get_variable_list(List<StringName> *r_variables) const {
-	variables.get_key_list(r_variables);
-	// r_variables->sort_custom<StringName::AlphCompare>(); // Don't force it.
+	for (const KeyValue<StringName, Variable> &E : variables) {
+		r_variables->push_back(E.key);
+	}
 }
 
 void VisualScript::set_instance_base_type(const StringName &p_type) {
@@ -713,12 +717,11 @@ int VisualScript::get_available_id() const {
 	// This is infinitely increasing,
 	// so one might want to implement a better solution,
 	// if the there is a case for huge number of nodes to be added to visual script.
-	List<int> nds;
-	nodes.get_key_list(&nds);
+
 	int max = -1;
-	for (const int &E : nds) {
-		if (E > max) {
-			max = E;
+	for (const KeyValue<int, NodeData> &E : nodes) {
+		if (E.key > max) {
+			max = E.key;
 		}
 	}
 	return (max + 1);
@@ -750,18 +753,15 @@ void VisualScript::_update_placeholders() {
 	List<PropertyInfo> pinfo;
 	Map<StringName, Variant> values;
 
-	List<StringName> keys;
-	variables.get_key_list(&keys);
-
-	for (const StringName &E : keys) {
-		if (!variables[E]._export) {
+	for (const KeyValue<StringName, Variable> &E : variables) {
+		if (!variables[E.key]._export) {
 			continue;
 		}
 
-		PropertyInfo p = variables[E].info;
-		p.name = String(E);
+		PropertyInfo p = variables[E.key].info;
+		p.name = String(E.key);
 		pinfo.push_back(p);
-		values[p.name] = variables[E].default_value;
+		values[p.name] = variables[E.key].default_value;
 	}
 
 	for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
@@ -781,18 +781,15 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) {
 		List<PropertyInfo> pinfo;
 		Map<StringName, Variant> values;
 
-		List<StringName> keys;
-		variables.get_key_list(&keys);
-
-		for (const StringName &E : keys) {
-			if (!variables[E]._export) {
+		for (const KeyValue<StringName, Variable> &E : variables) {
+			if (!variables[E.key]._export) {
 				continue;
 			}
 
-			PropertyInfo p = variables[E].info;
-			p.name = String(E);
+			PropertyInfo p = variables[E.key].info;
+			p.name = String(E.key);
 			pinfo.push_back(p);
-			values[p.name] = variables[E].default_value;
+			values[p.name] = variables[E.key].default_value;
 		}
 		sins->update(pinfo, values);
 
@@ -872,14 +869,11 @@ bool VisualScript::get_property_default_value(const StringName &p_property, Vari
 }
 
 void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
-	List<StringName> funcs;
-	functions.get_key_list(&funcs);
-
-	for (const StringName &E : funcs) {
+	for (const KeyValue<StringName, Function> &E : functions) {
 		MethodInfo mi;
-		mi.name = E;
-		if (functions[E].func_id >= 0) {
-			Ref<VisualScriptFunction> func = nodes[functions[E].func_id].node;
+		mi.name = E.key;
+		if (functions[E.key].func_id >= 0) {
+			Ref<VisualScriptFunction> func = nodes[functions[E.key].func_id].node;
 			if (func.is_valid()) {
 				for (int i = 0; i < func->get_argument_count(); i++) {
 					PropertyInfo arg;
@@ -945,10 +939,8 @@ int VisualScript::get_member_line(const StringName &p_member) const {
 
 #ifdef TOOLS_ENABLED
 bool VisualScript::are_subnodes_edited() const {
-	List<int> keys;
-	nodes.get_key_list(&keys);
-	for (const int &F : keys) {
-		if (nodes[F].node->is_edited()) {
+	for (const KeyValue<int, NodeData> &F : nodes) {
+		if (F.value.node->is_edited()) {
 			return true;
 		}
 	}
@@ -1017,15 +1009,13 @@ void VisualScript::_set_data(const Dictionary &p_data) {
 
 	// Takes all the rpc methods.
 	rpc_functions.clear();
-	List<StringName> fns;
-	functions.get_key_list(&fns);
-	for (const StringName &E : fns) {
-		if (functions[E].func_id >= 0 && nodes.has(functions[E].func_id)) {
-			Ref<VisualScriptFunction> vsf = nodes[functions[E].func_id].node;
+	for (const KeyValue<StringName, Function> &E : functions) {
+		if (E.value.func_id >= 0 && nodes.has(E.value.func_id)) {
+			Ref<VisualScriptFunction> vsf = nodes[E.value.func_id].node;
 			if (vsf.is_valid()) {
 				if (vsf->get_rpc_mode() != Multiplayer::RPC_MODE_DISABLED) {
 					Multiplayer::RPCConfig nd;
-					nd.name = E;
+					nd.name = E.key;
 					nd.rpc_mode = vsf->get_rpc_mode();
 					nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; // TODO
 					if (rpc_functions.find(nd) == -1) {
@@ -1045,13 +1035,11 @@ Dictionary VisualScript::_get_data() const {
 	d["base_type"] = base_type;
 
 	Array vars;
-	List<StringName> var_names;
-	variables.get_key_list(&var_names);
-	for (const StringName &E : var_names) {
-		Dictionary var = _get_variable_info(E);
-		var["name"] = E; // Make sure it's the right one.
-		var["default_value"] = variables[E].default_value;
-		var["export"] = variables[E]._export;
+	for (const KeyValue<StringName, Variable> &E : variables) {
+		Dictionary var = _get_variable_info(E.key);
+		var["name"] = E.key; // Make sure it's the right one.
+		var["default_value"] = E.value.default_value;
+		var["export"] = E.value._export;
 		vars.push_back(var);
 	}
 	d["variables"] = vars;
@@ -1073,23 +1061,19 @@ Dictionary VisualScript::_get_data() const {
 	d["signals"] = sigs;
 
 	Array funcs;
-	List<StringName> func_names;
-	functions.get_key_list(&func_names);
-	for (const StringName &E : func_names) {
+	for (const KeyValue<StringName, Function> &E : functions) {
 		Dictionary func;
-		func["name"] = E;
-		func["function_id"] = functions[E].func_id;
+		func["name"] = E.key;
+		func["function_id"] = E.value.func_id;
 		funcs.push_back(func);
 	}
 	d["functions"] = funcs;
 
 	Array nds;
-	List<int> node_ids;
-	nodes.get_key_list(&node_ids);
-	for (const int &F : node_ids) {
-		nds.push_back(F);
-		nds.push_back(nodes[F].pos);
-		nds.push_back(nodes[F].node);
+	for (const KeyValue<int, NodeData> &F : nodes) {
+		nds.push_back(F.key);
+		nds.push_back(F.value.pos);
+		nds.push_back(F.value.node);
 	}
 	d["nodes"] = nds;
 
@@ -1199,10 +1183,8 @@ Set<int> VisualScript::get_output_sequence_ports_connected(int from_node) {
 
 VisualScript::~VisualScript() {
 	// Remove all nodes and stuff that hold data refs.
-	List<int> nds;
-	nodes.get_key_list(&nds);
-	for (const int &E : nds) {
-		remove_node(E);
+	for (const KeyValue<int, NodeData> &E : nodes) {
+		remove_node(E.key);
 	}
 }
 
@@ -1230,14 +1212,12 @@ bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
 }
 
 void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
-	List<StringName> vars;
-	script->variables.get_key_list(&vars);
-	for (const StringName &E : vars) {
-		if (!script->variables[E]._export) {
+	for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) {
+		if (!E.value._export) {
 			continue;
 		}
-		PropertyInfo p = script->variables[E].info;
-		p.name = String(E);
+		PropertyInfo p = E.value.info;
+		p.name = String(E.key);
 		p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
 		p_properties->push_back(p);
 	}
@@ -1259,13 +1239,11 @@ Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name,
 }
 
 void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
-	List<StringName> fns;
-	script->functions.get_key_list(&fns);
-	for (const StringName &E : fns) {
+	for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) {
 		MethodInfo mi;
-		mi.name = E;
-		if (script->functions[E].func_id >= 0 && script->nodes.has(script->functions[E].func_id)) {
-			Ref<VisualScriptFunction> vsf = script->nodes[script->functions[E].func_id].node;
+		mi.name = E.key;
+		if (E.value.func_id >= 0 && script->nodes.has(E.value.func_id)) {
+			Ref<VisualScriptFunction> vsf = script->nodes[E.value.func_id].node;
 			if (vsf.is_valid()) {
 				for (int i = 0; i < vsf->get_argument_count(); i++) {
 					PropertyInfo arg;
@@ -1845,19 +1823,15 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
 
 	// Setup variables.
 	{
-		List<StringName> keys;
-		script->variables.get_key_list(&keys);
-		for (const StringName &E : keys) {
-			variables[E] = script->variables[E].default_value;
+		for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) {
+			variables[E.key] = E.value.default_value;
 		}
 	}
 
 	// Setup functions from sequence trees.
 	{
-		List<StringName> keys;
-		script->functions.get_key_list(&keys);
-		for (const StringName &E : keys) {
-			const VisualScript::Function vsfn = p_script->functions[E];
+		for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) {
+			const VisualScript::Function &vsfn = E.value;
 			Function function;
 			function.node = vsfn.func_id;
 			function.max_stack = 0;
@@ -1868,7 +1842,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
 			Map<StringName, int> local_var_indices;
 
 			if (function.node < 0) {
-				VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E));
+				VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E.key));
 				ERR_CONTINUE(function.node < 0);
 			}
 
@@ -1876,7 +1850,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
 				Ref<VisualScriptFunction> func_node = script->get_node(vsfn.func_id);
 
 				if (func_node.is_null()) {
-					VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E));
+					VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E.key));
 				}
 
 				ERR_CONTINUE(!func_node.is_valid());
@@ -1916,13 +1890,12 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
 				List<int> dc_keys;
 				while (!nd_queue.is_empty()) {
 					int ky = nd_queue.front()->get();
-					dc_lut[ky].get_key_list(&dc_keys);
-					for (const int &F : dc_keys) {
+					for (const KeyValue<int, Pair<int, int>> &F : dc_lut[ky]) {
 						VisualScript::DataConnection dc;
-						dc.from_node = dc_lut[ky][F].first;
-						dc.from_port = dc_lut[ky][F].second;
+						dc.from_node = F.value.first;
+						dc.from_port = F.value.second;
 						dc.to_node = ky;
-						dc.to_port = F;
+						dc.to_port = F.key;
 						dataconns.insert(dc);
 						nd_queue.push_back(dc.from_node);
 						node_ids.insert(dc.from_node);
@@ -2072,7 +2045,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
 				}
 			}
 
-			functions[E] = function;
+			functions[E.key] = function;
 		}
 	}
 }

+ 10 - 15
platform/iphone/export/export_plugin.cpp

@@ -107,16 +107,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
 	for (int i = 0; i < found_plugins.size(); i++) {
 		// Editable plugin plist values
 		PluginConfigIOS plugin = found_plugins[i];
-		const String *K = nullptr;
 
-		while ((K = plugin.plist.next(K))) {
-			String key = *K;
-			PluginConfigIOS::PlistItem item = plugin.plist[key];
-			switch (item.type) {
+		for (const KeyValue<String, PluginConfigIOS::PlistItem> &E : plugin.plist) {
+			switch (E.value.type) {
 				case PluginConfigIOS::PlistItemType::STRING_INPUT: {
-					String preset_name = "plugins_plist/" + key;
+					String preset_name = "plugins_plist/" + E.key;
 					if (!plist_keys.has(preset_name)) {
-						r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, preset_name), item.value));
+						r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, preset_name), E.value.value));
 						plist_keys.insert(preset_name);
 					}
 				} break;
@@ -1258,11 +1255,10 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
 
 		// Plist
 		// Using hash map container to remove duplicates
-		const String *K = nullptr;
 
-		while ((K = plugin.plist.next(K))) {
-			String key = *K;
-			PluginConfigIOS::PlistItem item = plugin.plist[key];
+		for (const KeyValue<String, PluginConfigIOS::PlistItem> &E : plugin.plist) {
+			String key = E.key;
+			const PluginConfigIOS::PlistItem &item = E.value;
 
 			String value;
 
@@ -1301,10 +1297,9 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
 
 	// Updating `Info.plist`
 	{
-		const String *K = nullptr;
-		while ((K = plist_values.next(K))) {
-			String key = *K;
-			String value = plist_values[key];
+		for (const KeyValue<String, String> &E : plist_values) {
+			String key = E.key;
+			String value = E.value;
 
 			if (key.is_empty() || value.is_empty()) {
 				continue;

+ 14 - 20
scene/animation/animation_tree.cpp

@@ -198,12 +198,11 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
 			blendw[i] = 0.0; //all to zero by default
 		}
 
-		const NodePath *K = nullptr;
-		while ((K = filter.next(K))) {
-			if (!state->track_map.has(*K)) {
+		for (const KeyValue<NodePath, bool> &E : filter) {
+			if (!state->track_map.has(E.key)) {
 				continue;
 			}
-			int idx = state->track_map[*K];
+			int idx = state->track_map[E.key];
 			blendw[idx] = 1.0; //filtered goes to one
 		}
 
@@ -374,9 +373,8 @@ bool AnimationNode::has_filter() const {
 Array AnimationNode::_get_filters() const {
 	Array paths;
 
-	const NodePath *K = nullptr;
-	while ((K = filter.next(K))) {
-		paths.push_back(String(*K)); //use strings, so sorting is possible
+	for (const KeyValue<NodePath, bool> &E : filter) {
+		paths.push_back(String(E.key)); //use strings, so sorting is possible
 	}
 	paths.sort(); //done so every time the scene is saved, it does not change
 
@@ -803,11 +801,10 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
 
 	List<NodePath> to_delete;
 
-	const NodePath *K = nullptr;
-	while ((K = track_cache.next(K))) {
-		TrackCache *tc = track_cache[*K];
+	for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+		TrackCache *tc = track_cache[K.key];
 		if (tc->setup_pass != setup_pass) {
-			to_delete.push_back(*K);
+			to_delete.push_back(K.key);
 		}
 	}
 
@@ -820,10 +817,9 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
 
 	state.track_map.clear();
 
-	K = nullptr;
 	int idx = 0;
-	while ((K = track_cache.next(K))) {
-		state.track_map[*K] = idx;
+	for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+		state.track_map[K.key] = idx;
 		idx++;
 	}
 
@@ -835,9 +831,8 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
 }
 
 void AnimationTree::_clear_caches() {
-	const NodePath *K = nullptr;
-	while ((K = track_cache.next(K))) {
-		memdelete(track_cache[*K]);
+	for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
+		memdelete(K.value);
 	}
 	playing_caches.clear();
 
@@ -1569,9 +1564,8 @@ void AnimationTree::_process_graph(double p_delta) {
 
 	{
 		// finally, set the tracks
-		const NodePath *K = nullptr;
-		while ((K = track_cache.next(K))) {
-			TrackCache *track = track_cache[*K];
+		for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+			TrackCache *track = K.value;
 			if (track->process_pass != process_pass) {
 				continue; //not processed, ignore
 			}

+ 3 - 1
scene/gui/code_edit.cpp

@@ -3036,7 +3036,9 @@ void CodeEdit::_text_changed() {
 
 	lc = get_line_count();
 	List<int> breakpoints;
-	breakpointed_lines.get_key_list(&breakpoints);
+	for (const KeyValue<int, bool> &E : breakpointed_lines) {
+		breakpoints.push_back(E.key);
+	}
 	for (const int &line : breakpoints) {
 		if (line < lines_edited_from || (line < lc && is_line_breakpointed(line))) {
 			continue;

+ 11 - 11
scene/gui/graph_edit.cpp

@@ -523,7 +523,7 @@ void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<S
 		}
 	}
 
-	p_comment_enclosed_nodes.set(p_node->get_name(), enclosed_nodes);
+	p_comment_enclosed_nodes.insert(p_node->get_name(), enclosed_nodes);
 }
 
 void GraphEdit::_set_drag_comment_enclosed_nodes(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes, bool p_drag) {
@@ -1742,11 +1742,11 @@ HashMap<int, Vector<StringName>> GraphEdit::_layering(const Set<StringName> &r_s
 				Vector<StringName> t;
 				t.push_back(E->get());
 				if (!l.has(current_layer)) {
-					l.set(current_layer, Vector<StringName>{});
+					l.insert(current_layer, Vector<StringName>{});
 				}
 				selected = true;
 				t.append_array(l[current_layer]);
-				l.set(current_layer, t);
+				l.insert(current_layer, t);
 				Set<StringName> V;
 				V.insert(E->get());
 				_set_operations(GraphEdit::UNION, u, V);
@@ -1860,10 +1860,10 @@ void GraphEdit::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layer
 				}
 				d[q] = crossings;
 			}
-			c.set(p, d);
+			c.insert(p, d);
 		}
 
-		r_layers.set(i, _split(lower_layer, c));
+		r_layers.insert(i, _split(lower_layer, c));
 	}
 }
 
@@ -2026,7 +2026,7 @@ void GraphEdit::_place_block(StringName p_v, float p_delta, const HashMap<int, V
 			threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
 			w = r_align[w];
 		} while (w != p_v);
-		r_node_positions.set(p_v, pos);
+		r_node_positions.insert(p_v, pos);
 	}
 
 #undef PRED
@@ -2082,10 +2082,10 @@ void GraphEdit::arrange_nodes() {
 							ports = p_ports;
 						}
 					}
-					port_info.set(_connection, ports);
+					port_info.insert(_connection, ports);
 				}
 			}
-			upper_neighbours.set(gn->get_name(), s);
+			upper_neighbours.insert(gn->get_name(), s);
 		}
 	}
 
@@ -2109,7 +2109,7 @@ void GraphEdit::arrange_nodes() {
 		inner_shift[E->get()] = 0.0f;
 		sink[E->get()] = E->get();
 		shift[E->get()] = FLT_MAX;
-		new_positions.set(E->get(), default_position);
+		new_positions.insert(E->get(), default_position);
 		if ((StringName)root[E->get()] == E->get()) {
 			block_heads.insert(E->get());
 		}
@@ -2129,7 +2129,7 @@ void GraphEdit::arrange_nodes() {
 		do {
 			Vector2 cal_pos;
 			cal_pos.y = start_from + (real_t)inner_shift[u];
-			new_positions.set(u, cal_pos);
+			new_positions.insert(u, cal_pos);
 			u = align[u];
 		} while (u != E->get());
 	}
@@ -2161,7 +2161,7 @@ void GraphEdit::arrange_nodes() {
 				}
 				cal_pos.x = current_node_start_pos;
 			}
-			new_positions.set(layer[j], cal_pos);
+			new_positions.insert(layer[j], cal_pos);
 		}
 
 		start_from += largest_node_size + gap_h;

+ 2 - 2
scene/main/missing_node.cpp

@@ -53,8 +53,8 @@ bool MissingNode::_get(const StringName &p_name, Variant &r_ret) const {
 }
 
 void MissingNode::_get_property_list(List<PropertyInfo> *p_list) const {
-	for (OrderedHashMap<StringName, Variant>::ConstElement E = properties.front(); E; E = E.next()) {
-		p_list->push_back(PropertyInfo(E.value().get_type(), E.key()));
+	for (const KeyValue<StringName, Variant> &E : properties) {
+		p_list->push_back(PropertyInfo(E.value.get_type(), E.key));
 	}
 }
 

+ 1 - 1
scene/main/missing_node.h

@@ -36,7 +36,7 @@
 
 class MissingNode : public Node {
 	GDCLASS(MissingNode, Node)
-	OrderedHashMap<StringName, Variant> properties;
+	HashMap<StringName, Variant> properties;
 
 	String original_class;
 	bool recording_properties = false;

+ 5 - 7
scene/main/scene_tree.cpp

@@ -438,9 +438,8 @@ bool SceneTree::process(double p_time) {
 
 	if (multiplayer_poll) {
 		multiplayer->poll();
-		const NodePath *rpath = nullptr;
-		while ((rpath = custom_multiplayers.next(rpath))) {
-			custom_multiplayers[*rpath]->poll();
+		for (KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
+			E.value->poll();
 		}
 	}
 
@@ -1137,9 +1136,8 @@ Array SceneTree::get_processed_tweens() {
 
 Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const {
 	Ref<MultiplayerAPI> out = multiplayer;
-	const NodePath *spath = nullptr;
-	while ((spath = custom_multiplayers.next(spath))) {
-		const Vector<StringName> snames = (*spath).get_names();
+	for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
+		const Vector<StringName> snames = E.key.get_names();
 		const Vector<StringName> tnames = p_for_path.get_names();
 		if (tnames.size() < snames.size()) {
 			continue;
@@ -1154,7 +1152,7 @@ Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const
 			}
 		}
 		if (valid) {
-			out = custom_multiplayers[*spath];
+			out = E.value;
 			break;
 		}
 	}

+ 9 - 11
scene/main/shader_globals_override.cpp

@@ -229,20 +229,19 @@ void ShaderGlobalsOverride::_activate() {
 		active = true;
 		add_to_group(SceneStringNames::get_singleton()->shader_overrides_group_active);
 
-		const StringName *K = nullptr;
-		while ((K = overrides.next(K))) {
-			Override *o = overrides.getptr(*K);
+		for (const KeyValue<StringName, Override> &E : overrides) {
+			const Override *o = &E.value;
 			if (o->in_use && o->override.get_type() != Variant::NIL) {
 				if (o->override.get_type() == Variant::OBJECT) {
 					RID tex_rid = o->override;
-					RS::get_singleton()->global_variable_set_override(*K, tex_rid);
+					RS::get_singleton()->global_variable_set_override(E.key, tex_rid);
 				} else {
-					RS::get_singleton()->global_variable_set_override(*K, o->override);
+					RS::get_singleton()->global_variable_set_override(E.key, o->override);
 				}
 			}
-		}
 
-		update_configuration_warnings(); //may have activated
+			update_configuration_warnings(); //may have activated
+		}
 	}
 }
 
@@ -256,11 +255,10 @@ void ShaderGlobalsOverride::_notification(int p_what) {
 		case Node3D::NOTIFICATION_EXIT_TREE: {
 			if (active) {
 				//remove overrides
-				const StringName *K = nullptr;
-				while ((K = overrides.next(K))) {
-					Override *o = overrides.getptr(*K);
+				for (const KeyValue<StringName, Override> &E : overrides) {
+					const Override *o = &E.value;
 					if (o->in_use) {
-						RS::get_singleton()->global_variable_set_override(*K, Variant());
+						RS::get_singleton()->global_variable_set_override(E.key, Variant());
 					}
 				}
 			}

+ 3 - 3
scene/multiplayer/multiplayer_spawner.cpp

@@ -91,9 +91,9 @@ void MultiplayerSpawner::_notification(int p_what) {
 
 		case NOTIFICATION_EXIT_TREE: {
 			_update_spawn_node();
-			const ObjectID *oid = nullptr;
-			while ((oid = tracked_nodes.next(oid))) {
-				Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid));
+
+			for (const KeyValue<ObjectID, SpawnInfo> &E : tracked_nodes) {
+				Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E.key));
 				ERR_CONTINUE(!node);
 				node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit));
 				// This is unlikely, but might still crash the engine.

+ 2 - 4
scene/multiplayer/scene_cache_interface.cpp

@@ -50,10 +50,8 @@ void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) {
 		path_get_cache.erase(p_id);
 		// Cleanup sent cache.
 		// Some refactoring is needed to make this faster and do paths GC.
-		List<NodePath> keys;
-		path_send_cache.get_key_list(&keys);
-		for (const NodePath &E : keys) {
-			PathSentCache *psc = path_send_cache.getptr(E);
+		for (const KeyValue<NodePath, PathSentCache> &E : path_send_cache) {
+			PathSentCache *psc = path_send_cache.getptr(E.key);
 			psc->confirmed_peers.erase(p_id);
 		}
 	}

+ 2 - 3
scene/multiplayer/scene_replication_interface.cpp

@@ -49,9 +49,8 @@ void SceneReplicationInterface::make_default() {
 
 void SceneReplicationInterface::_free_remotes(int p_id) {
 	const HashMap<uint32_t, ObjectID> remotes = rep_state->peer_get_remotes(p_id);
-	const uint32_t *k = nullptr;
-	while ((k = remotes.next(k))) {
-		Node *node = rep_state->get_node(remotes.get(*k));
+	for (const KeyValue<uint32_t, ObjectID> &E : remotes) {
+		Node *node = rep_state->get_node(E.value);
 		ERR_CONTINUE(!node);
 		node->queue_delete();
 	}

+ 8 - 12
scene/multiplayer/scene_replication_state.cpp

@@ -55,9 +55,8 @@ void SceneReplicationState::_untrack(const ObjectID &p_id) {
 		}
 		// If we spawned or synced it, we need to remove it from any peer it was sent to.
 		if (net_id || peer == 0) {
-			const int *k = nullptr;
-			while ((k = peers_info.next(k))) {
-				peers_info.get(*k).known_nodes.erase(p_id);
+			for (KeyValue<int, PeerInfo> &E : peers_info) {
+				E.value.known_nodes.erase(p_id);
 			}
 		}
 	}
@@ -134,9 +133,8 @@ void SceneReplicationState::reset() {
 	peers_info.clear();
 	known_peers.clear();
 	// Tracked nodes are cleared on deletion, here we only reset the ids so they can be later re-assigned.
-	const ObjectID *oid = nullptr;
-	while ((oid = tracked_nodes.next(oid))) {
-		TrackedNode &tobj = tracked_nodes[*oid];
+	for (KeyValue<ObjectID, TrackedNode> &E : tracked_nodes) {
+		TrackedNode &tobj = E.value;
 		tobj.net_id = 0;
 		tobj.remote_peer = 0;
 		tobj.last_sync = 0;
@@ -195,9 +193,8 @@ Error SceneReplicationState::peer_add_node(int p_peer, const ObjectID &p_id) {
 		ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
 		peers_info[p_peer].known_nodes.insert(p_id);
 	} else {
-		const int *pid = nullptr;
-		while ((pid = peers_info.next(pid))) {
-			peers_info.get(*pid).known_nodes.insert(p_id);
+		for (KeyValue<int, PeerInfo> &E : peers_info) {
+			E.value.known_nodes.insert(p_id);
 		}
 	}
 	return OK;
@@ -208,9 +205,8 @@ Error SceneReplicationState::peer_del_node(int p_peer, const ObjectID &p_id) {
 		ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER);
 		peers_info[p_peer].known_nodes.erase(p_id);
 	} else {
-		const int *pid = nullptr;
-		while ((pid = peers_info.next(pid))) {
-			peers_info.get(*pid).known_nodes.erase(p_id);
+		for (KeyValue<int, PeerInfo> &E : peers_info) {
+			E.value.known_nodes.erase(p_id);
 		}
 	}
 	return OK;

+ 2 - 2
scene/multiplayer/scene_replication_state.h

@@ -81,8 +81,8 @@ private:
 
 public:
 	const Set<int> get_peers() const { return known_peers; }
-	const Set<ObjectID> get_spawned_nodes() const { return spawned_nodes; }
-	const Set<ObjectID> get_path_only_nodes() const { return path_only_nodes; }
+	const Set<ObjectID> &get_spawned_nodes() const { return spawned_nodes; }
+	const Set<ObjectID> &get_path_only_nodes() const { return path_only_nodes; }
 
 	MultiplayerSynchronizer *get_synchronizer(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_synchronizer() : nullptr; }
 	MultiplayerSpawner *get_spawner(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_spawner() : nullptr; }

+ 4 - 4
scene/resources/packed_scene.cpp

@@ -913,10 +913,10 @@ Error SceneState::pack(Node *p_scene) {
 	}
 
 	variants.resize(variant_map.size());
-	const Variant *K = nullptr;
-	while ((K = variant_map.next(K))) {
-		int idx = variant_map[*K];
-		variants.write[idx] = *K;
+
+	for (const KeyValue<Variant, int> &E : variant_map) {
+		int idx = E.value;
+		variants.write[idx] = E.key;
 	}
 
 	node_paths.resize(nodepath_map.size());

+ 1 - 1
scene/resources/surface_tool.cpp

@@ -1165,7 +1165,7 @@ void SurfaceTool::generate_normals(bool p_flip) {
 		for (int i = 0; i < 3; i++) {
 			Vector3 *lv = vertex_hash.getptr(v[i]);
 			if (!lv) {
-				vertex_hash.set(v[i], normal);
+				vertex_hash.insert(v[i], normal);
 			} else {
 				(*lv) += normal;
 			}

+ 88 - 194
scene/resources/theme.cpp

@@ -123,76 +123,50 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const {
 void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
 	List<PropertyInfo> list;
 
-	const StringName *key = nullptr;
-
 	// Type variations.
-	while ((key = variation_map.next(key))) {
-		list.push_back(PropertyInfo(Variant::STRING_NAME, String() + *key + "/base_type"));
+	for (const KeyValue<StringName, StringName> &E : variation_map) {
+		list.push_back(PropertyInfo(Variant::STRING_NAME, String() + E.key + "/base_type"));
 	}
 
-	key = nullptr;
-
 	// Icons.
-	while ((key = icon_map.next(key))) {
-		const StringName *key2 = nullptr;
-
-		while ((key2 = icon_map[*key].next(key2))) {
-			list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/icons/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
+	for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : icon_map) {
+		for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
+			list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/icons/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
 		}
 	}
 
-	key = nullptr;
-
 	// Styles.
-	while ((key = style_map.next(key))) {
-		const StringName *key2 = nullptr;
-
-		while ((key2 = style_map[*key].next(key2))) {
-			list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/styles/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
+	for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : style_map) {
+		for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
+			list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/styles/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
 		}
 	}
 
-	key = nullptr;
-
 	// Fonts.
-	while ((key = font_map.next(key))) {
-		const StringName *key2 = nullptr;
-
-		while ((key2 = font_map[*key].next(key2))) {
-			list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/fonts/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
+	for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : font_map) {
+		for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
+			list.push_back(PropertyInfo(Variant::OBJECT, String() + E.key + "/fonts/" + F.key, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
 		}
 	}
 
-	key = nullptr;
-
 	// Font sizes.
-	while ((key = font_size_map.next(key))) {
-		const StringName *key2 = nullptr;
-
-		while ((key2 = font_size_map[*key].next(key2))) {
-			list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2, PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
+	for (const KeyValue<StringName, HashMap<StringName, int>> &E : font_size_map) {
+		for (const KeyValue<StringName, int> &F : E.value) {
+			list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/font_sizes/" + F.key, PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
 		}
 	}
 
-	key = nullptr;
-
 	// Colors.
-	while ((key = color_map.next(key))) {
-		const StringName *key2 = nullptr;
-
-		while ((key2 = color_map[*key].next(key2))) {
-			list.push_back(PropertyInfo(Variant::COLOR, String() + *key + "/colors/" + *key2));
+	for (const KeyValue<StringName, HashMap<StringName, Color>> &E : color_map) {
+		for (const KeyValue<StringName, Color> &F : E.value) {
+			list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/colors/" + F.key));
 		}
 	}
 
-	key = nullptr;
-
 	// Constants.
-	while ((key = constant_map.next(key))) {
-		const StringName *key2 = nullptr;
-
-		while ((key2 = constant_map[*key].next(key2))) {
-			list.push_back(PropertyInfo(Variant::INT, String() + *key + "/constants/" + *key2));
+	for (const KeyValue<StringName, HashMap<StringName, int>> &E : constant_map) {
+		for (const KeyValue<StringName, int> &F : E.value) {
+			list.push_back(PropertyInfo(Variant::INT, String() + E.key + "/constants/" + F.key));
 		}
 	}
 
@@ -414,10 +388,8 @@ void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) con
 		return;
 	}
 
-	const StringName *key = nullptr;
-
-	while ((key = icon_map[p_theme_type].next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, Ref<Texture2D>> &E : icon_map[p_theme_type]) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -437,9 +409,8 @@ void Theme::remove_icon_type(const StringName &p_theme_type) {
 
 	_freeze_change_propagation();
 
-	const StringName *L = nullptr;
-	while ((L = icon_map[p_theme_type].next(L))) {
-		Ref<Texture2D> icon = icon_map[p_theme_type][*L];
+	for (const KeyValue<StringName, Ref<Texture2D>> &E : icon_map[p_theme_type]) {
+		Ref<Texture2D> icon = E.value;
 		if (icon.is_valid()) {
 			icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
 		}
@@ -453,9 +424,8 @@ void Theme::remove_icon_type(const StringName &p_theme_type) {
 void Theme::get_icon_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	const StringName *key = nullptr;
-	while ((key = icon_map.next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : icon_map) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -528,10 +498,8 @@ void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list)
 		return;
 	}
 
-	const StringName *key = nullptr;
-
-	while ((key = style_map[p_theme_type].next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, Ref<StyleBox>> &E : style_map[p_theme_type]) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -551,9 +519,8 @@ void Theme::remove_stylebox_type(const StringName &p_theme_type) {
 
 	_freeze_change_propagation();
 
-	const StringName *L = nullptr;
-	while ((L = style_map[p_theme_type].next(L))) {
-		Ref<StyleBox> style = style_map[p_theme_type][*L];
+	for (const KeyValue<StringName, Ref<StyleBox>> &E : style_map[p_theme_type]) {
+		Ref<StyleBox> style = E.value;
 		if (style.is_valid()) {
 			style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
 		}
@@ -567,9 +534,8 @@ void Theme::remove_stylebox_type(const StringName &p_theme_type) {
 void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	const StringName *key = nullptr;
-	while ((key = style_map.next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : style_map) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -644,10 +610,8 @@ void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) con
 		return;
 	}
 
-	const StringName *key = nullptr;
-
-	while ((key = font_map[p_theme_type].next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, Ref<Font>> &E : font_map[p_theme_type]) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -667,9 +631,8 @@ void Theme::remove_font_type(const StringName &p_theme_type) {
 
 	_freeze_change_propagation();
 
-	const StringName *L = nullptr;
-	while ((L = font_map[p_theme_type].next(L))) {
-		Ref<Font> font = font_map[p_theme_type][*L];
+	for (const KeyValue<StringName, Ref<Font>> &E : font_map[p_theme_type]) {
+		Ref<Font> font = E.value;
 		if (font.is_valid()) {
 			font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
 		}
@@ -683,9 +646,8 @@ void Theme::remove_font_type(const StringName &p_theme_type) {
 void Theme::get_font_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	const StringName *key = nullptr;
-	while ((key = font_map.next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : font_map) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -747,10 +709,8 @@ void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list
 		return;
 	}
 
-	const StringName *key = nullptr;
-
-	while ((key = font_size_map[p_theme_type].next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, int> &E : font_size_map[p_theme_type]) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -774,9 +734,8 @@ void Theme::remove_font_size_type(const StringName &p_theme_type) {
 void Theme::get_font_size_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	const StringName *key = nullptr;
-	while ((key = font_size_map.next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, HashMap<StringName, int>> &E : font_size_map) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -836,10 +795,8 @@ void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) co
 		return;
 	}
 
-	const StringName *key = nullptr;
-
-	while ((key = color_map[p_theme_type].next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, Color> &E : color_map[p_theme_type]) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -863,9 +820,8 @@ void Theme::remove_color_type(const StringName &p_theme_type) {
 void Theme::get_color_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	const StringName *key = nullptr;
-	while ((key = color_map.next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, HashMap<StringName, Color>> &E : color_map) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -925,10 +881,8 @@ void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list)
 		return;
 	}
 
-	const StringName *key = nullptr;
-
-	while ((key = constant_map[p_theme_type].next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, int> &E : constant_map[p_theme_type]) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -952,9 +906,8 @@ void Theme::remove_constant_type(const StringName &p_theme_type) {
 void Theme::get_constant_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	const StringName *key = nullptr;
-	while ((key = constant_map.next(key))) {
-		p_list->push_back(*key);
+	for (const KeyValue<StringName, HashMap<StringName, int>> &E : constant_map) {
+		p_list->push_back(E.key);
 	}
 }
 
@@ -1311,52 +1264,12 @@ void Theme::remove_type(const StringName &p_theme_type) {
 void Theme::get_type_list(List<StringName> *p_list) const {
 	ERR_FAIL_NULL(p_list);
 
-	Set<StringName> types;
-	const StringName *key = nullptr;
-
-	// Icons.
-	while ((key = icon_map.next(key))) {
-		types.insert(*key);
-	}
-
-	key = nullptr;
-
-	// StyleBoxes.
-	while ((key = style_map.next(key))) {
-		types.insert(*key);
-	}
-
-	key = nullptr;
-
-	// Fonts.
-	while ((key = font_map.next(key))) {
-		types.insert(*key);
-	}
-
-	key = nullptr;
-
-	// Font sizes.
-	while ((key = font_size_map.next(key))) {
-		types.insert(*key);
-	}
-
-	key = nullptr;
-
-	// Colors.
-	while ((key = color_map.next(key))) {
-		types.insert(*key);
-	}
-
-	key = nullptr;
-
-	// Constants.
-	while ((key = constant_map.next(key))) {
-		types.insert(*key);
-	}
-
-	for (Set<StringName>::Element *E = types.front(); E; E = E->next()) {
-		p_list->push_back(E->get());
-	}
+	get_icon_type_list(p_list);
+	get_stylebox_type_list(p_list);
+	get_font_type_list(p_list);
+	get_font_size_type_list(p_list);
+	get_color_type_list(p_list);
+	get_constant_type_list(p_list);
 }
 
 void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) {
@@ -1667,75 +1580,62 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
 
 	// Colors.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->color_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = p_other->color_map[*K].next(L))) {
-				set_color(*L, *K, p_other->color_map[*K][*L]);
+		for (const KeyValue<StringName, HashMap<StringName, Color>> &E : p_other->color_map) {
+			for (const KeyValue<StringName, Color> &F : E.value) {
+				set_color(F.key, E.key, F.value);
 			}
 		}
 	}
 
 	// Constants.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->constant_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = p_other->constant_map[*K].next(L))) {
-				set_constant(*L, *K, p_other->constant_map[*K][*L]);
+		for (const KeyValue<StringName, HashMap<StringName, int>> &E : p_other->constant_map) {
+			for (const KeyValue<StringName, int> &F : E.value) {
+				set_constant(F.key, E.key, F.value);
 			}
 		}
 	}
 
 	// Fonts.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->font_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = p_other->font_map[*K].next(L))) {
-				set_font(*L, *K, p_other->font_map[*K][*L]);
+		for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : p_other->font_map) {
+			for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
+				set_font(F.key, E.key, F.value);
 			}
 		}
 	}
 
 	// Font sizes.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->font_size_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = p_other->font_size_map[*K].next(L))) {
-				set_font_size(*L, *K, p_other->font_size_map[*K][*L]);
+		for (const KeyValue<StringName, HashMap<StringName, int>> &E : p_other->font_size_map) {
+			for (const KeyValue<StringName, int> &F : E.value) {
+				set_font_size(F.key, E.key, F.value);
 			}
 		}
 	}
 
 	// Icons.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->icon_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = p_other->icon_map[*K].next(L))) {
-				set_icon(*L, *K, p_other->icon_map[*K][*L]);
+		for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : p_other->icon_map) {
+			for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
+				set_icon(F.key, E.key, F.value);
 			}
 		}
 	}
 
 	// Styleboxes.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->style_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = p_other->style_map[*K].next(L))) {
-				set_stylebox(*L, *K, p_other->style_map[*K][*L]);
+		for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : p_other->style_map) {
+			for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
+				set_stylebox(F.key, E.key, F.value);
 			}
 		}
 	}
 
 	// Type variations.
 	{
-		const StringName *K = nullptr;
-		while ((K = p_other->variation_map.next(K))) {
-			set_type_variation(*K, p_other->variation_map[*K]);
+		for (const KeyValue<StringName, StringName> &E : p_other->variation_map) {
+			set_type_variation(E.key, E.value);
 		}
 	}
 
@@ -1745,12 +1645,10 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
 void Theme::clear() {
 	// These items need disconnecting.
 	{
-		const StringName *K = nullptr;
-		while ((K = icon_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = icon_map[*K].next(L))) {
-				Ref<Texture2D> icon = icon_map[*K][*L];
-				if (icon.is_valid()) {
+		for (const KeyValue<StringName, HashMap<StringName, Ref<Texture2D>>> &E : icon_map) {
+			for (const KeyValue<StringName, Ref<Texture2D>> &F : E.value) {
+				if (F.value.is_valid()) {
+					Ref<Texture2D> icon = F.value;
 					icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
 				}
 			}
@@ -1758,12 +1656,10 @@ void Theme::clear() {
 	}
 
 	{
-		const StringName *K = nullptr;
-		while ((K = style_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = style_map[*K].next(L))) {
-				Ref<StyleBox> style = style_map[*K][*L];
-				if (style.is_valid()) {
+		for (const KeyValue<StringName, HashMap<StringName, Ref<StyleBox>>> &E : style_map) {
+			for (const KeyValue<StringName, Ref<StyleBox>> &F : E.value) {
+				if (F.value.is_valid()) {
+					Ref<StyleBox> style = F.value;
 					style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
 				}
 			}
@@ -1771,12 +1667,10 @@ void Theme::clear() {
 	}
 
 	{
-		const StringName *K = nullptr;
-		while ((K = font_map.next(K))) {
-			const StringName *L = nullptr;
-			while ((L = font_map[*K].next(L))) {
-				Ref<Font> font = font_map[*K][*L];
-				if (font.is_valid()) {
+		for (const KeyValue<StringName, HashMap<StringName, Ref<Font>>> &E : font_map) {
+			for (const KeyValue<StringName, Ref<Font>> &F : E.value) {
+				if (F.value.is_valid()) {
+					Ref<Font> font = F.value;
 					font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
 				}
 			}

+ 2 - 3
servers/rendering/renderer_rd/storage_rd/material_storage.cpp

@@ -1959,10 +1959,9 @@ Vector<StringName> MaterialStorage::global_variable_get_list() const {
 		ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
 	}
 
-	const StringName *K = nullptr;
 	Vector<StringName> names;
-	while ((K = global_variables.variables.next(K))) {
-		names.push_back(*K);
+	for (const KeyValue<StringName, GlobalVariables::Variable> &E : global_variables.variables) {
+		names.push_back(E.key);
 	}
 	names.sort_custom<StringName::AlphCompare>();
 	return names;

+ 7 - 8
servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

@@ -1831,13 +1831,13 @@ void TextureStorage::update_decal_atlas() {
 		Vector<DecalAtlas::SortItem> itemsv;
 		itemsv.resize(decal_atlas.textures.size());
 		int base_size = 8;
-		const RID *K = nullptr;
 
 		int idx = 0;
-		while ((K = decal_atlas.textures.next(K))) {
+
+		for (const KeyValue<RID, DecalAtlas::Texture> &E : decal_atlas.textures) {
 			DecalAtlas::SortItem &si = itemsv.write[idx];
 
-			Texture *src_tex = get_texture(*K);
+			Texture *src_tex = get_texture(E.key);
 
 			si.size.width = (src_tex->width / border) + 1;
 			si.size.height = (src_tex->height / border) + 1;
@@ -1847,7 +1847,7 @@ void TextureStorage::update_decal_atlas() {
 				base_size = nearest_power_of_2_templated(si.size.width);
 			}
 
-			si.texture = *K;
+			si.texture = E.key;
 			idx++;
 		}
 
@@ -1983,10 +1983,9 @@ void TextureStorage::update_decal_atlas() {
 
 				RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, cc);
 
-				const RID *K = nullptr;
-				while ((K = decal_atlas.textures.next(K))) {
-					DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
-					Texture *src_tex = get_texture(*K);
+				for (const KeyValue<RID, DecalAtlas::Texture> &E : decal_atlas.textures) {
+					DecalAtlas::Texture *t = decal_atlas.textures.getptr(E.key);
+					Texture *src_tex = get_texture(E.key);
 					copy_effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
 				}
 

+ 3 - 3
servers/rendering/rendering_server_default.cpp

@@ -179,10 +179,10 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
 			print_line("GPU PROFILE (total " + rtos(total_time) + "ms): ");
 
 			float print_threshold = 0.01;
-			for (OrderedHashMap<String, float>::Element E = print_gpu_profile_task_time.front(); E; E = E.next()) {
-				double time = E.value() / double(print_frame_profile_frame_count);
+			for (const KeyValue<String, float> &E : print_gpu_profile_task_time) {
+				double time = E.value / double(print_frame_profile_frame_count);
 				if (time > print_threshold) {
-					print_line("\t-" + E.key() + ": " + rtos(time) + "ms");
+					print_line("\t-" + E.key + ": " + rtos(time) + "ms");
 				}
 			}
 			print_gpu_profile_task_time.clear();

+ 2 - 2
servers/rendering/rendering_server_default.h

@@ -33,7 +33,7 @@
 
 #include "core/math/octree.h"
 #include "core/templates/command_queue_mt.h"
-#include "core/templates/ordered_hash_map.h"
+#include "core/templates/hash_map.h"
 #include "renderer_canvas_cull.h"
 #include "renderer_scene_cull.h"
 #include "renderer_viewport.h"
@@ -69,7 +69,7 @@ class RenderingServerDefault : public RenderingServer {
 
 	//for printing
 	bool print_gpu_profile = false;
-	OrderedHashMap<String, float> print_gpu_profile_task_time;
+	HashMap<String, float> print_gpu_profile_task_time;
 	uint64_t print_frame_profile_ticks_from = 0;
 	uint32_t print_frame_profile_frame_count = 0;
 

+ 1 - 1
servers/rendering/shader_types.h

@@ -31,7 +31,7 @@
 #ifndef SHADERTYPES_H
 #define SHADERTYPES_H
 
-#include "core/templates/ordered_hash_map.h"
+#include "core/templates/map.h"
 #include "servers/rendering_server.h"
 #include "shader_language.h"
 

+ 13 - 16
tests/core/object/test_class_db.h

@@ -173,7 +173,7 @@ struct NamesCache {
 	}
 };
 
-typedef OrderedHashMap<StringName, ExposedClass> ExposedClasses;
+typedef HashMap<StringName, ExposedClass> ExposedClasses;
 
 struct Context {
 	Vector<StringName> enum_types;
@@ -183,13 +183,13 @@ struct Context {
 	NamesCache names_cache;
 
 	const ExposedClass *find_exposed_class(const StringName &p_name) const {
-		ExposedClasses::ConstElement elem = exposed_classes.find(p_name);
-		return elem ? &elem.value() : nullptr;
+		ExposedClasses::ConstIterator elem = exposed_classes.find(p_name);
+		return elem ? &elem->value : nullptr;
 	}
 
 	const ExposedClass *find_exposed_class(const TypeReference &p_type_ref) const {
-		ExposedClasses::ConstElement elem = exposed_classes.find(p_type_ref.name);
-		return elem ? &elem.value() : nullptr;
+		ExposedClasses::ConstIterator elem = exposed_classes.find(p_type_ref.name);
+		return elem ? &elem->value : nullptr;
 	}
 
 	bool has_type(const TypeReference &p_type_ref) const {
@@ -676,12 +676,11 @@ void add_exposed_classes(Context &r_context) {
 		// Add signals
 
 		const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map;
-		const StringName *k = nullptr;
 
-		while ((k = signal_map.next(k))) {
+		for (const KeyValue<StringName, MethodInfo> &K : signal_map) {
 			SignalData signal;
 
-			const MethodInfo &method_info = signal_map.get(*k);
+			const MethodInfo &method_info = signal_map.get(K.key);
 
 			signal.name = method_info.name;
 
@@ -734,14 +733,12 @@ void add_exposed_classes(Context &r_context) {
 		ClassDB::get_integer_constant_list(class_name, &constants, true);
 
 		const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map;
-		k = nullptr;
 
-		while ((k = enum_map.next(k))) {
+		for (const KeyValue<StringName, List<StringName>> &K : enum_map) {
 			EnumData enum_;
-			enum_.name = *k;
+			enum_.name = K.key;
 
-			const List<StringName> &enum_constants = enum_map.get(*k);
-			for (const StringName &E : enum_constants) {
+			for (const StringName &E : K.value) {
 				const StringName &constant_name = E;
 				TEST_FAIL_COND(String(constant_name).find("::") != -1,
 						"Enum constant contains '::', check bindings to remove the scope: '",
@@ -760,7 +757,7 @@ void add_exposed_classes(Context &r_context) {
 
 			exposed_class.enums.push_back(enum_);
 
-			r_context.enum_types.push_back(String(class_name) + "." + String(*k));
+			r_context.enum_types.push_back(String(class_name) + "." + String(K.key));
 		}
 
 		for (const String &E : constants) {
@@ -850,8 +847,8 @@ TEST_SUITE("[ClassDB]") {
 			TEST_FAIL_COND(object_class->base != StringName(),
 					"Object class derives from another class: '", object_class->base, "'.");
 
-			for (ExposedClasses::Element E = context.exposed_classes.front(); E; E = E.next()) {
-				validate_class(context, E.value());
+			for (const KeyValue<StringName, ExposedClass> &E : context.exposed_classes) {
+				validate_class(context, E.value);
 			}
 		}
 	}

+ 32 - 34
tests/core/templates/test_ordered_hash_map.h → tests/core/templates/test_hash_map.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  test_ordered_hash_map.h                                              */
+/*  test_hash_map.h                                                      */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,56 +28,53 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef TEST_ORDERED_HASH_MAP_H
-#define TEST_ORDERED_HASH_MAP_H
+#ifndef TEST_HASH_MAP_H
+#define TEST_HASH_MAP_H
 
-#include "core/templates/ordered_hash_map.h"
+#include "core/templates/hash_map.h"
 
 #include "tests/test_macros.h"
 
-namespace TestOrderedHashMap {
+namespace TestHashMap {
 
-TEST_CASE("[OrderedHashMap] Insert element") {
-	OrderedHashMap<int, int> map;
-	OrderedHashMap<int, int>::Element e = map.insert(42, 84);
+TEST_CASE("[HashMap] Insert element") {
+	HashMap<int, int> map;
+	HashMap<int, int>::Iterator e = map.insert(42, 84);
 
 	CHECK(e);
-	CHECK(e.key() == 42);
-	CHECK(e.get() == 84);
-	CHECK(e.value() == 84);
+	CHECK(e->key == 42);
+	CHECK(e->value == 84);
 	CHECK(map[42] == 84);
 	CHECK(map.has(42));
 	CHECK(map.find(42));
 }
 
-TEST_CASE("[OrderedHashMap] Overwrite element") {
-	OrderedHashMap<int, int> map;
+TEST_CASE("[HashMap] Overwrite element") {
+	HashMap<int, int> map;
 	map.insert(42, 84);
 	map.insert(42, 1234);
 
 	CHECK(map[42] == 1234);
 }
 
-TEST_CASE("[OrderedHashMap] Erase via element") {
-	OrderedHashMap<int, int> map;
-	OrderedHashMap<int, int>::Element e = map.insert(42, 84);
-
-	map.erase(e);
-	CHECK(!e);
+TEST_CASE("[HashMap] Erase via element") {
+	HashMap<int, int> map;
+	HashMap<int, int>::Iterator e = map.insert(42, 84);
+	map.remove(e);
 	CHECK(!map.has(42));
 	CHECK(!map.find(42));
 }
 
-TEST_CASE("[OrderedHashMap] Erase via key") {
-	OrderedHashMap<int, int> map;
+TEST_CASE("[HashMap] Erase via key") {
+	HashMap<int, int> map;
 	map.insert(42, 84);
 	map.erase(42);
 	CHECK(!map.has(42));
 	CHECK(!map.find(42));
 }
 
-TEST_CASE("[OrderedHashMap] Size") {
-	OrderedHashMap<int, int> map;
+TEST_CASE("[HashMap] Size") {
+	HashMap<int, int> map;
 	map.insert(42, 84);
 	map.insert(123, 84);
 	map.insert(123, 84);
@@ -87,8 +84,8 @@ TEST_CASE("[OrderedHashMap] Size") {
 	CHECK(map.size() == 4);
 }
 
-TEST_CASE("[OrderedHashMap] Iteration") {
-	OrderedHashMap<int, int> map;
+TEST_CASE("[HashMap] Iteration") {
+	HashMap<int, int> map;
 	map.insert(42, 84);
 	map.insert(123, 12385);
 	map.insert(0, 12934);
@@ -102,34 +99,35 @@ TEST_CASE("[OrderedHashMap] Iteration") {
 	expected.push_back(Pair<int, int>(123485, 1238888));
 
 	int idx = 0;
-	for (OrderedHashMap<int, int>::Element E = map.front(); E; E = E.next()) {
-		CHECK(expected[idx] == Pair<int, int>(E.key(), E.value()));
+	for (const KeyValue<int, int> &E : map) {
+		CHECK(expected[idx] == Pair<int, int>(E.key, E.value));
 		++idx;
 	}
 }
 
-TEST_CASE("[OrderedHashMap] Const iteration") {
-	OrderedHashMap<int, int> map;
+TEST_CASE("[HashMap] Const iteration") {
+	HashMap<int, int> map;
 	map.insert(42, 84);
 	map.insert(123, 12385);
 	map.insert(0, 12934);
 	map.insert(123485, 1238888);
 	map.insert(123, 111111);
 
-	const OrderedHashMap<int, int> const_map = map;
+	const HashMap<int, int> const_map = map;
 
 	Vector<Pair<int, int>> expected;
 	expected.push_back(Pair<int, int>(42, 84));
 	expected.push_back(Pair<int, int>(123, 111111));
 	expected.push_back(Pair<int, int>(0, 12934));
 	expected.push_back(Pair<int, int>(123485, 1238888));
+	expected.push_back(Pair<int, int>(123, 111111));
 
 	int idx = 0;
-	for (OrderedHashMap<int, int>::ConstElement E = const_map.front(); E; E = E.next()) {
-		CHECK(expected[idx] == Pair<int, int>(E.key(), E.value()));
+	for (const KeyValue<int, int> &E : const_map) {
+		CHECK(expected[idx] == Pair<int, int>(E.key, E.value));
 		++idx;
 	}
 }
-} // namespace TestOrderedHashMap
+} // namespace TestHashMap
 
-#endif // TEST_ORDERED_HASH_MAP_H
+#endif // TEST_HASH_MAP_H

+ 1 - 1
tests/test_main.cpp

@@ -59,10 +59,10 @@
 #include "tests/core/string/test_string.h"
 #include "tests/core/string/test_translation.h"
 #include "tests/core/templates/test_command_queue.h"
+#include "tests/core/templates/test_hash_map.h"
 #include "tests/core/templates/test_list.h"
 #include "tests/core/templates/test_local_vector.h"
 #include "tests/core/templates/test_lru.h"
-#include "tests/core/templates/test_ordered_hash_map.h"
 #include "tests/core/templates/test_paged_array.h"
 #include "tests/core/templates/test_vector.h"
 #include "tests/core/test_crypto.h"