Implement ReFuel style type atoms and type collections.
This commit is contained in:
parent
2690c5bec0
commit
1dcf167022
95
Dashboard.Common/Collections/TypeAtom.cs
Normal file
95
Dashboard.Common/Collections/TypeAtom.cs
Normal file
@ -0,0 +1,95 @@
|
||||
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() { }
|
||||
}
|
||||
}
|
44
Dashboard.Common/Collections/TypeHashSet.cs
Normal file
44
Dashboard.Common/Collections/TypeHashSet.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Dashboard.Collections
|
||||
{
|
||||
public class TypeHashSet(bool hierarchical = false) : IEnumerable<TypeAtom>
|
||||
{
|
||||
private readonly HashSet<int> _set = new HashSet<int>();
|
||||
|
||||
public bool Contains<T>() => _set.Contains(TypeAtom<T>.Id);
|
||||
|
||||
public bool Set<T>()
|
||||
{
|
||||
if (!_set.Add(TypeAtom<T>.Id))
|
||||
return false;
|
||||
|
||||
if (hierarchical)
|
||||
foreach (TypeAtom ancestor in TypeAtom<T>.Ancestors)
|
||||
{
|
||||
_set.Add(ancestor.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Reset<T>()
|
||||
{
|
||||
if (!_set.Remove(TypeAtom<T>.Id))
|
||||
return false;
|
||||
|
||||
if (hierarchical)
|
||||
foreach (TypeAtom ancestor in TypeAtom<T>.Ancestors)
|
||||
{
|
||||
_set.Remove(ancestor.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Clear() => _set.Clear();
|
||||
|
||||
public IEnumerator<TypeAtom> GetEnumerator() => _set.Select(x => TypeAtom.Get(x)!).GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user