XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Collections;
using System.Runtime;
using System.Runtime.CompilerServices;

namespace XFESystem.Browser;

/// <summary>Page-owned ephemerons. Buckets contain no strong key references;
/// a value that refers back to its key cannot keep a detached node alive.
/// Pruning and release explicitly free native handles without finalizers.</summary>
internal sealed class DependentIdentityMap<TKey,TValue> : IEnumerable<KeyValuePair<TKey,TValue>>
    where TKey : class where TValue : class
{
    private sealed class Entry(TKey key,TValue value)
    {
        internal DependentHandle Handle = new(key,value);
    }
    private readonly Dictionary<int,List<Entry>> buckets=[];
    private readonly List<int> emptyBuckets=[];
    private int count;
    public long HandlesCreated {get;private set;}
    public long HandlesDisposed {get;private set;}
    public int Count {get{Prune();return count;}}
    public IEnumerable<TKey> Keys => this.Select(pair=>pair.Key);
    public TValue this[TKey key] => TryGetValue(key,out var value)?value:throw new KeyNotFoundException();
    public bool ContainsKey(TKey key)=>TryGetValue(key,out _);
    public bool TryGetValue(TKey key,out TValue value)
    {
        if(buckets.TryGetValue(RuntimeHelpers.GetHashCode(key),out var bucket))
            foreach(var entry in bucket)
            {
                var pair=entry.Handle.TargetAndDependent;
                if(ReferenceEquals(pair.Target,key)&&pair.Dependent is TValue found){value=found;return true;}
            }
        value=null!;return false;
    }
    public void Add(TKey key,TValue value)
    {
        ArgumentNullException.ThrowIfNull(key);ArgumentNullException.ThrowIfNull(value);
        int hash=RuntimeHelpers.GetHashCode(key);
        if(!buckets.TryGetValue(hash,out var bucket))buckets.Add(hash,bucket=[]);
        for(int index=bucket.Count-1;index>=0;index--)
        {
            var entry=bucket[index];var pair=entry.Handle.TargetAndDependent;
            if(pair.Target is null){DisposeEntry(entry);bucket.RemoveAt(index);continue;}
            if(ReferenceEquals(pair.Target,key))throw new ArgumentException("The identity key already exists.",nameof(key));
        }
        bucket.Add(new(key,value));count++;HandlesCreated++;
    }
    public bool Remove(TKey key)=>Remove(key,out _);
    public bool Remove(TKey key,out TValue value)
    {
        int hash=RuntimeHelpers.GetHashCode(key);
        if(buckets.TryGetValue(hash,out var bucket))
            for(int index=0;index<bucket.Count;index++)
            {
                var entry=bucket[index];var pair=entry.Handle.TargetAndDependent;
                if(!ReferenceEquals(pair.Target,key))continue;
                value=(TValue)pair.Dependent!;DisposeEntry(entry);bucket.RemoveAt(index);
                if(bucket.Count==0)buckets.Remove(hash);return true;
            }
        value=null!;return false;
    }
    public void Clear()
    {
        foreach(var bucket in buckets.Values)foreach(var entry in bucket)DisposeEntry(entry);
        buckets.Clear();emptyBuckets.Clear();
    }
    private void DisposeEntry(Entry entry){entry.Handle.Dispose();count--;HandlesDisposed++;}
    private void Prune()
    {
        emptyBuckets.Clear();
        foreach(var item in buckets)
        {
            var bucket=item.Value;
            for(int index=bucket.Count-1;index>=0;index--)
                if(bucket[index].Handle.Target is null){DisposeEntry(bucket[index]);bucket.RemoveAt(index);}
            if(bucket.Count==0)emptyBuckets.Add(item.Key);
        }
        foreach(int hash in emptyBuckets)buckets.Remove(hash);
        emptyBuckets.Clear();
    }
    public IEnumerator<KeyValuePair<TKey,TValue>> GetEnumerator()
    {
        foreach(var bucket in buckets.Values)foreach(var entry in bucket)
        {
            var pair=entry.Handle.TargetAndDependent;
            if(pair.Target is TKey key&&pair.Dependent is TValue value)yield return new(key,value);
        }
    }
    IEnumerator IEnumerable.GetEnumerator()=>GetEnumerator();
}