173 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace Engine.Core;
 | 
						|
 | 
						|
/// <summary>
 | 
						|
/// TODO This is VEERY experimental, and doesn't work well with the indices access. Use with caution
 | 
						|
/// </summary>
 | 
						|
/// <typeparam name="TIndex"></typeparam>
 | 
						|
/// <typeparam name="TItem"></typeparam>
 | 
						|
public class FastListOrdered<TIndex, TItem> : IList<TItem>, IReadOnlyList<TItem>, IEnumerable<TItem> where TItem : notnull where TIndex : IComparable
 | 
						|
{
 | 
						|
    private readonly SortedDictionary<TIndex, FastList<TItem>> items = null!;
 | 
						|
 | 
						|
    private readonly Func<TItem, TIndex> getIndexFunc = null!;
 | 
						|
    private readonly IComparer<TIndex> sortBy = null!;
 | 
						|
 | 
						|
    private int count = 0;
 | 
						|
    public int Count => count;
 | 
						|
 | 
						|
    public bool IsReadOnly { get; set; } = false;
 | 
						|
 | 
						|
    public TItem this[int index]
 | 
						|
    {
 | 
						|
        get { (TIndex tIndex, int i) = GetAt(index); return items[tIndex][i]; }
 | 
						|
        set
 | 
						|
        {
 | 
						|
            if (IsReadOnly)
 | 
						|
                throw new System.Data.ReadOnlyException();
 | 
						|
            (TIndex tIndex, int i) = GetAt(index); items[tIndex][i] = value;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private (TIndex TIndex, int i) GetAt(Index index)
 | 
						|
    {
 | 
						|
        int actualIndex = index.IsFromEnd
 | 
						|
                ? count - index.Value
 | 
						|
                : index.Value;
 | 
						|
 | 
						|
        if (actualIndex < 0 || actualIndex >= count)
 | 
						|
            throw new IndexOutOfRangeException();
 | 
						|
 | 
						|
        int leftIndex = actualIndex;
 | 
						|
        foreach ((TIndex i, FastList<TItem> list) in items)
 | 
						|
        {
 | 
						|
            if (leftIndex < list.Count)
 | 
						|
                return (i, leftIndex);
 | 
						|
            leftIndex -= list.Count;
 | 
						|
        }
 | 
						|
        throw new IndexOutOfRangeException();
 | 
						|
    }
 | 
						|
 | 
						|
    public int IndexOf(TItem item)
 | 
						|
    {
 | 
						|
        int indexCounter = 0;
 | 
						|
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
						|
        {
 | 
						|
            int i = list.IndexOf(item);
 | 
						|
            if (i != -1)
 | 
						|
                return indexCounter + i;
 | 
						|
            indexCounter += list.Count;
 | 
						|
        }
 | 
						|
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    public void Add(TItem item)
 | 
						|
    {
 | 
						|
        if (IsReadOnly)
 | 
						|
            throw new System.Data.ReadOnlyException();
 | 
						|
 | 
						|
        TIndex key = getIndexFunc(item);
 | 
						|
        if (!items.TryGetValue(key, out FastList<TItem>? list))
 | 
						|
            items[key] = list = [];
 | 
						|
 | 
						|
        list.Add(item);
 | 
						|
        count++;
 | 
						|
    }
 | 
						|
 | 
						|
    public void Insert(int index, TItem item)
 | 
						|
    {
 | 
						|
        if (IsReadOnly)
 | 
						|
            throw new System.Data.ReadOnlyException();
 | 
						|
 | 
						|
        TIndex tIndex = getIndexFunc(item);
 | 
						|
        if (!items.TryGetValue(tIndex, out FastList<TItem>? list))
 | 
						|
            items[tIndex] = list = [];
 | 
						|
 | 
						|
        list.Insert(index, item);
 | 
						|
        count++;
 | 
						|
    }
 | 
						|
 | 
						|
    public bool Remove(TItem item)
 | 
						|
    {
 | 
						|
        if (IsReadOnly)
 | 
						|
            throw new System.Data.ReadOnlyException();
 | 
						|
 | 
						|
        TIndex index = getIndexFunc(item);
 | 
						|
        if (!items.TryGetValue(index, out FastList<TItem>? list))
 | 
						|
            throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
 | 
						|
 | 
						|
        if (!list.Remove(item))
 | 
						|
            return false;
 | 
						|
 | 
						|
        count--;
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    public void RemoveAt(int index)
 | 
						|
    {
 | 
						|
        if (IsReadOnly)
 | 
						|
            throw new System.Data.ReadOnlyException();
 | 
						|
 | 
						|
        (TIndex tIndex, int i) = GetAt(index);
 | 
						|
        items[tIndex].RemoveAt(i);
 | 
						|
        count--;
 | 
						|
    }
 | 
						|
 | 
						|
    public void Clear()
 | 
						|
    {
 | 
						|
        if (IsReadOnly)
 | 
						|
            throw new System.Data.ReadOnlyException();
 | 
						|
 | 
						|
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
						|
            list.Clear();
 | 
						|
 | 
						|
        count = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    public bool Contains(TItem item)
 | 
						|
    {
 | 
						|
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
						|
            if (list.Contains(item))
 | 
						|
                return true;
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    public void CopyTo(TItem[] array, int arrayIndex)
 | 
						|
    {
 | 
						|
        int indexCounter = 0;
 | 
						|
 | 
						|
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
						|
        {
 | 
						|
            list.CopyTo(array, indexCounter);
 | 
						|
            indexCounter += list.Count;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public IEnumerator<TItem> GetEnumerator()
 | 
						|
    {
 | 
						|
        foreach ((TIndex index, FastList<TItem> list) in items)
 | 
						|
            foreach (TItem item in list)
 | 
						|
                yield return item;
 | 
						|
    }
 | 
						|
 | 
						|
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
						|
 | 
						|
    public FastListOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
 | 
						|
    {
 | 
						|
        this.getIndexFunc = getIndexFunc;
 | 
						|
        this.sortBy = Comparer<TIndex>.Create(sortBy);
 | 
						|
        items = new(this.sortBy);
 | 
						|
    }
 | 
						|
 | 
						|
    public FastListOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
 | 
						|
    {
 | 
						|
        this.getIndexFunc = getIndexFunc;
 | 
						|
        this.sortBy = sortBy;
 | 
						|
        items = new(sortBy);
 | 
						|
    }
 | 
						|
}
 |