Skip to content

Commit

Permalink
Optimizing traversal over linked scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
octa-one committed May 7, 2022
1 parent dc215e6 commit 40a3917
Showing 1 changed file with 85 additions and 45 deletions.
130 changes: 85 additions & 45 deletions core/koin-core/src/commonMain/kotlin/org/koin/core/scope/Scope.kt
Expand Up @@ -232,68 +232,91 @@ data class Scope(
if (_closed) {
throw ClosedScopeException("Scope '$id' is closed")
}

val parameters = parameterDef?.invoke()
val instanceContext = InstanceContext(_koin, this, parameters)

if (parameters != null) {
_koin.logger.log(Level.DEBUG) { "| put parameters on stack $parameters " }
_parameterStack.addFirst(parameters)
}
val instanceContext = InstanceContext(_koin, this, parameters)
val value = resolveValue<T>(qualifier, clazz, instanceContext, parameterDef)

val value = _koin.instanceRegistry.resolveInstance(qualifier, clazz, this.scopeQualifier, instanceContext)
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look in injected parameters" }
_parameterStack.firstOrNull()?.getOrNull<T>(clazz)
}
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look at scope source" }
getFromSource<T>(clazz)
}
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look in other scopes" }
findInOtherScope<T>(clazz, qualifier, parameters)
}

if (parameters != null) {
_koin.logger.log(Level.DEBUG) { "| remove parameters from stack" }
_parameterStack.removeFirstOrNull()
}
return value
}

private fun <T> resolveValue(
qualifier: Qualifier?,
clazz: KClass<*>,
instanceContext: InstanceContext,
parameterDef: ParametersDefinition?
) = (_koin.instanceRegistry.resolveInstance(qualifier, clazz, this.scopeQualifier, instanceContext)
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look in injected parameters" }
_parameterStack.firstOrNull()?.getOrNull<T>(clazz)
}
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look at scope source" }
_source?.let {
if (clazz.isInstance(it)) {
_source as? T
} else null
}
}
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look in other scopes" }
findInOtherScope<T>(clazz, qualifier, parameterDef)
}
?: run {
_parameterStack.clear()
_koin.logger.log(Level.DEBUG) { "| clear parameter stack" }
throwDefinitionNotFound(qualifier, clazz)
})
return value ?: throwDefinitionNotFound(qualifier, clazz)
}

@Suppress("UNCHECKED_CAST")
private fun <T> getFromSource(clazz: KClass<*>): T? {
return if (clazz.isInstance(_source)) _source as? T else null
return _source?.let { source -> if (clazz.isInstance(source)) source as? T else null }
}

private fun <T> findInOtherScope(
clazz: KClass<*>,
qualifier: Qualifier?,
parameters: ParametersDefinition?
parameters: ParametersHolder?
): T? {
var instance: T? = null
for (scope in linkedScopes) {
instance = scope.getOrNull<T>(
clazz,
qualifier,
parameters
)
if (instance != null) break
val visitedScopes = mutableSetOf<ScopeID>()
val queue = ArrayDeque(linkedScopes)

while (queue.isNotEmpty()) {
val currentScope = queue.removeFirst()
val currentValue = currentScope.resolveLinkedScopeInstanceOrNull<T>(qualifier, clazz, parameters)
if (currentValue != null) {
return currentValue
} else {
currentScope.linkedScopes.forEach { scope ->
if (visitedScopes.add(scope.id)) {
queue.addLast(scope)
}
}
}
}
return instance
return null
}

private fun <T> resolveLinkedScopeInstanceOrNull(
qualifier: Qualifier?,
clazz: KClass<*>,
parameters: ParametersHolder?
) : T? {
if (_closed) return null

if (parameters != null) {
_koin.logger.log(Level.DEBUG) { "| put parameters on stack $parameters " }
_parameterStack.addFirst(parameters)
}

val instanceContext = InstanceContext(_koin, this, parameters)
val value = _koin.instanceRegistry.resolveInstance(qualifier, clazz, this.scopeQualifier, instanceContext)
?: run {
_koin.logger.log(Level.DEBUG) { "- lookup? t:'${clazz.getFullName()}' - q:'$qualifier' look at scope source" }
getFromSource<T>(clazz)
}

if (parameters != null) {
_koin.logger.log(Level.DEBUG) { "| remove parameters from stack" }
_parameterStack.removeFirstOrNull()
}

return value
}

private fun throwDefinitionNotFound(
Expand All @@ -314,7 +337,7 @@ data class Scope(
* @param instance The instance you're declaring.
* @param qualifier Qualifier for this declaration
* @param secondaryTypes List of secondary bound types
* @param override Allows to override a previous declaration of the same type (default to false).
* @param allowOverride Allows to override a previous declaration of the same type (default to false).
*/
inline fun <reified T> declare(
instance: T,
Expand Down Expand Up @@ -357,8 +380,25 @@ data class Scope(
* @return list of instances of type T
*/
fun <T> getAll(clazz: KClass<*>): List<T> {
val context = InstanceContext(_koin, this)
return _koin.instanceRegistry.getAll<T>(clazz, context) + linkedScopes.flatMap { scope -> scope.getAll(clazz) }
val accumulator = mutableListOf<T>()
val visitedScopes = mutableSetOf<ScopeID>()
val queue = ArrayDeque<Scope>()
queue.addLast(this)

while (queue.isNotEmpty()) {
val currentScope = queue.removeFirst()
val context = InstanceContext(_koin, currentScope)

accumulator.addAll(_koin.instanceRegistry.getAll(clazz, context))

currentScope.linkedScopes.forEach { scope ->
if (visitedScopes.add(scope.id)) {
queue.addLast(scope)
}
}
}

return accumulator.toList()
}

// /**
Expand Down

0 comments on commit 40a3917

Please sign in to comment.