File size: 3,894 Bytes
f7ccd08 32b4893 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | { SPDX-License-Identifier: LicenseRef-Sovereign-Leviathan-SL-AGPL3-001
Licensing: see LICENSE in the repository root. }
{ Buffer: Physical storage management with generation tracking.
Implements allocation, reference counting, and generation counters
for temporal safety (use-after-free detection).
Key properties:
- Generational tracking: each buffer has monotonically increasing generation
- Arc semantics: refcount > 1 indicates shared ownership
- Memory safety: generation validation prevents stale references
}
unit buffer;
{$MODE FPC}
interface
type
{ Buffer metadata }
TBuffer = record
{ Allocated data }
data: ^single;
{ Physical size in elements }
size: uint32;
{ Reference count (Arc semantics) }
refcount: uint32;
{ Generation counter for temporal safety }
generation: uint32;
end;
PBuffer = ^TBuffer;
{ Allocate a new buffer with given size }
function AllocateBuffer(size: uint32): PBuffer;
{ Free a buffer (when refcount reaches 0) }
procedure FreeBuffer(var buf: PBuffer);
{ Increment reference count (Arc::clone equivalent) }
procedure CloneBuffer(buf: PBuffer);
{ Decrement reference count }
procedure ReleaseBuffer(var buf: PBuffer);
{ Check if buffer is exclusively owned (refcount = 1) }
function IsExclusivelyOwned(buf: PBuffer): boolean;
{ Get current generation of buffer }
function GetGeneration(buf: PBuffer): uint32;
{ Increment generation on mutation }
procedure IncrementGeneration(buf: PBuffer);
{ Validate that generation matches expected }
function ValidateGeneration(buf: PBuffer; expected: uint32): boolean;
{ Zero-initialize a buffer region }
procedure ZeroBuffer(buf: PBuffer; size: uint32);
{ Copy data from source to destination buffer }
procedure CopyBufferData(
src: PBuffer; src_offset: uint32;
dst: PBuffer; dst_offset: uint32;
count: uint32
);
implementation
var
{ Global generation counter for allocation tracking }
global_generation: uint32 = 0;
function AllocateBuffer(size: uint32): PBuffer;
var
buf: PBuffer;
begin
new(buf);
if buf = nil then
exit(nil);
getmem(buf^.data, size * sizeof(single));
if buf^.data = nil then
begin
dispose(buf);
exit(nil);
end;
buf^.size := size;
buf^.refcount := 1;
buf^.generation := global_generation;
inc(global_generation);
{ Zero-initialize }
ZeroBuffer(buf, size);
result := buf;
end;
procedure FreeBuffer(var buf: PBuffer);
begin
if buf = nil then
exit;
if buf^.data <> nil then
freemem(buf^.data);
dispose(buf);
buf := nil;
end;
procedure CloneBuffer(buf: PBuffer);
begin
if buf <> nil then
inc(buf^.refcount);
end;
procedure ReleaseBuffer(var buf: PBuffer);
begin
if buf = nil then
exit;
dec(buf^.refcount);
if buf^.refcount = 0 then
FreeBuffer(buf)
else
buf := nil;
end;
function IsExclusivelyOwned(buf: PBuffer): boolean;
begin
if buf = nil then
result := false
else
result := (buf^.refcount = 1);
end;
function GetGeneration(buf: PBuffer): uint32;
begin
if buf = nil then
result := 0
else
result := buf^.generation;
end;
procedure IncrementGeneration(buf: PBuffer);
begin
if buf <> nil then
begin
inc(buf^.generation);
inc(global_generation);
end;
end;
function ValidateGeneration(buf: PBuffer; expected: uint32): boolean;
begin
if buf = nil then
result := false
else
result := (buf^.generation = expected);
end;
procedure ZeroBuffer(buf: PBuffer; size: uint32);
var
i: uint32;
begin
if buf = nil then
exit;
for i := 0 to size - 1 do
buf^.data^[i] := 0.0;
end;
procedure CopyBufferData(
src: PBuffer; src_offset: uint32;
dst: PBuffer; dst_offset: uint32;
count: uint32
);
var
i: uint32;
begin
if (src = nil) or (dst = nil) then
exit;
for i := 0 to count - 1 do
dst^.data^[dst_offset + i] := src^.data^[src_offset + i];
end;
end.
|