Skip to content

Commit 7c93cb0

Browse files
committed
Implement cache for inheritance check
1 parent a5f6d06 commit 7c93cb0

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

godot-core/src/engine/mod.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
//! Godot engine classes and methods.
99
10-
// Re-exports of generated symbols
1110
use crate::builtin::{GString, NodePath};
1211
use crate::obj::dom::EngineDomain;
1312
use crate::obj::{Gd, GodotClass, Inherits, InstanceId};
13+
use std::collections::HashSet;
1414

15+
// Re-exports of generated symbols
1516
pub use crate::gen::central::global;
1617
pub use crate::gen::classes::*;
1718
pub use crate::gen::utilities;
@@ -246,15 +247,13 @@ pub(crate) fn ensure_object_alive(
246247

247248
#[cfg(debug_assertions)]
248249
pub(crate) fn ensure_object_inherits(
249-
derived: &ClassName,
250-
base: &ClassName,
250+
derived: ClassName,
251+
base: ClassName,
251252
instance_id: InstanceId,
252253
) -> bool {
253-
// TODO static cache.
254-
255254
if derived == base
256-
|| base == &Object::class_name() // always true
257-
|| ClassDb::singleton().is_parent_class(derived.to_string_name(), base.to_string_name())
255+
|| base == Object::class_name() // for Object base, anything inherits by definition
256+
|| is_derived_base_cached(derived, base)
258257
{
259258
return true;
260259
}
@@ -265,6 +264,30 @@ pub(crate) fn ensure_object_inherits(
265264
)
266265
}
267266

267+
/// Checks if `derived` inherits from `base`, using a cache for _successful_ queries.
268+
#[cfg(debug_assertions)]
269+
fn is_derived_base_cached(derived: ClassName, base: ClassName) -> bool {
270+
use sys::Global;
271+
static CACHE: Global<HashSet<(ClassName, ClassName)>> = Global::default();
272+
273+
let mut cache = CACHE.lock();
274+
let key = (derived, base);
275+
if cache.contains(&key) {
276+
return true;
277+
}
278+
279+
// Query Godot API (takes linear time in depth of inheritance tree).
280+
let is_parent_class =
281+
ClassDb::singleton().is_parent_class(derived.to_string_name(), base.to_string_name());
282+
283+
// Insert only successful queries. Those that fail are on the error path already and don't need to be fast.
284+
if is_parent_class {
285+
cache.insert(key);
286+
}
287+
288+
is_parent_class
289+
}
290+
268291
// Separate function, to avoid constructing string twice
269292
// Note that more optimizations than that likely make no sense, as loading is quite expensive
270293
fn load_impl<T>(path: &GString) -> Option<Gd<T>>

godot-core/src/obj/rtti.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl ObjectRtti {
4444
#[inline]
4545
pub fn check_type<T: GodotClass>(&self) -> InstanceId {
4646
#[cfg(debug_assertions)]
47-
crate::engine::ensure_object_inherits(&self.class_name, &T::class_name(), self.instance_id);
47+
crate::engine::ensure_object_inherits(self.class_name, T::class_name(), self.instance_id);
4848

4949
self.instance_id
5050
}

0 commit comments

Comments
 (0)