Init Scripts in new repo
This commit is contained in:
142
Collections/BitBuffer.cs
Normal file
142
Collections/BitBuffer.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
|
||||
namespace SJK.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Stores an Array of bits that can be retrieved by index. Can be used to return multiple bits as an int or long.
|
||||
/// </summary>
|
||||
public sealed class BitBuffer
|
||||
{
|
||||
// Number of bits in a byte
|
||||
private const int BitsInByte = 8;
|
||||
private const float BitsInByteFloat = 8f;
|
||||
private byte[] data;
|
||||
|
||||
/// <summary>
|
||||
/// Length of the bit buffer in bits.
|
||||
/// </summary>
|
||||
public int Length
|
||||
{
|
||||
get { return length; }
|
||||
set
|
||||
{
|
||||
AppendNewArray(value);
|
||||
length = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capacity of the bit buffer.
|
||||
/// </summary>
|
||||
public int Capacity { get { return data.Length; } }
|
||||
|
||||
private int length;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BitBuffer class with the specified length in bits.
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the bit buffer in bits.</param>
|
||||
public BitBuffer(int length)
|
||||
{
|
||||
data = new byte[length / BitsInByte + 5];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BitBuffer class with the specified byte array.
|
||||
/// </summary>
|
||||
/// <param name="_data">The byte array to initialize the bit buffer.</param>
|
||||
public BitBuffer(byte[] _data)
|
||||
{
|
||||
data = _data;
|
||||
length = data.Length * BitsInByte;
|
||||
}
|
||||
|
||||
private void AppendNewArray(int length)
|
||||
{
|
||||
int capacity = length / BitsInByte + 1;
|
||||
byte[] newData = new byte[capacity];
|
||||
Array.Copy(data, newData, System.Math.Min(data.Length, newData.Length));
|
||||
data = newData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bit at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the bit.</param>
|
||||
/// <returns>The value of the bit at the specified index.</returns>
|
||||
public bool GetBit(long index)
|
||||
{
|
||||
return GetBits(index, 1) > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the bit at the specified index to the specified value.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the bit.</param>
|
||||
/// <param name="value">The value to set the bit to.</param>
|
||||
public void SetBit(long index, bool value)
|
||||
{
|
||||
SetBits(index, value ? 1 : 0, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified number of bits starting from the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The starting index of the bits.</param>
|
||||
/// <param name="bits">The number of bits to retrieve.</param>
|
||||
/// <returns>The retrieved bits as an integer.</returns>
|
||||
public unsafe int GetBits(long index, int bits)
|
||||
{
|
||||
#if DEBUG
|
||||
if (bits > 32)
|
||||
throw new ArgumentOutOfRangeException($"{nameof(BitBuffer)} does not support accessing more then size of int (32 bits) : {bits}");
|
||||
if (bits <= 0)
|
||||
throw new ArgumentOutOfRangeException($"{nameof(BitBuffer)} cannot have zero or lower be the length of the bits : {bits}");
|
||||
if (index <0)
|
||||
throw new IndexOutOfRangeException($"{nameof(BitBuffer)} cannot index a value lower then zero : {index}");
|
||||
if (index >= length - bits)
|
||||
throw new IndexOutOfRangeException($"{nameof(BitBuffer)} cannot bit greater then the length of the bitBuffer : {index}, {bits}");
|
||||
#endif
|
||||
long byteIndex = index / BitsInByte;
|
||||
int offset = (int)(index - byteIndex * BitsInByte);
|
||||
|
||||
fixed (byte* d = &data[byteIndex])
|
||||
{
|
||||
return (*((int*)d) >> offset) & ((1 << bits) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the specified number of bits starting from the specified index to the specified value.
|
||||
/// </summary>
|
||||
/// <param name="index">The starting index of the bits.</param>
|
||||
/// <param name="value">The value to set the bits to.</param>
|
||||
/// <param name="bits">The number of bits to set.</param>
|
||||
public unsafe void SetBits(long index, int value, int bits)
|
||||
{
|
||||
int mask = (1 << bits) - 1;
|
||||
int newValue = value;
|
||||
newValue &= mask;
|
||||
long byteIndex = index / BitsInByte;
|
||||
int offset = (int)(index - byteIndex * BitsInByte);
|
||||
|
||||
fixed (byte* d = data)
|
||||
{
|
||||
int* l = (int*)(d + byteIndex);
|
||||
int v = *l;
|
||||
v = v & ~((mask << offset));
|
||||
v = v | (newValue << offset);
|
||||
*(int*)(d + byteIndex) = v;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying byte array of the BitBuffer.
|
||||
/// </summary>
|
||||
/// <returns>The underlying byte array.</returns>
|
||||
public byte[] GetData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
132
Collections/Palette.cs
Normal file
132
Collections/Palette.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
using System.Diagnostics;
|
||||
using SJK.Functional;
|
||||
|
||||
public class Palette<TEntry> where TEntry : IEquatable<TEntry>
|
||||
|
||||
{
|
||||
private List<TEntry> _entries = new();
|
||||
private Dictionary<TEntry, int> _index = new();
|
||||
public int Capacity => _entries.Capacity;
|
||||
public int Count => _entries.Count;
|
||||
public TEntry Get(int index)
|
||||
{
|
||||
Debug.Assert(index >= 0 && index < Count,$"{nameof(index)} is out of range, {nameof(index)} has value {index}, while {nameof(Count)} has value of {Count}");
|
||||
return _entries[index];
|
||||
}
|
||||
public Option<TEntry> Get(Predicate<TEntry> predicate)
|
||||
{
|
||||
foreach (var item in _entries)
|
||||
{
|
||||
if (predicate(item))
|
||||
{
|
||||
return Option<TEntry>.Some(item);
|
||||
}
|
||||
}
|
||||
return Option<TEntry>.None;
|
||||
}
|
||||
public virtual int GetOrAddIndex(TEntry entry)
|
||||
{
|
||||
int index;
|
||||
if (_index.TryGetValue(entry, out index))
|
||||
return index;
|
||||
index = _entries.Count;
|
||||
_index.Add(entry, index);
|
||||
_entries.Add(entry);
|
||||
return index;
|
||||
}
|
||||
|
||||
public IReadOnlyList<TEntry> Entries => _entries;
|
||||
public void Clear()
|
||||
{
|
||||
_entries.Clear();
|
||||
_index.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class RefPalette<TEntry> where TEntry : IEquatable<TEntry>
|
||||
{
|
||||
private readonly List<TEntry> _entries = new();
|
||||
private readonly List<int> _refCounts = new();
|
||||
private readonly Dictionary<TEntry, int> _index = new();
|
||||
private readonly Stack<int> _free = new();
|
||||
|
||||
public RefPalette(TEntry defaultEntry)
|
||||
{
|
||||
_entries.Add(defaultEntry);
|
||||
_refCounts.Add(int.MaxValue); // default entry never removed
|
||||
_index.Add(defaultEntry, 0);
|
||||
}
|
||||
|
||||
public int Count => _entries.Count;
|
||||
public IReadOnlyList<TEntry> Entries => _entries;
|
||||
|
||||
public TEntry Get(int index)
|
||||
{
|
||||
Debug.Assert(index >= 0 && index < _entries.Count,
|
||||
$"{nameof(index)} out of range. index={index}, count={_entries.Count}");
|
||||
|
||||
return _entries[index];
|
||||
}
|
||||
|
||||
public int GetOrAddIndex(TEntry entry)
|
||||
{
|
||||
if (_index.TryGetValue(entry, out var index))
|
||||
return index;
|
||||
|
||||
if (_free.Count > 0)
|
||||
{
|
||||
index = _free.Pop();
|
||||
_entries[index] = entry;
|
||||
_refCounts[index] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = _entries.Count;
|
||||
_entries.Add(entry);
|
||||
_refCounts.Add(0);
|
||||
}
|
||||
|
||||
_index[entry] = index;
|
||||
return index;
|
||||
}
|
||||
|
||||
public void AddRef(int index)
|
||||
{
|
||||
Debug.Assert(index >= 0 && index < _refCounts.Count);
|
||||
_refCounts[index]++;
|
||||
}
|
||||
|
||||
public void Release(int index)
|
||||
{
|
||||
Debug.Assert(index > 0 && index < _refCounts.Count); // never release default
|
||||
|
||||
int count = --_refCounts[index];
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
var entry = _entries[index];
|
||||
_index.Remove(entry);
|
||||
|
||||
_entries[index] = default!;
|
||||
_free.Push(index);
|
||||
}
|
||||
}
|
||||
|
||||
public int RefCount(int index)
|
||||
{
|
||||
return _refCounts[index];
|
||||
}
|
||||
|
||||
public Option<TEntry> Get(Predicate<TEntry> predicate)
|
||||
{
|
||||
for (int i = 0; i < _entries.Count; i++)
|
||||
{
|
||||
if (_refCounts[i] > 0 && predicate(_entries[i]))
|
||||
return Option<TEntry>.Some(_entries[i]);
|
||||
}
|
||||
|
||||
return Option<TEntry>.None;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user