Implement ReFuel style type atoms and type collections.

This commit is contained in:
H. Utku Maden 2025-07-24 23:16:24 +03:00
parent 2690c5bec0
commit 1dcf167022
2 changed files with 139 additions and 0 deletions

View 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() { }
}
}

View 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();
}
}