add memory class isnt that cool

This commit is contained in:
Qrakhen 2026-01-07 14:57:03 +01:00
parent 880f3e60ce
commit f62c48396f
5 changed files with 147 additions and 2 deletions

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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; }

View File

@ -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?