mirror of
https://github.com/godotengine/godot.git
synced 2026-01-06 10:11:57 +03:00
Add a new HashMap implementation
Adds a new, cleaned up, HashMap implementation. * Uses Robin Hood Hashing (https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing). * Keeps elements in a double linked list for simpler, ordered, iteration. * Allows keeping iterators for later use in removal (Unlike Map<>, it does not do much for performance vs keeping the key, but helps replace old code). * Uses a more modern C++ iterator API, deprecates the old one. * Supports custom allocator (in case there is a wish to use a paged one). This class aims to unify all the associative template usage and replace it by this one: * Map<> (whereas key order does not matter, which is 99% of cases) * HashMap<> * OrderedHashMap<> * OAHashMap<>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user