using System; using System.Collections.Generic; using ModestTree; namespace Zenject { [NoReflectionBaking] public class DisposeBlock : IDisposable { static readonly StaticMemoryPool _pool = new StaticMemoryPool(OnSpawned, OnDespawned); List _disposables; List _objectPoolPairs; static void OnSpawned(DisposeBlock that) { Assert.IsNull(that._disposables); Assert.IsNull(that._objectPoolPairs); } static void OnDespawned(DisposeBlock that) { if (that._disposables != null) { // Dispose in reverse order since usually that makes the most sense for (int i = that._disposables.Count - 1; i >= 0; i--) { that._disposables[i].Dispose(); } ListPool.Instance.Despawn(that._disposables); that._disposables = null; } if (that._objectPoolPairs != null) { // Dispose in reverse order since usually that makes the most sense for (int i = that._objectPoolPairs.Count - 1; i >= 0; i--) { var pair = that._objectPoolPairs[i]; pair.Pool.Despawn(pair.Object); } ListPool.Instance.Despawn(that._objectPoolPairs); that._objectPoolPairs = null; } } void LazyInitializeDisposableList() { if (_disposables == null) { _disposables = ListPool.Instance.Spawn(); } } public void AddRange(IList disposables) where T : IDisposable { LazyInitializeDisposableList(); for (int i = 0; i < disposables.Count; i++) { _disposables.Add(disposables[i]); } } public void Add(IDisposable disposable) { LazyInitializeDisposableList(); Assert.That(!_disposables.Contains(disposable)); _disposables.Add(disposable); } public void Remove(IDisposable disposable) { Assert.IsNotNull(_disposables); _disposables.RemoveWithConfirm(disposable); } void StoreSpawnedObject(T obj, IDespawnableMemoryPool pool) { if (typeof(T).DerivesFrom()) { Add((IDisposable)obj); } else { // This allocation is ok because it's a struct var pair = new SpawnedObjectPoolPair { Pool = pool, Object = obj }; if (_objectPoolPairs == null) { _objectPoolPairs = ListPool.Instance.Spawn(); } _objectPoolPairs.Add(pair); } } public T Spawn(IMemoryPool pool) { var obj = pool.Spawn(); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1) { var obj = pool.Spawn(p1); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1, TParam2 p2) { var obj = pool.Spawn(p1, p2); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1, TParam2 p2, TParam3 p3) { var obj = pool.Spawn(p1, p2, p3); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4) { var obj = pool.Spawn(p1, p2, p3, p4); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4, TParam5 p5) { var obj = pool.Spawn(p1, p2, p3, p4, p5); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4, TParam5 p5, TParam6 p6) { var obj = pool.Spawn(p1, p2, p3, p4, p5, p6); StoreSpawnedObject(obj, pool); return obj; } public TValue Spawn(IMemoryPool pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4, TParam5 p5, TParam6 p6, TParam7 p7) { var obj = pool.Spawn(p1, p2, p3, p4, p5, p6, p7); StoreSpawnedObject(obj, pool); return obj; } public List SpawnList(IEnumerable elements) { var list = SpawnList(); list.AddRange(elements); return list; } public List SpawnList() { return Spawn(ListPool.Instance); } public static DisposeBlock Spawn() { return _pool.Spawn(); } public void Dispose() { _pool.Despawn(this); } struct SpawnedObjectPoolPair { public IMemoryPool Pool; public object Object; } } }