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