perf(scope): speed up dependency lookup with Map-based binding resolver index

Optimize resolve()/tryResolve() to use O(1) Map-based lookup by type and name instead of iterating through all modules and bindings. Behavior of factory, singleton, instance, and named bindings is preserved.
This commit is contained in:
Sergey Penkovsky
2025-08-05 17:20:35 +03:00
parent a4573ce8ef
commit ffff33c744

View File

@@ -39,6 +39,10 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
final Set<Module> _modulesList = HashSet(); final Set<Module> _modulesList = HashSet();
// индекс для мгновенного поиска bindingов
final Map<Object, Map<String?, BindingResolver>> _bindingResolvers = {};
/// RU: Генерирует уникальный идентификатор для скоупа. /// RU: Генерирует уникальный идентификатор для скоупа.
/// ENG: Generates unique identifier for scope. /// ENG: Generates unique identifier for scope.
String _generateScopeId() { String _generateScopeId() {
@@ -96,6 +100,7 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
for (var module in modules) { for (var module in modules) {
module.builder(this); module.builder(this);
} }
_rebuildResolversIndex();
return this; return this;
} }
@@ -107,7 +112,7 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
Scope dropModules() { Scope dropModules() {
// [AlexeyYuPopkov](https://github.com/AlexeyYuPopkov) Thank you for the [Removed exception "ConcurrentModificationError"](https://github.com/pese-git/cherrypick/pull/2) // [AlexeyYuPopkov](https://github.com/AlexeyYuPopkov) Thank you for the [Removed exception "ConcurrentModificationError"](https://github.com/pese-git/cherrypick/pull/2)
_modulesList.clear(); _modulesList.clear();
_rebuildResolversIndex();
return this; return this;
} }
@@ -254,16 +259,20 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
} }
BindingResolver<T>? _findBindingResolver<T>(String? named) { BindingResolver<T>? _findBindingResolver<T>(String? named) {
final byType = _bindingResolvers[T];
if (byType == null) return null;
return byType[named] as BindingResolver<T>?;
}
// Индексируем все bindingи после каждого installModules/dropModules
void _rebuildResolversIndex() {
_bindingResolvers.clear();
for (var module in _modulesList) { for (var module in _modulesList) {
for (var binding in module.bindingSet) { for (var binding in module.bindingSet) {
if (binding.key == T && _bindingResolvers.putIfAbsent(binding.key, () => {});
((!binding.isNamed && named == null) || final nameKey = binding.isNamed ? binding.name : null;
(binding.isNamed && named == binding.name))) { _bindingResolvers[binding.key]![nameKey] = binding.resolver!;
return binding.resolver as BindingResolver<T>?;
}
} }
} }
return null;
} }
} }