// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable enable using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; namespace osu.Game.Rulesets.Objects.Pooling { /// /// Manages a mapping between and /// internal class HitObjectEntryManager { /// /// All entries, including entries of the nested hit objects. /// public IEnumerable AllEntries => entryMap.Values; public event Action? OnEntryAdded; public event Action? OnEntryRemoved; private readonly Func createLifetimeEntry; private readonly Dictionary entryMap = new Dictionary(); private readonly Dictionary parentMap = new Dictionary(); public HitObjectEntryManager(Func createLifetimeEntry) { this.createLifetimeEntry = createLifetimeEntry; } public HitObjectLifetimeEntry Add(HitObject hitObject, HitObject? parentHitObject) { if (parentHitObject != null && !entryMap.TryGetValue(parentHitObject, out var parentEntry)) throw new InvalidOperationException($@"The parent {nameof(HitObject)} must be added to this {nameof(HitObjectEntryManager)} before nested {nameof(HitObject)} is added."); if (entryMap.ContainsKey(hitObject)) throw new InvalidOperationException($@"The {nameof(HitObject)} is already added to this {nameof(HitObjectEntryManager)}."); if (parentHitObject != null) parentMap[hitObject] = parentHitObject; var entry = createLifetimeEntry(hitObject); entryMap[hitObject] = entry; OnEntryAdded?.Invoke(entry, parentHitObject); return entry; } public bool Remove(HitObject hitObject) { if (!entryMap.TryGetValue(hitObject, out var entry)) return false; parentMap.Remove(hitObject, out var parentHitObject); OnEntryRemoved?.Invoke(entry, parentHitObject); return true; } public bool TryGet(HitObject hitObject, [MaybeNullWhen(false)] out HitObjectLifetimeEntry entry) { return entryMap.TryGetValue(hitObject, out entry); } } }