From 42f58a8649a074ba02a17bd478862aac96d3915a Mon Sep 17 00:00:00 2001 From: Westin Miller Date: Thu, 17 Aug 2017 23:52:39 -0700 Subject: [PATCH] Recursive dependency trees - Now TorchBase and TorchSession can each have seperate managers - Managers now have a Dispose function that's run on shutdown --- Torch.API/Managers/IManager.cs | 7 +- Torch/Managers/DependencyManager.cs | 141 ++++++++++++++++++++++++---- Torch/Managers/Manager.cs | 5 + Torch/Managers/ScriptingManager.cs | 5 + 4 files changed, 139 insertions(+), 19 deletions(-) diff --git a/Torch.API/Managers/IManager.cs b/Torch.API/Managers/IManager.cs index e6e3059..79b7952 100644 --- a/Torch.API/Managers/IManager.cs +++ b/Torch.API/Managers/IManager.cs @@ -12,8 +12,13 @@ namespace Torch.API.Managers public interface IManager { /// - /// Initializes the manager. Called after Torch is initialized. + /// Initializes the manager. Called once this manager's dependencies have been initialized. /// void Init(); + + /// + /// Disposes the manager. Called before this manager's dependencies are disposed. + /// + void Dispose(); } } diff --git a/Torch/Managers/DependencyManager.cs b/Torch/Managers/DependencyManager.cs index bc0bdbf..ab1aa14 100644 --- a/Torch/Managers/DependencyManager.cs +++ b/Torch/Managers/DependencyManager.cs @@ -69,12 +69,35 @@ namespace Torch.Managers private readonly Dictionary _dependencySatisfaction; private readonly List _registeredManagers; private readonly List _orderedManagers; + private readonly DependencyManager _parentManager; - public DependencyManager() + public DependencyManager(DependencyManager parent = null) { _dependencySatisfaction = new Dictionary(); _registeredManagers = new List(); _orderedManagers = new List(); + _parentManager = parent; + if (parent == null) + return; + foreach (KeyValuePair kv in parent._dependencySatisfaction) + _dependencySatisfaction.Add(kv.Key, kv.Value); + } + + private void AddDependencySatisfaction(ManagerInstance instance) + { + foreach (Type supplied in instance.SuppliedManagers) + if (_dependencySatisfaction.ContainsKey(supplied)) + // When we already have a manager supplying this component we have to unregister it. + _dependencySatisfaction[supplied] = null; + else + _dependencySatisfaction.Add(supplied, instance); + } + + private void RebuildDependencySatisfaction() + { + _dependencySatisfaction.Clear(); + foreach (ManagerInstance manager in _registeredManagers) + AddDependencySatisfaction(manager); } /// @@ -85,39 +108,91 @@ namespace Torch.Managers /// or when the given manager is derived from an already existing manager. /// /// Manager to register + /// When adding a new manager to an initialized dependency manager /// true if added, false if not public bool AddManager(IManager manager) { + if (_initialized) + throw new InvalidOperationException("Can't add new managers to an initialized dependency manager"); // Protect against adding a manager derived from an existing manager if (_registeredManagers.Any(x => x.Instance.GetType().IsInstanceOfType(manager))) return false; // Protect against adding a manager when an existing manager derives from it. + // ReSharper disable once ConvertIfStatementToReturnStatement if (_registeredManagers.Any(x => manager.GetType().IsInstanceOfType(x.Instance))) return false; var instance = new ManagerInstance(manager); _registeredManagers.Add(instance); - - foreach (Type supplied in instance.SuppliedManagers) - if (_dependencySatisfaction.ContainsKey(supplied)) - // When we already have a manager supplying this component we have to unregister it. - _dependencySatisfaction[supplied] = null; - else - _dependencySatisfaction.Add(supplied, instance); + AddDependencySatisfaction(instance); return true; } + /// + /// Clears all managers registered with this dependency manager + /// + /// When removing managers from an initialized dependency manager + public void ClearManagers() + { + if (_initialized) + throw new InvalidOperationException("Can't remove managers from an initialized dependency manager"); + + _registeredManagers.Clear(); + _dependencySatisfaction.Clear(); + } + + /// + /// Removes a single manager from this dependency manager. + /// + /// The manager to remove + /// true if successful, false if the manager wasn't found + /// When removing managers from an initialized dependency manager + public bool RemoveManager(IManager manager) + { + if (_initialized) + throw new InvalidOperationException("Can't remove managers from an initialized dependency manager"); + if (manager == null) + return false; + for (var i = 0; i < _registeredManagers.Count; i++) + if (_registeredManagers[i].Instance == manager) + { + _registeredManagers.RemoveAtFast(i); + RebuildDependencySatisfaction(); + return true; + } + return false; + } + + /// + /// Removes a single manager from this dependency manager. + /// + /// The dependency type to remove + /// The manager that was removed, or null if one wasn't removed + /// When removing managers from an initialized dependency manager + public IManager RemoveManager(Type type) + { + IManager mgr = GetManager(type); + return RemoveManager(mgr) ? mgr : null; + } + + /// + /// Removes a single manager from this dependency manager. + /// + /// The dependency type to remove + /// The manager that was removed, or null if one wasn't removed + /// When removing managers from an initialized dependency manager + public IManager RemoveManager() + { + return RemoveManager(typeof(T)); + } + private void Sort() { // Resets the previous sort results #region Reset _orderedManagers.Clear(); foreach (ManagerInstance manager in _registeredManagers) - { manager.Dependents.Clear(); - foreach (DependencyInfo dependency in manager.Dependencies) - dependency.Field.SetValue(manager.Instance, null); - } #endregion // Creates the dependency graph @@ -133,7 +208,7 @@ namespace Torch.Managers inFactor++; dependencyInstance.Dependents.Add(manager); } - else if (!dependency.Optional) + else if (!dependency.Optional && _parentManager?.GetManager(dependency.DependencyType) == null) _log.Warn("Unable to satisfy dependency {0} ({1}) of {2}.", dependency.DependencyType.Name, dependency.Field.Name, manager.Instance.GetType().Name); } @@ -194,26 +269,56 @@ namespace Torch.Managers { manager.Dependents.Clear(); foreach (DependencyInfo dependency in manager.Dependencies) - dependency.Field.SetValue(manager.Instance, _dependencySatisfaction.GetValueOrDefault(dependency.DependencyType)?.Instance); + dependency.Field.SetValue(manager.Instance, GetManager(dependency.DependencyType)); } #endregion } - private bool _initiated = false; + private bool _initialized = false; /// /// Initializes the dependency manager, and all its registered managers. /// public void Init() { - if (_initiated) + if (_initialized) throw new InvalidOperationException("Can't start the dependency manager more than once"); - _initiated = true; + _initialized = true; Sort(); foreach (ManagerInstance manager in _orderedManagers) manager.Instance.Init(); } + /// + /// Disposes the dependency manager, and all its registered managers. + /// + public void Dispose() + { + if (!_initialized) + throw new InvalidOperationException("Can't dispose an uninitialized dependency manager"); + for (int i = _orderedManagers.Count - 1; i >= 0; i--) + { + _orderedManagers[i].Instance.Dispose(); + foreach (DependencyInfo field in _orderedManagers[i].Dependencies) + field.Field.SetValue(_orderedManagers[i].Instance, null); + } + _initialized = false; + } + + + /// + /// Gets the manager that provides the given type. If there is no such manager, returns null. + /// + /// Type of manager + /// manager, or null if none exists + public IManager GetManager(Type type) + { + // ReSharper disable once ConvertIfStatementToReturnStatement + if (_dependencySatisfaction.TryGetValue(type, out ManagerInstance mgr)) + return mgr.Instance; + return _parentManager?.GetManager(type); + } + /// /// Gets the manager that provides the given type. If there is no such manager, returns null. /// @@ -221,7 +326,7 @@ namespace Torch.Managers /// manager, or null if none exists public T GetManager() where T : class, IManager { - return (T)_dependencySatisfaction.GetValueOrDefault(typeof(T))?.Instance; + return (T)GetManager(typeof(T)); } } } diff --git a/Torch/Managers/Manager.cs b/Torch/Managers/Manager.cs index 2680d7f..ab66f77 100644 --- a/Torch/Managers/Manager.cs +++ b/Torch/Managers/Manager.cs @@ -45,5 +45,10 @@ namespace Torch.Managers { } + + public virtual void Dispose() + { + + } } } diff --git a/Torch/Managers/ScriptingManager.cs b/Torch/Managers/ScriptingManager.cs index b599898..eccf904 100644 --- a/Torch/Managers/ScriptingManager.cs +++ b/Torch/Managers/ScriptingManager.cs @@ -41,6 +41,11 @@ namespace Torch.Managers Log.Info(whitelist);*/ } + public void Dispose() + { + // TODO unregister whitelist patches + } + public void UnwhitelistType(Type t) { throw new NotImplementedException();