using System.Collections.Concurrent; using System.Collections.Immutable; namespace Dashboard.Collections { /// /// Helper class for better type access performance. /// public record TypeAtom { public Type Type { get; } public int Id { get; } public ImmutableHashSet Ancestors { get; } // Makes it so TypeAtom doesn't get pissed at me private protected TypeAtom() { throw new NotSupportedException(); } private TypeAtom(Type type) { Type = type; HashSet ancestors = new HashSet(); FindAncestors(Type, ancestors); ancestors.Add(this); Ancestors = ancestors.ToImmutableHashSet(); lock (s_lockObject) { Id = s_counter++; s_atoms.Add(Id, this); s_types.Add(Type, this); } } private static readonly object s_lockObject = new object(); private static readonly Dictionary s_atoms = new Dictionary(); private static readonly Dictionary s_types = new Dictionary(); private static int s_counter = 0; public static TypeAtom? Get(int id) => s_atoms.GetValueOrDefault(id); public static TypeAtom Get(Type type) { if (s_types.TryGetValue(type, out TypeAtom? id)) return id; // Type is not registered, try to acquire lock. lock (s_lockObject) { // Maybe somebody else registered this type whilst acquiring the lock. if (s_types.TryGetValue(type, out id)) return id; // Register the type if applicable and leave. return new TypeAtom(type); } } private static void FindAncestors(Type type, HashSet destination) { // Traverse the object tree for all possible aliases. if (type.BaseType != null) { foreach (TypeAtom ancestor in Get(type.BaseType).Ancestors) { destination.Add(ancestor); } } foreach (Type trait in type.GetInterfaces()) { TypeAtom atom = Get(trait); destination.Add(atom); } } } /// /// Helper class for better type access performance. /// public sealed record TypeAtom : TypeAtom { public static TypeAtom Atom { get; } = Get(typeof(T)); public new static int Id => Atom.Id; public new static Type Type => Atom.Type; public new static ImmutableHashSet Ancestors => Atom.Ancestors; private TypeAtom() { } } }