like actually rewrite object tables and ptrs and stuff. much happier now
This commit is contained in:
parent
bdd1322a82
commit
a66580e7fe
|
|
@ -1,118 +0,0 @@
|
||||||
using Qrakhen.Qamp.Core.Collections.Abstractions;
|
|
||||||
using Qrakhen.Qamp.Core.Values;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Qrakhen.Qamp.Core.Collections;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Similar to a register with the caveat that the memory can free up or reserve blocks within itself, returning the next writeable address when storing data.
|
|
||||||
/// </summary>
|
|
||||||
public class Addreg<TValue> :
|
|
||||||
IGetSet<Address, TValue>,
|
|
||||||
IToArray<TValue>,
|
|
||||||
IEnumerable<KeyValuePair<Address, TValue>>
|
|
||||||
{
|
|
||||||
private const int BLOCK_SIZE = sizeof(int);
|
|
||||||
private const uint BLOCK_FULL = (uint)((1UL << 32) - 1);
|
|
||||||
|
|
||||||
private readonly TValue[] _data;
|
|
||||||
|
|
||||||
private readonly uint[] _alloc;
|
|
||||||
|
|
||||||
public int Size { get; }
|
|
||||||
|
|
||||||
public TValue this[Address index]
|
|
||||||
{
|
|
||||||
get => _data[index];
|
|
||||||
set => _data[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Addreg(int size = 4096)
|
|
||||||
{
|
|
||||||
Size = size;
|
|
||||||
_data = new TValue[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetBlockIndex(Address address)
|
|
||||||
{
|
|
||||||
return (int)(address / BLOCK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetBitIndex(Address address)
|
|
||||||
{
|
|
||||||
return (int)(address % BLOCK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Address SeekFree(Address from = default)
|
|
||||||
{
|
|
||||||
Address cur = from - (from % BLOCK_SIZE);
|
|
||||||
while (cur < Size)
|
|
||||||
{
|
|
||||||
int block = GetBlockIndex(cur);
|
|
||||||
uint mask = _alloc[block];
|
|
||||||
if (mask < BLOCK_FULL)
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
while ((mask & (1 << index)) > 0)
|
|
||||||
index++;
|
|
||||||
|
|
||||||
return (Address)((long)block * BLOCK_SIZE + index);
|
|
||||||
}
|
|
||||||
cur += BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
return Address.Void;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Free(Address address, int size = 1)
|
|
||||||
{
|
|
||||||
ArgumentOutOfRangeException.ThrowIfNotEqual(1, size); // only support single address freeing atm
|
|
||||||
int block = GetBlockIndex(address);
|
|
||||||
int index = GetBitIndex(address);
|
|
||||||
uint flags = _alloc[block];
|
|
||||||
_alloc[block] &= ~(1U << index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Allocate(int size = 1)
|
|
||||||
{
|
|
||||||
ArgumentOutOfRangeException.ThrowIfNotEqual(1, size); // only support single address allocation atm
|
|
||||||
Address address = SeekFree();
|
|
||||||
int block = GetBlockIndex(address);
|
|
||||||
int index = GetBitIndex(address);
|
|
||||||
_alloc[block] |= (1U << index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TValue[] ToArray()
|
|
||||||
{
|
|
||||||
return _data.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TValue Get(Address index)
|
|
||||||
{
|
|
||||||
return _data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(Address index, TValue value)
|
|
||||||
{
|
|
||||||
_data[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address Add(TValue value)
|
|
||||||
{
|
|
||||||
Address free = SeekFree();
|
|
||||||
if (free == Address.Void)
|
|
||||||
throw new QampException($"Tried to add {value} to a memory block, but no free memory could be allocated.");
|
|
||||||
Set(free, value);
|
|
||||||
return free;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<Address, TValue>> GetEnumerator()
|
|
||||||
{
|
|
||||||
for (Address addr = 0; addr < Size; addr++)
|
|
||||||
yield return new KeyValuePair<Address, TValue>(addr, Get(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
using Qrakhen.Qamp.Core.Collections.Abstractions;
|
||||||
|
using Qrakhen.Qamp.Core.Values;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Qrakhen.Qamp.Core.Collections;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Similar to a register with <see cref="Address"/> as key;
|
||||||
|
/// But with the caveat that the memory slots can be allocated or freed up,
|
||||||
|
/// automatically seeking for free addresses when adding data,
|
||||||
|
/// making it much easier to deal with addresses or pointers.
|
||||||
|
/// </summary>
|
||||||
|
public class Table<TValue> :
|
||||||
|
IGetSet<Address, TValue>,
|
||||||
|
IToArray<TValue>,
|
||||||
|
IEnumerable<KeyValuePair<Address, TValue>>
|
||||||
|
{
|
||||||
|
public const int BLOCK_SIZE = sizeof(int);
|
||||||
|
private const uint BLOCK_FULL = (uint)((1UL << 32) - 1);
|
||||||
|
|
||||||
|
private readonly TValue[] _data;
|
||||||
|
private readonly uint[] _alloc;
|
||||||
|
|
||||||
|
public int Size { get; }
|
||||||
|
public int Blocks => Size / BLOCK_SIZE;
|
||||||
|
|
||||||
|
public TValue this[Address index]
|
||||||
|
{
|
||||||
|
get => Get(index);
|
||||||
|
set => Set(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Table(int size = 4096)
|
||||||
|
{
|
||||||
|
Size = size;
|
||||||
|
if (size % BLOCK_SIZE != 0)
|
||||||
|
throw new ArgumentException($"{nameof(Table<TValue>)} size parameter must be product (multiple) of its block size {BLOCK_SIZE}.");
|
||||||
|
_data = new TValue[size];
|
||||||
|
_alloc = new uint[size / BLOCK_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetBlockIndex(Address address)
|
||||||
|
{
|
||||||
|
return (int)(address / BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetBitIndex(Address address)
|
||||||
|
{
|
||||||
|
return (int)(address % BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAllocated(Address address)
|
||||||
|
{
|
||||||
|
return (_alloc[GetBlockIndex(address)] & (1 << GetBitIndex(address))) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAllocBit(Address address, bool value)
|
||||||
|
{
|
||||||
|
int block = GetBlockIndex(address);
|
||||||
|
int index = GetBitIndex(address);
|
||||||
|
if (value)
|
||||||
|
_alloc[block] |= 1U << index;
|
||||||
|
else
|
||||||
|
_alloc[block] &= ~(1U << index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Address SeekFree(Address from = default)
|
||||||
|
{
|
||||||
|
Address cur = from - (from % BLOCK_SIZE);
|
||||||
|
while (cur < Size)
|
||||||
|
{
|
||||||
|
int block = GetBlockIndex(cur);
|
||||||
|
uint mask = _alloc[block];
|
||||||
|
if (mask < BLOCK_FULL)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
while ((mask & (1 << index)) > 0)
|
||||||
|
index++;
|
||||||
|
|
||||||
|
return (Address)((long)block * BLOCK_SIZE + index);
|
||||||
|
}
|
||||||
|
cur += BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
return Address.Void;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Validate(Address address)
|
||||||
|
{
|
||||||
|
if (address < 0 || address >= Size)
|
||||||
|
throw new RuntimeException($"Tried to access address outside memory {address}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(Address address, int size = 1)
|
||||||
|
{
|
||||||
|
ArgumentOutOfRangeException.ThrowIfNotEqual(1, size); // only support single address freeing atm
|
||||||
|
SetAllocBit(address, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address Allocate(int size = 1)
|
||||||
|
{
|
||||||
|
ArgumentOutOfRangeException.ThrowIfNotEqual(1, size); // only support single address allocation atm
|
||||||
|
Address address = SeekFree();
|
||||||
|
SetAllocBit(address, true);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue[] ToArray()
|
||||||
|
{
|
||||||
|
return [.. _data];
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue Get(Address index)
|
||||||
|
{
|
||||||
|
Validate(index);
|
||||||
|
if (!IsAllocated(index))
|
||||||
|
return default;
|
||||||
|
return _data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGet(Address index, [MaybeNullWhen(false)] out TValue? value)
|
||||||
|
{
|
||||||
|
Validate(index);
|
||||||
|
value = default;
|
||||||
|
if (!IsAllocated(index))
|
||||||
|
return false;
|
||||||
|
value = _data[index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(Address index, TValue value)
|
||||||
|
{
|
||||||
|
Validate(index);
|
||||||
|
SetAllocBit(index, true);
|
||||||
|
_data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calls <see cref="Allocate(int)"/> and then <see cref="Set(Address, TValue)"/>,
|
||||||
|
/// returning the address at which <paramref name="value"/> was stored at.
|
||||||
|
/// </summary>
|
||||||
|
public Address Add(TValue value)
|
||||||
|
{
|
||||||
|
Address free = SeekFree();
|
||||||
|
if (free == Address.Void)
|
||||||
|
throw new QampException($"Tried to add {value} to a memory block, but no free memory could be allocated.");
|
||||||
|
Set(free, value);
|
||||||
|
return free;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Print()
|
||||||
|
{
|
||||||
|
string r = $"Table [{nameof(TValue)}]:\n";
|
||||||
|
int c = 0;
|
||||||
|
for (int b = 0; b < Blocks; b++)
|
||||||
|
{
|
||||||
|
uint block = _alloc[b];
|
||||||
|
if (block == 0)
|
||||||
|
continue;
|
||||||
|
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||||
|
{
|
||||||
|
Address address = MakeAddress(b, i);
|
||||||
|
if (!IsAllocated(address))
|
||||||
|
continue;
|
||||||
|
c++;
|
||||||
|
r += $" {address}: {Get(address)}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r += $"{c}/{Size - c} slots allocated.";
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Address MakeAddress(int block, int index) => new((long)block * BLOCK_SIZE + index);
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<Address, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
for (Address addr = 0; addr < Size; addr++)
|
||||||
|
yield return new KeyValuePair<Address, TValue>(addr, Get(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ public readonly record struct Address(long Value)
|
||||||
{
|
{
|
||||||
public static readonly Address Void = new Address(-1);
|
public static readonly Address Void = new Address(-1);
|
||||||
|
|
||||||
public override string ToString() => $"&{Value:x8}";
|
public override string ToString() => Value < 0 ? "&void" : $"&{Value:x8}";
|
||||||
|
|
||||||
public static implicit operator long(Address address) => address.Value;
|
public static implicit operator long(Address address) => address.Value;
|
||||||
public static implicit operator Address(long value) => new(value);
|
public static implicit operator Address(long value) => new(value);
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,39 @@
|
||||||
|
|
||||||
namespace Qrakhen.Qamp.Core.Values.Objects;
|
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||||
|
|
||||||
public static class ObjRegister
|
public class ObjTable(int size = 4096)
|
||||||
{
|
{
|
||||||
private static readonly Addreg<Obj> _register = [];
|
public static readonly ObjTable Shared = new ObjTable(4096);
|
||||||
|
|
||||||
|
private readonly Table<Obj> _table = new Table<Obj>(size);
|
||||||
|
|
||||||
|
public Obj? Get(Address address) => _table[address];
|
||||||
|
public T? Get<T>(Address address) where T : Obj => _table[address] as T;
|
||||||
|
public bool TryGet(Address address, out Obj? obj) => _table.TryGet(address, out obj);
|
||||||
|
public void Free(Address address) => _table.Free(address);
|
||||||
|
public Address Register(Obj obj) => _table.Add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Obj(ValueType type) : ITypedValue
|
public class Obj : ITypedValue
|
||||||
{
|
{
|
||||||
public bool __gcMarked = false;
|
internal bool __GC_Marked = false;
|
||||||
public int __gcCount = 1;
|
internal int __GC_Count = 1;
|
||||||
|
|
||||||
public readonly ValueType Type = type;
|
internal readonly Address __Address; // unsure lol
|
||||||
|
public readonly ValueType Type;
|
||||||
|
|
||||||
public ValueType ValueType => Type;
|
public ValueType ValueType => Type;
|
||||||
|
|
||||||
|
public Obj(ValueType type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
__Address = ObjTable.Shared.Register(this);
|
||||||
|
}
|
||||||
|
|
||||||
public static Value Create(Obj obj)
|
public static Value Create(Obj obj)
|
||||||
{
|
{
|
||||||
return new Value(Ptr.Create(obj));
|
return new Value(Ptr.Create(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => "Obj<undefined>";
|
public override string ToString() => "Obj<undefined>";
|
||||||
|
|
||||||
static Obj()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ public class String(string? value) : Obj(ValueType.String)
|
||||||
List<byte> result = new();
|
List<byte> result = new();
|
||||||
foreach (var pair in _strings) {
|
foreach (var pair in _strings) {
|
||||||
String str = pair.Value;
|
String str = pair.Value;
|
||||||
if (str == null || str.__gcMarked)
|
if (str == null || str.__GC_Marked)
|
||||||
continue;
|
continue;
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
bytes = Encoding.ASCII.GetBytes(str.Value!);
|
bytes = Encoding.ASCII.GetBytes(str.Value!);
|
||||||
|
|
|
||||||
|
|
@ -4,33 +4,25 @@ using Qrakhen.Qamp.Core.Collections;
|
||||||
|
|
||||||
namespace Qrakhen.Qamp.Core.Values;
|
namespace Qrakhen.Qamp.Core.Values;
|
||||||
|
|
||||||
|
// generally interesting: GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Normal));
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = sizeof(ulong))]
|
[StructLayout(LayoutKind.Sequential, Size = sizeof(ulong))]
|
||||||
public readonly struct Ptr
|
public readonly struct Ptr
|
||||||
{
|
{
|
||||||
private static readonly PushStack<Obj> _register = new();
|
private static readonly Table<Obj> _register = []; // should not be needed that anymore tbh.
|
||||||
|
|
||||||
private static readonly Collections.Addreg<Obj> _memory = [];
|
|
||||||
|
|
||||||
[Serialized] public readonly Address Address;
|
[Serialized] public readonly Address Address;
|
||||||
|
|
||||||
//private readonly IntPtr _pointer;
|
|
||||||
//public IntPtr Pointer => _pointer;
|
|
||||||
|
|
||||||
public Obj? Value {
|
public Obj? Value {
|
||||||
get {
|
get {
|
||||||
if (_register.TryGet(Address, out Obj obj))
|
if (ObjTable.Shared.TryGet(Address, out Obj? obj))
|
||||||
return obj;
|
return obj;
|
||||||
return null;
|
return null;
|
||||||
//if (_pointer == IntPtr.Zero)
|
|
||||||
// throw new ObjectDisposedException(nameof(Ptr));
|
|
||||||
//return (Obj)GCHandle.FromIntPtr(_pointer).Target!;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Ptr(Address address)
|
private Ptr(Address address)
|
||||||
{
|
{
|
||||||
|
|
||||||
//_pointer = GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Normal));
|
|
||||||
Address = address;
|
Address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +53,7 @@ public readonly struct Ptr
|
||||||
{
|
{
|
||||||
await Task.Run(() => {
|
await Task.Run(() => {
|
||||||
foreach (var obj in _register) {
|
foreach (var obj in _register) {
|
||||||
obj.__gcCount = 0;
|
obj.Value.__GC_Count = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -69,9 +61,9 @@ public readonly struct Ptr
|
||||||
public static byte[] SerializeFunctions()
|
public static byte[] SerializeFunctions()
|
||||||
{
|
{
|
||||||
List<byte> result = new();
|
List<byte> result = new();
|
||||||
for (int i = 0; i < _register.Count; i++) {
|
foreach (var element in _register) {
|
||||||
Obj obj = _register.Get(i);
|
Obj obj = element.Value;
|
||||||
if (obj == null || obj.__gcMarked)
|
if (obj == null || obj.__GC_Marked)
|
||||||
continue;
|
continue;
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
if (obj is Function function) {
|
if (obj is Function function) {
|
||||||
|
|
@ -82,7 +74,7 @@ public readonly struct Ptr
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.AddRange(i.GetBytes());
|
result.AddRange(((long)element.Key).GetBytes());
|
||||||
result.AddRange(bytes.Length.GetBytes());
|
result.AddRange(bytes.Length.GetBytes());
|
||||||
result.AddRange(bytes);
|
result.AddRange(bytes);
|
||||||
result.Add(0);
|
result.Add(0);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue