259 lines
6.7 KiB
Plaintext
259 lines
6.7 KiB
Plaintext
comptime {
|
|
_ = start;
|
|
}
|
|
|
|
test {
|
|
_ = build;
|
|
_ = builtin;
|
|
_ = data_structures;
|
|
_ = os;
|
|
_ = start;
|
|
}
|
|
|
|
const build = #import("build.nat");
|
|
const builtin = #import("builtin.nat");
|
|
const testing = #import("testing.nat");
|
|
|
|
const data_structures = #import("data_structures.nat");
|
|
|
|
const c = #import("c.nat");
|
|
const os = #import("os.nat");
|
|
|
|
const start = #import("start.nat");
|
|
|
|
const assert = fn(ok: bool) void {
|
|
if (!ok) {
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
const byte_equal = fn (a: []const u8, b: []const u8) bool {
|
|
var result = false;
|
|
if (a.length == b.length) {
|
|
result = true;
|
|
for (a, b) |a_byte, b_byte| {
|
|
if (a_byte != b_byte) {
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const print = fn(bytes: []const u8) void {
|
|
const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout);
|
|
const file_writer = FileWriter{
|
|
.descriptor = file_descriptor,
|
|
};
|
|
_ = file_writer.write_all(bytes) catch unreachable;
|
|
}
|
|
|
|
const format_usize = fn(n: usize, buffer: &[65]u8) []u8 {
|
|
var index: usize = buffer.length;
|
|
var absolute = n;
|
|
|
|
while (true) {
|
|
const digit: u8 = #cast(absolute % 10);
|
|
index -= 1;
|
|
const ch = '0' + digit;
|
|
buffer[index] = ch;
|
|
assert(buffer[index] == ch);
|
|
absolute /= 10;
|
|
|
|
if (absolute == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return buffer[index..];
|
|
}
|
|
|
|
const print_usize = fn(n: usize) void {
|
|
var buffer: [65]u8 = undefined;
|
|
const bytes = format_usize(n, buffer = buffer.&);
|
|
assert(bytes.length < buffer.length);
|
|
const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout);
|
|
const file_writer = FileWriter{
|
|
.descriptor = file_descriptor,
|
|
};
|
|
file_writer.write_all(bytes) catch unreachable;
|
|
}
|
|
|
|
const print_u8 = fn(n: u8) void {
|
|
print_usize(n);
|
|
}
|
|
|
|
const kilobytes = fn (n: u64) u64 {
|
|
return n * 1024;
|
|
}
|
|
|
|
const megabytes = fn (n: u64) u64 {
|
|
return n * 1024 * 1024;
|
|
}
|
|
|
|
const gigabytes = fn (n: u64) u64 {
|
|
return n * 1024 * 1024 * 1024;
|
|
}
|
|
|
|
const terabytes = fn (n: u64) u64 {
|
|
return n * 1024 * 1024 * 1024 * 1024;
|
|
}
|
|
|
|
const Arena = struct{
|
|
position: u64,
|
|
commit_position: u64,
|
|
alignment: u64,
|
|
size: u64,
|
|
|
|
const Temporary = struct{
|
|
arena: &Arena,
|
|
position: u64,
|
|
};
|
|
|
|
const commit_granularity = 2 * 1024 * 1024;
|
|
const reserve = os.reserve;
|
|
const commit = os.commit;
|
|
|
|
const init = fn (requested_size: u64) *!&Arena {
|
|
var size = requested_size;
|
|
const size_roundup_granularity = megabytes(64);
|
|
size += size_roundup_granularity - 1;
|
|
size -= size % size_roundup_granularity;
|
|
const initial_commit_size = commit_granularity;
|
|
assert(initial_commit_size >= #size(Arena));
|
|
|
|
const reserved_memory = try reserve(size);
|
|
try commit(reserved_memory, initial_commit_size);
|
|
|
|
const arena: &Arena = #cast(reserved_memory);
|
|
arena.@ = .{
|
|
.position = #size(Arena),
|
|
.commit_position = initial_commit_size,
|
|
.alignment = 8,
|
|
.size = size,
|
|
};
|
|
|
|
return arena;
|
|
}
|
|
|
|
const allocate = fn (arena: &Arena, size: u64) *!&any {
|
|
|
|
if (arena.position + size <= arena.size) {
|
|
const base: &any = #cast(arena);
|
|
var post_alignment_position = arena.position + arena.alignment - 1;
|
|
post_alignment_position -= post_alignment_position % arena.alignment;
|
|
const alignment = post_alignment_position - arena.position;
|
|
const result = base + arena.position + alignment;
|
|
arena.position += size + alignment;
|
|
|
|
if (arena.commit_position < arena.position - arena.commit_position) {
|
|
var size_to_commit = arena.position - arena.commit_position;
|
|
size_to_commit += commit_granularity - 1;
|
|
size_to_commit -= size_to_commit % commit_granularity;
|
|
try commit(base + arena.commit_position, size_to_commit);
|
|
arena.commit_position += size_to_commit;
|
|
}
|
|
|
|
return result;
|
|
} else {
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
const new = fn (arena: &Arena, $T: type) *!&T {
|
|
const result: &T = #cast(arena.allocate(#size(T)));
|
|
return result;
|
|
}
|
|
|
|
const new_array = fn (arena: &Arena, $T: type, count: usize) *![]T {
|
|
const result: [&]T = #cast(try arena.allocate(#size(T) * count));
|
|
return result[0..count];
|
|
}
|
|
};
|
|
|
|
const Writer = struct{
|
|
callback: &const fn(writer: &Writer, bytes: []const u8) Writer.Error!usize,
|
|
const Error = error{
|
|
write_failed,
|
|
};
|
|
};
|
|
|
|
const FileWriter = struct{
|
|
descriptor: os.FileDescriptor,
|
|
|
|
const write = fn(file_writer: FileWriter, bytes: []const u8) Writer.Error!usize {
|
|
const bytes_written = file_writer.descriptor.write(bytes) catch return Writer.Error.write_failed;
|
|
return bytes_written;
|
|
}
|
|
|
|
const write_all = fn(file_writer: FileWriter, bytes: []const u8) Writer.Error!void {
|
|
var bytes_written: usize = 0;
|
|
|
|
while (bytes_written < bytes.length) {
|
|
const iteration_written_byte_count = try file_writer.write(bytes = bytes[bytes_written..]);
|
|
bytes_written += iteration_written_byte_count;
|
|
}
|
|
|
|
assert(bytes_written == bytes.length);
|
|
}
|
|
};
|
|
|
|
const copy_bytes = fn(destination: []u8, source: []const u8) void {
|
|
assert(ok = destination.length == source.length);
|
|
for (0..destination.length) |i| {
|
|
destination[i] = source[i];
|
|
}
|
|
}
|
|
|
|
const c_len = fn (pointer_to_string: [&:0]const u8) usize {
|
|
var i: usize = 0;
|
|
while (pointer_to_string[i] != 0) {
|
|
i += 1;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
const c_slice = fn (pointer_to_string: [&:0]const u8) [:0]const u8 {
|
|
const length = c_len(pointer_to_string);
|
|
return pointer_to_string[0..length:0];
|
|
}
|
|
|
|
const concatenate_bytes = fn (arena: &Arena, byte_sequences: []const []const u8) *![]u8 {
|
|
var byte_count: usize = 0;
|
|
for (byte_sequences) |byte_sequence| {
|
|
byte_count += byte_sequence.length;
|
|
}
|
|
|
|
var concatenation = try arena.new_array($u8, byte_count);
|
|
var offset: usize = 0;
|
|
|
|
for (byte_sequences) |bs| {
|
|
var i: usize = 0;
|
|
|
|
while (i < bs.length) {
|
|
concatenation[offset + i] = bs[i];
|
|
i += 1;
|
|
}
|
|
|
|
offset += i;
|
|
}
|
|
|
|
return concatenation;
|
|
}
|
|
|
|
test "concatenate" {
|
|
var arena = try Arena.init(2*1024*1024);
|
|
const concatenation = try concatenate_bytes(arena, .{ "ABC", "DEF" }.&);
|
|
const are_equal = byte_equal(concatenation, "ABCDEF");
|
|
try testing.expect(are_equal);
|
|
}
|
|
|
|
const Target = struct {
|
|
cpu: builtin.Cpu,
|
|
os: builtin.Os,
|
|
abi: builtin.Abi,
|
|
};
|