From f62c48396f98f3621da5199618127b1a46fffbfb Mon Sep 17 00:00:00 2001 From: Qrakhen Date: Wed, 7 Jan 2026 14:57:03 +0100 Subject: [PATCH] add memory class isnt that cool --- Qrakhen.Qamp.Core/Collections/Memory.cs | 118 ++++++++++++++++++++++++ Qrakhen.Qamp.Core/Values/Address.cs | 4 +- Qrakhen.Qamp.Core/Values/Ptr.cs | 3 + Qrakhen.Qamp.Core/Values/Value.cs | 22 +++++ Qrakhen.Qamp.Core/Values/ValueType.cs | 2 +- 5 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 Qrakhen.Qamp.Core/Collections/Memory.cs diff --git a/Qrakhen.Qamp.Core/Collections/Memory.cs b/Qrakhen.Qamp.Core/Collections/Memory.cs new file mode 100644 index 0000000..2723c79 --- /dev/null +++ b/Qrakhen.Qamp.Core/Collections/Memory.cs @@ -0,0 +1,118 @@ +using Qrakhen.Qamp.Core.Collections.Abstractions; +using Qrakhen.Qamp.Core.Values; +using System.Collections; + +namespace Qrakhen.Qamp.Core.Collections; + +/// +/// 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. +/// +public class Memory : + IGetSet, + IToArray, + IEnumerable> +{ + 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> GetEnumerator() + { + for (Address addr = 0; addr < Size; addr++) + yield return new KeyValuePair(addr, Get(addr)); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} diff --git a/Qrakhen.Qamp.Core/Values/Address.cs b/Qrakhen.Qamp.Core/Values/Address.cs index afb5ff0..a3640bc 100644 --- a/Qrakhen.Qamp.Core/Values/Address.cs +++ b/Qrakhen.Qamp.Core/Values/Address.cs @@ -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); diff --git a/Qrakhen.Qamp.Core/Values/Ptr.cs b/Qrakhen.Qamp.Core/Values/Ptr.cs index 13ad90c..f22fca0 100644 --- a/Qrakhen.Qamp.Core/Values/Ptr.cs +++ b/Qrakhen.Qamp.Core/Values/Ptr.cs @@ -9,6 +9,8 @@ public readonly struct Ptr { private static readonly PushStack _register = new(); + private static readonly Collections.Memory _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; } diff --git a/Qrakhen.Qamp.Core/Values/Value.cs b/Qrakhen.Qamp.Core/Values/Value.cs index 2e9899d..c50155f 100644 --- a/Qrakhen.Qamp.Core/Values/Value.cs +++ b/Qrakhen.Qamp.Core/Values/Value.cs @@ -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 Data { get; } diff --git a/Qrakhen.Qamp.Core/Values/ValueType.cs b/Qrakhen.Qamp.Core/Values/ValueType.cs index 00e6d8e..fe7a8c9 100644 --- a/Qrakhen.Qamp.Core/Values/ValueType.cs +++ b/Qrakhen.Qamp.Core/Values/ValueType.cs @@ -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?