Files
doslang-mirror/fec/std/mem.fe
T
coolguy ae83f5b142 std: mem.Arena 를 구현한다
SPEC R11 은 재귀·그래프 모양 데이터를 아레나가 값을 소유하고 정수 핸들이
가리키는 것으로 답한다. 그 답은 아레나가 실제로 있어야 쓸 수 있다.

핸들은 오프셋이라 아레나가 사는 동안 유효하고, 두 핸들을 비교하는 것은 두 수를
비교하는 것이다. 아레나는 몰래 자라지 않는다 -- 움직인 핸들은 더 이상 아무것도
가리키지 않기 때문이다.

길에서 고친 것 셋:

- Self 가 제네릭 인스턴스에서만 타입으로 묶여 있어서, 평범한 구조체의 Self{..}
  가 안 풀렸다. 이제 모든 메서드에서 묶는다.
- binding.Type.method() 가 식 자리에서 해석되지 않았다.
- 다른 유닛의 비제네릭 구조체 메서드가 lowering 되지 않고 extern 으로만 나갔다.
  파일을 나눌 때 그 가지가 빠졌다.

  handles 0 4 8 / value 65 / full / reset 0 / balanced

exec.py 26/26.
2026-08-17 07:21:40 +09:00

61 lines
2.2 KiB
Plaintext

unit std.mem;
import std.sys;
// `create`, `destroy`, `alloc_slice` and `replace` are compiler intrinsics:
// they need to know the type they are handed, which no signature can say.
// What is written here is what can be written in Ferro.
/// A block of storage handed out in pieces, released all at once.
///
/// SPEC R11 answers recursive and graph-shaped data with an arena that owns
/// the values and integer handles that reference them. This is that arena. A
/// handle is an offset, so it stays valid while the arena does, and comparing
/// two handles is comparing two numbers.
pub struct Arena {
bytes: ^[]mut u8,
used: usize,
pub fn with_capacity(n: usize) -> !Self {
let room: ^[]mut u8 = try mem.alloc_slice(u8, n);
return Self{ bytes: room, used: 0 };
}
pub fn size(self: &Self) -> usize { return self.used; }
pub fn room(self: &Self) -> usize { return self.bytes.^.n; }
/// Reserve `n` bytes aligned to `align` and give back where they start.
/// Failure is running out of room, which the caller decides what to do
/// about; the arena never grows behind your back, because a handle that
/// moved would no longer mean anything.
pub fn alloc(self: &mut Self, n: usize, align: usize) -> !usize {
var at: usize = self.used;
if align > 1 {
let over: usize = at % align;
if over != 0 { at = at + align - over; }
}
if at + n > self.bytes.^.n { return error.ArenaFull; }
self.used = at + n;
return at;
}
/// One byte at a handle. Reading and writing go through here so that a
/// handle can be checked once, in one place.
pub fn at(self: &Self, handle: usize) -> !u8 {
if handle >= self.used { return error.BadHandle; }
return self.bytes.^[handle];
}
pub fn put(self: &mut Self, handle: usize, value: u8) -> !void {
if handle >= self.used { return error.BadHandle; }
self.bytes.^[handle] = value;
return;
}
/// Forget everything handed out so far. Every handle from before is stale;
/// that is the trade an arena makes.
pub fn reset(self: &mut Self) -> void { self.used = 0; }
pub fn drop(self: &mut Self) -> void { mem.destroy(self.bytes); }
}