Browse Source

Speed up GDScript::get_must_clear_dependencies()

get_must_clear_dependencies() has a N^3*log(N) time complexity, and this can very quickly slow down the quitting process as more gdscripts are added in a project.
This change improves it to N^2*log(N).
Instead of using all the inverted dependencies, we do the same with all (non-inverted) dependencies, which is N times faster.

Fixes #85435
eldidou 1 year ago
parent
commit
0d77c3e092
2 changed files with 17 additions and 26 deletions
  1. 16 25
      modules/gdscript/gdscript.cpp
  2. 1 1
      modules/gdscript/gdscript.h

+ 16 - 25
modules/gdscript/gdscript.cpp

@@ -1156,8 +1156,8 @@ RBSet<GDScript *> GDScript::get_dependencies() {
 	return dependencies;
 	return dependencies;
 }
 }
 
 
-RBSet<GDScript *> GDScript::get_inverted_dependencies() {
-	RBSet<GDScript *> inverted_dependencies;
+HashMap<GDScript *, RBSet<GDScript *>> GDScript::get_all_dependencies() {
+	HashMap<GDScript *, RBSet<GDScript *>> all_dependencies;
 
 
 	List<GDScript *> scripts;
 	List<GDScript *> scripts;
 	{
 	{
@@ -1171,51 +1171,42 @@ RBSet<GDScript *> GDScript::get_inverted_dependencies() {
 	}
 	}
 
 
 	for (GDScript *scr : scripts) {
 	for (GDScript *scr : scripts) {
-		if (scr == nullptr || scr == this || scr->destructing) {
+		if (scr == nullptr || scr->destructing) {
 			continue;
 			continue;
 		}
 		}
-
-		RBSet<GDScript *> scr_dependencies = scr->get_dependencies();
-		if (scr_dependencies.has(this)) {
-			inverted_dependencies.insert(scr);
-		}
+		all_dependencies.insert(scr, scr->get_dependencies());
 	}
 	}
 
 
-	return inverted_dependencies;
+	return all_dependencies;
 }
 }
 
 
 RBSet<GDScript *> GDScript::get_must_clear_dependencies() {
 RBSet<GDScript *> GDScript::get_must_clear_dependencies() {
 	RBSet<GDScript *> dependencies = get_dependencies();
 	RBSet<GDScript *> dependencies = get_dependencies();
 	RBSet<GDScript *> must_clear_dependencies;
 	RBSet<GDScript *> must_clear_dependencies;
-	HashMap<GDScript *, RBSet<GDScript *>> inverted_dependencies;
-
-	for (GDScript *E : dependencies) {
-		inverted_dependencies.insert(E, E->get_inverted_dependencies());
-	}
+	HashMap<GDScript *, RBSet<GDScript *>> all_dependencies = get_all_dependencies();
 
 
 	RBSet<GDScript *> cant_clear;
 	RBSet<GDScript *> cant_clear;
-	for (KeyValue<GDScript *, RBSet<GDScript *>> &E : inverted_dependencies) {
+	for (KeyValue<GDScript *, RBSet<GDScript *>> &E : all_dependencies) {
+		if (dependencies.has(E.key)) {
+			continue;
+		}
 		for (GDScript *F : E.value) {
 		for (GDScript *F : E.value) {
-			if (!dependencies.has(F)) {
-				cant_clear.insert(E.key);
-				for (GDScript *G : E.key->get_dependencies()) {
-					cant_clear.insert(G);
-				}
-				break;
+			if (dependencies.has(F)) {
+				cant_clear.insert(F);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	for (KeyValue<GDScript *, RBSet<GDScript *>> &E : inverted_dependencies) {
-		if (cant_clear.has(E.key) || ScriptServer::is_global_class(E.key->get_fully_qualified_name())) {
+	for (GDScript *E : dependencies) {
+		if (cant_clear.has(E) || ScriptServer::is_global_class(E->get_fully_qualified_name())) {
 			continue;
 			continue;
 		}
 		}
-		must_clear_dependencies.insert(E.key);
+		must_clear_dependencies.insert(E);
 	}
 	}
 
 
 	cant_clear.clear();
 	cant_clear.clear();
 	dependencies.clear();
 	dependencies.clear();
-	inverted_dependencies.clear();
+	all_dependencies.clear();
 	return must_clear_dependencies;
 	return must_clear_dependencies;
 }
 }
 
 

+ 1 - 1
modules/gdscript/gdscript.h

@@ -254,7 +254,7 @@ public:
 	const Ref<GDScriptNativeClass> &get_native() const { return native; }
 	const Ref<GDScriptNativeClass> &get_native() const { return native; }
 
 
 	RBSet<GDScript *> get_dependencies();
 	RBSet<GDScript *> get_dependencies();
-	RBSet<GDScript *> get_inverted_dependencies();
+	HashMap<GDScript *, RBSet<GDScript *>> get_all_dependencies();
 	RBSet<GDScript *> get_must_clear_dependencies();
 	RBSet<GDScript *> get_must_clear_dependencies();
 
 
 	virtual bool has_script_signal(const StringName &p_signal) const override;
 	virtual bool has_script_signal(const StringName &p_signal) const override;