96 lines
2.9 KiB
C#
96 lines
2.9 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Collections.Immutable;
|
|
|
|
namespace Dashboard.Collections
|
|
{
|
|
/// <summary>
|
|
/// Helper class for better type access performance.
|
|
/// </summary>
|
|
public record TypeAtom
|
|
{
|
|
|
|
public Type Type { get; }
|
|
public int Id { get; }
|
|
public ImmutableHashSet<TypeAtom> 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<TypeAtom> ancestors = new HashSet<TypeAtom>();
|
|
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<int, TypeAtom> s_atoms = new Dictionary<int, TypeAtom>();
|
|
private static readonly Dictionary<Type, TypeAtom> s_types = new Dictionary<Type, TypeAtom>();
|
|
|
|
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<TypeAtom> 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper class for better type access performance.
|
|
/// </summary>
|
|
public sealed record TypeAtom<T> : 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<TypeAtom> Ancestors => Atom.Ancestors;
|
|
|
|
private TypeAtom() { }
|
|
}
|
|
}
|