add memory class isnt that cool
This commit is contained in:
parent
880f3e60ce
commit
f62c48396f
|
|
@ -0,0 +1,118 @@
|
|||
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 Memory<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 Memory(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();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,9 @@ namespace Qrakhen.Qamp.Core.Values;
|
|||
[StructLayout(LayoutKind.Sequential, Size = sizeof(long))]
|
||||
public readonly record struct Address(long Value)
|
||||
{
|
||||
public override string ToString() => $"0x{Value:x8}";
|
||||
public static readonly Address Void = new Address(-1);
|
||||
|
||||
public override string ToString() => $"&{Value:x8}";
|
||||
|
||||
public static implicit operator long(Address address) => address.Value;
|
||||
public static implicit operator Address(long value) => new(value);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ public readonly struct Ptr
|
|||
{
|
||||
private static readonly PushStack<Obj> _register = new();
|
||||
|
||||
private static readonly Collections.Memory<Obj> _memory = [];
|
||||
|
||||
[Serialized] public readonly Address Address;
|
||||
|
||||
//private readonly IntPtr _pointer;
|
||||
|
|
@ -27,6 +29,7 @@ public readonly struct Ptr
|
|||
|
||||
private Ptr(Address address)
|
||||
{
|
||||
|
||||
//_pointer = GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Normal));
|
||||
Address = address;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using Qrakhen.Qamp.Core.Abstractions;
|
||||
using Qrakhen.Qamp.Core.Values.Objects;
|
||||
using String = Qrakhen.Qamp.Core.Values.Objects.String;
|
||||
|
|
@ -7,6 +8,27 @@ using T = Qrakhen.Qamp.Core.Values.ValueType;
|
|||
|
||||
namespace Qrakhen.Qamp.Core.Values;
|
||||
|
||||
|
||||
|
||||
// HEY. IDEA.
|
||||
// have custom structs for types. this way we can handle many more thing and also more clean no????
|
||||
|
||||
public interface IPrimitive
|
||||
{
|
||||
public static abstract string Name { get; }
|
||||
public static abstract int SizeOf { get; }
|
||||
|
||||
public ulong Raw { get; }
|
||||
|
||||
public string Print();
|
||||
}
|
||||
|
||||
public readonly record struct Signed(long Value)// : IPrimitive
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public interface IValue<T>
|
||||
{
|
||||
T Data { get; }
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public enum ValueType
|
|||
Integer = Unsigned | Signed | Char,
|
||||
Primitive = Integer | Decimal | Bool,
|
||||
|
||||
Address = 0x0020, // coded with : symbol
|
||||
Address = 0x0020,
|
||||
|
||||
// classes etc. here?
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue