Improve the StackAllocator so it allows all kinds of allocation patterns.

This allows using the StackAllocator for more data structures and library functions.
Fixes #268
Fixes #95 (at least to the point where I can't do anything about it)
This commit is contained in:
IntegratedQuantum 2024-02-08 17:59:18 +01:00
parent 0177099f6b
commit d08096057f
15 changed files with 153 additions and 146 deletions

View File

@ -25,7 +25,7 @@ pub fn readAllJsonFilesInAddons(externalAllocator: NeverFailingAllocator, addons
};
defer dir.close();
var walker = dir.walk(main.globalAllocator.allocator) catch unreachable;
var walker = dir.walk(main.stackAllocator.allocator) catch unreachable;
defer walker.deinit();
while(walker.next() catch |err| blk: {
@ -69,7 +69,7 @@ pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: ma
};
defer dir.close();
var walker = dir.walk(main.globalAllocator.allocator) catch unreachable;
var walker = dir.walk(main.stackAllocator.allocator) catch unreachable;
defer walker.deinit();
while(walker.next() catch |err| blk: {
@ -90,9 +90,9 @@ pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: ma
}
pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(JsonElement), items: *std.StringHashMap(JsonElement), biomes: *std.StringHashMap(JsonElement), recipes: *main.List([]const u8)) void {
var addons = main.List(std.fs.Dir).init(main.globalAllocator);
var addons = main.List(std.fs.Dir).init(main.stackAllocator);
defer addons.deinit();
var addonNames = main.List([]const u8).init(main.globalAllocator);
var addonNames = main.List([]const u8).init(main.stackAllocator);
defer addonNames.deinit();
{ // Find all the sub-directories to the assets folder.
@ -111,13 +111,13 @@ pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u
std.log.err("Got error while reading addon {s} from {s}: {s}", .{addon.name, assetPath, @errorName(err)});
continue;
});
addonNames.append(main.globalAllocator.dupe(u8, addon.name));
addonNames.append(main.stackAllocator.dupe(u8, addon.name));
}
}
}
defer for(addons.items, addonNames.items) |*dir, addonName| {
dir.close();
main.globalAllocator.free(addonName);
main.stackAllocator.free(addonName);
};
readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "blocks", blocks);
@ -224,13 +224,13 @@ var loadedAssets: bool = false;
pub fn loadWorldAssets(assetFolder: []const u8, palette: *BlockPalette) !void {
if(loadedAssets) return; // The assets already got loaded by the server.
loadedAssets = true;
var blocks = commonBlocks.cloneWithAllocator(main.globalAllocator.allocator) catch unreachable;
var blocks = commonBlocks.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer blocks.clearAndFree();
var items = commonItems.cloneWithAllocator(main.globalAllocator.allocator) catch unreachable;
var items = commonItems.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer items.clearAndFree();
var biomes = commonBiomes.cloneWithAllocator(main.globalAllocator.allocator) catch unreachable;
var biomes = commonBiomes.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer biomes.clearAndFree();
var recipes = main.List([]const u8).init(main.globalAllocator);
var recipes = main.List([]const u8).init(main.stackAllocator);
recipes.appendSlice(commonRecipes.items);
defer recipes.clearAndFree();

View File

@ -391,10 +391,8 @@ pub const draw = struct {
}
pub inline fn print(comptime format: []const u8, args: anytype, x: f32, y: f32, fontSize: f32, alignment: TextBuffer.Alignment) void {
var stackFallback = std.heap.stackFallback(4096, main.globalAllocator.allocator);
const allocator = stackFallback.get();
const string = std.fmt.allocPrint(allocator, format, args) catch unreachable;
defer allocator.free(string);
const string = std.fmt.allocPrint(main.stackAllocator.allocator, format, args) catch unreachable;
defer main.stackAllocator.free(string);
text(string, x, y ,fontSize, alignment);
}
};
@ -560,13 +558,11 @@ pub const TextBuffer = struct {
pub fn init(allocator: NeverFailingAllocator, text: []const u8, initialFontEffect: FontEffect, showControlCharacters: bool, alignment: Alignment) TextBuffer {
var self: TextBuffer = undefined;
self.alignment = alignment;
var stackFallback = std.heap.stackFallback(4096, main.globalAllocator.allocator);
const stackFallbackAllocator = stackFallback.get();
// Parse the input text:
var parser = Parser {
.unicodeIterator = std.unicode.Utf8Iterator{.bytes = text, .i = 0},
.currentFontEffect = initialFontEffect,
.parsedText = main.List(u32).init(.{.allocator = stackFallbackAllocator, .IAssertThatTheProvidedAllocatorCantFail = {}}),
.parsedText = main.List(u32).init(main.stackAllocator),
.fontEffects = main.List(FontEffect).init(allocator),
.characterIndex = main.List(u32).init(allocator),
.showControlCharacters = showControlCharacters
@ -1040,9 +1036,7 @@ const TextRendering = struct {
}
fn renderText(text: []const u8, x: f32, y: f32, fontSize: f32, initialFontEffect: TextBuffer.FontEffect, alignment: TextBuffer.Alignment) void {
var stackFallback = std.heap.stackFallback(4096, main.globalAllocator.allocator);
const allocator = stackFallback.get();
const buf = TextBuffer.init(.{.allocator = allocator, .IAssertThatTheProvidedAllocatorCantFail = {}}, text, initialFontEffect, false, alignment);
const buf = TextBuffer.init(main.stackAllocator, text, initialFontEffect, false, alignment);
defer buf.deinit();
buf.render(x, y, fontSize);
@ -1530,7 +1524,7 @@ pub const TextureArray = struct {
const maxLOD = if(mipmapping) 1 + std.math.log2_int(u31, @min(maxWidth, maxHeight)) else 1;
c.glTexStorage3D(c.GL_TEXTURE_2D_ARRAY, maxLOD, c.GL_RGBA8, maxWidth, maxHeight, @intCast(images.len));
var arena = main.utils.NeverFailingArenaAllocator.init(main.globalAllocator);
var arena = main.utils.NeverFailingArenaAllocator.init(main.stackAllocator);
defer arena.deinit();
const lodBuffer: [][]Color = arena.allocator().alloc([]Color, maxLOD);
for(lodBuffer, 0..) |*buffer, i| {

View File

@ -182,12 +182,12 @@ pub fn deinit() void {
}
fn save() void {
const guiJson = JsonElement.initObject(main.globalAllocator);
defer guiJson.free(main.globalAllocator);
const guiJson = JsonElement.initObject(main.stackAllocator);
defer guiJson.free(main.stackAllocator);
for(windowList.items) |window| {
const windowJson = JsonElement.initObject(main.globalAllocator);
const windowJson = JsonElement.initObject(main.stackAllocator);
for(window.relativePosition, 0..) |relPos, i| {
const relPosJson = JsonElement.initObject(main.globalAllocator);
const relPosJson = JsonElement.initObject(main.stackAllocator);
switch(relPos) {
.ratio => |ratio| {
relPosJson.put("type", "ratio");
@ -222,13 +222,13 @@ fn save() void {
}
fn load() void {
const json: JsonElement = main.files.readToJson(main.globalAllocator, "gui_layout.json") catch |err| blk: {
const json: JsonElement = main.files.readToJson(main.stackAllocator, "gui_layout.json") catch |err| blk: {
if(err != error.FileNotFound) {
std.log.err("Could not read gui_layout.json: {s}", .{@errorName(err)});
}
break :blk JsonElement{.JsonNull={}};
};
defer json.free(main.globalAllocator);
defer json.free(main.stackAllocator);
for(windowList.items) |window| {
const windowJson = json.getChild(window.id);
@ -649,7 +649,7 @@ pub const inventory = struct {
if(carriedItemStack.amount == 0) if(hoveredItemSlot) |hovered| {
if(hovered.itemStack.item) |item| {
const tooltip = item.getTooltip();
var textBuffer: graphics.TextBuffer = graphics.TextBuffer.init(main.globalAllocator, tooltip, .{}, false, .left);
var textBuffer: graphics.TextBuffer = graphics.TextBuffer.init(main.stackAllocator, tooltip, .{}, false, .left);
defer textBuffer.deinit();
var size = textBuffer.calculateLineBreaks(16, 256);
size[0] = 0;

View File

@ -275,10 +275,10 @@ pub const ItemDropManager = struct {
self.mutex.lock();
defer self.mutex.unlock();
if(self.size == maxCapacity) {
const json = itemStack.store(main.globalAllocator);
defer json.free(main.globalAllocator);
const json = itemStack.store(main.stackAllocator);
defer json.free(main.stackAllocator);
const string = json.toString(main.stackAllocator);
defer main.globalAllocator.free(string);
defer main.stackAllocator.free(string);
std.log.err("Item drop capacitiy limit reached. Failed to add itemStack: {s}", .{string});
if(itemStack.item) |item| {
item.deinit();

View File

@ -441,7 +441,7 @@ const TextureGenerator = struct {
var pixelMaterials: [16][16]PixelData = undefined;
for(0..16) |x| {
for(0..16) |y| {
pixelMaterials[x][y] = PixelData.init(main.globalAllocator);
pixelMaterials[x][y] = PixelData.init(main.stackAllocator);
}
}
@ -1331,19 +1331,19 @@ pub fn register(_: []const u8, texturePath: []const u8, replacementTexturePath:
}
pub fn registerRecipes(file: []const u8) void {
var shortcuts = std.StringHashMap(*BaseItem).init(main.globalAllocator.allocator);
var shortcuts = std.StringHashMap(*BaseItem).init(main.stackAllocator.allocator);
defer shortcuts.deinit();
defer {
var keyIterator = shortcuts.keyIterator();
while(keyIterator.next()) |key| {
main.globalAllocator.free(key.*);
main.stackAllocator.free(key.*);
}
}
var items = main.List(*BaseItem).init(main.globalAllocator);
var items = main.List(*BaseItem).init(main.stackAllocator);
defer items.deinit();
var itemAmounts = main.List(u16).init(main.globalAllocator);
var itemAmounts = main.List(u16).init(main.stackAllocator);
defer itemAmounts.deinit();
var string = main.List(u8).init(main.globalAllocator);
var string = main.List(u8).init(main.stackAllocator);
defer string.deinit();
var lines = std.mem.split(u8, file, "\n");
while(lines.next()) |line| {

View File

@ -97,7 +97,7 @@ const Socket = struct {
}
fn resolveIP(addr: []const u8) !u32 {
const list = try std.net.getAddressList(main.globalAllocator.allocator, addr, settings.defaultPort);
const list = try std.net.getAddressList(main.stackAllocator.allocator, addr, settings.defaultPort);
defer list.deinit();
return list.addrs[0].in.sa.addr;
}
@ -605,8 +605,8 @@ pub const Protocols = struct {
conn.handShakeState.store(data[0], .Monotonic);
switch(data[0]) {
stepUserData => {
const json = JsonElement.parseFromString(main.globalAllocator, data[1..]);
defer json.free(main.globalAllocator);
const json = JsonElement.parseFromString(main.stackAllocator, data[1..]);
defer json.free(main.stackAllocator);
const name = json.get([]const u8, "name", "unnamed");
const version = json.get([]const u8, "version", "unknown");
std.log.info("User {s} joined using version {s}.", .{name, version});
@ -617,7 +617,7 @@ pub const Protocols = struct {
defer main.stackAllocator.free(path);
var dir = try std.fs.cwd().openDir(path, .{.iterate = true});
defer dir.close();
var arrayList = main.List(u8).init(main.globalAllocator);
var arrayList = main.List(u8).init(main.stackAllocator);
defer arrayList.deinit();
arrayList.append(stepAssets);
try utils.Compression.pack(dir, arrayList.writer());
@ -627,13 +627,13 @@ pub const Protocols = struct {
// TODO:
conn.user.?.initPlayer(name);
const jsonObject = JsonElement.initObject(main.globalAllocator);
defer jsonObject.free(main.globalAllocator);
jsonObject.put("player", conn.user.?.player.save(main.globalAllocator));
const jsonObject = JsonElement.initObject(main.stackAllocator);
defer jsonObject.free(main.stackAllocator);
jsonObject.put("player", conn.user.?.player.save(main.stackAllocator));
// TODO:
// jsonObject.put("player_id", ((User)conn).player.id);
// jsonObject.put("blockPalette", Server.world.blockPalette.save());
const spawn = JsonElement.initObject(main.globalAllocator);
const spawn = JsonElement.initObject(main.stackAllocator);
spawn.put("x", main.server.world.?.spawn[0]);
spawn.put("y", main.server.world.?.spawn[1]);
spawn.put("z", main.server.world.?.spawn[2]);
@ -657,8 +657,8 @@ pub const Protocols = struct {
try utils.Compression.unpack(dir, data[1..]);
},
stepServerData => {
const json = JsonElement.parseFromString(main.globalAllocator, data[1..]);
defer json.free(main.globalAllocator);
const json = JsonElement.parseFromString(main.stackAllocator, data[1..]);
defer json.free(main.stackAllocator);
try conn.manager.world.?.finishHandshake(json);
conn.handShakeState.store(stepComplete, .Monotonic);
conn.handShakeWaiting.broadcast(); // Notify the waiting client thread.
@ -680,8 +680,8 @@ pub const Protocols = struct {
}
pub fn clientSide(conn: *Connection, name: []const u8) void {
const jsonObject = JsonElement.initObject(main.globalAllocator);
defer jsonObject.free(main.globalAllocator);
const jsonObject = JsonElement.initObject(main.stackAllocator);
defer jsonObject.free(main.stackAllocator);
jsonObject.putOwnedString("version", settings.version);
jsonObject.putOwnedString("name", name);
const prefix = [1]u8 {stepUserData};
@ -869,8 +869,8 @@ pub const Protocols = struct {
pub const entity = struct {
pub const id: u8 = 8;
fn receive(conn: *Connection, data: []const u8) !void {
const jsonArray = JsonElement.parseFromString(main.globalAllocator, data);
defer jsonArray.free(main.globalAllocator);
const jsonArray = JsonElement.parseFromString(main.stackAllocator, data);
defer jsonArray.free(main.stackAllocator);
var i: u32 = 0;
while(i < jsonArray.JsonArray.items.len) : (i += 1) {
const elem = jsonArray.JsonArray.items[i];
@ -1065,8 +1065,8 @@ pub const Protocols = struct {
// );
},
type_itemStackCollect => {
const json = JsonElement.parseFromString(main.globalAllocator, data[1..]);
defer json.free(main.globalAllocator);
const json = JsonElement.parseFromString(main.stackAllocator, data[1..]);
defer json.free(main.stackAllocator);
const item = items.Item.init(json) catch |err| {
std.log.err("Error {s} while collecting item {s}. Ignoring it.", .{@errorName(err), data[1..]});
return;
@ -1083,8 +1083,8 @@ pub const Protocols = struct {
},
type_timeAndBiome => {
if(conn.manager.world) |world| {
const json = JsonElement.parseFromString(main.globalAllocator, data[1..]);
defer json.free(main.globalAllocator);
const json = JsonElement.parseFromString(main.stackAllocator, data[1..]);
defer json.free(main.stackAllocator);
const expectedTime = json.get(i64, "time", 0);
var curTime = world.gameTime.load(.Monotonic);
if(@abs(curTime -% expectedTime) >= 1000) {
@ -1155,8 +1155,8 @@ pub const Protocols = struct {
pub fn sendInventory_full(conn: *Connection, inv: Inventory) void {
const json = inv.save(main.globalAllocator);
defer json.free(main.globalAllocator);
const json = inv.save(main.stackAllocator);
defer json.free(main.stackAllocator);
const string = json.toString(main.stackAllocator);
defer main.stackAllocator.free(string);
addHeaderAndSendImportant(conn, type_inventoryFull, string);
@ -1169,8 +1169,8 @@ pub const Protocols = struct {
}
pub fn itemStackDrop(conn: *Connection, stack: ItemStack, pos: Vec3d, dir: Vec3f, vel: f32) void {
const jsonObject = stack.store(main.globalAllocator);
defer jsonObject.free(main.globalAllocator);
const jsonObject = stack.store(main.stackAllocator);
defer jsonObject.free(main.stackAllocator);
jsonObject.put("x", pos[0]);
jsonObject.put("y", pos[1]);
jsonObject.put("z", pos[2]);
@ -1184,16 +1184,16 @@ pub const Protocols = struct {
}
pub fn itemStackCollect(conn: *Connection, stack: ItemStack) void {
const json = stack.store(main.globalAllocator);
defer json.free(main.globalAllocator);
const json = stack.store(main.stackAllocator);
defer json.free(main.stackAllocator);
const string = json.toString(main.stackAllocator);
defer main.stackAllocator.free(string);
addHeaderAndSendImportant(conn, type_itemStackCollect, string);
}
pub fn sendTimeAndBiome(conn: *Connection, world: *const main.server.ServerWorld) void {
const json = JsonElement.initObject(main.globalAllocator);
defer json.free(main.globalAllocator);
const json = JsonElement.initObject(main.stackAllocator);
defer json.free(main.stackAllocator);
json.put("time", world.gameTime);
const pos = conn.user.?.player.pos;
json.put("biome", (world.getBiome(@intFromFloat(pos[0]), @intFromFloat(pos[1]), @intFromFloat(pos[2]))).id);
@ -1483,9 +1483,9 @@ pub const Connection = struct {
self.mutex.lock();
defer self.mutex.unlock();
var runLengthEncodingStarts: main.List(u32) = main.List(u32).init(main.globalAllocator);
var runLengthEncodingStarts: main.List(u32) = main.List(u32).init(main.stackAllocator);
defer runLengthEncodingStarts.deinit();
var runLengthEncodingLengths: main.List(u32) = main.List(u32).init(main.globalAllocator);
var runLengthEncodingLengths: main.List(u32) = main.List(u32).init(main.stackAllocator);
defer runLengthEncodingLengths.deinit();
for(self.receivedPackets) |list| {

View File

@ -486,19 +486,19 @@ pub const MenuBackGround = struct {
var dir = try std.fs.cwd().makeOpenPath("assets/backgrounds", .{.iterate = true});
defer dir.close();
var walker = try dir.walk(main.globalAllocator.allocator);
var walker = try dir.walk(main.stackAllocator.allocator);
defer walker.deinit();
var fileList = main.List([]const u8).init(main.globalAllocator);
var fileList = main.List([]const u8).init(main.stackAllocator);
defer {
for(fileList.items) |fileName| {
main.globalAllocator.free(fileName);
main.stackAllocator.free(fileName);
}
fileList.deinit();
}
while(try walker.next()) |entry| {
if(entry.kind == .file and std.ascii.endsWithIgnoreCase(entry.basename, ".png")) {
fileList.append(main.globalAllocator.dupe(u8, entry.path));
fileList.append(main.stackAllocator.dupe(u8, entry.path));
}
}
if(fileList.items.len == 0) {

View File

@ -574,7 +574,7 @@ pub const ChunkMesh = struct {
fn initLight(self: *ChunkMesh) void {
self.mutex.lock();
var lightEmittingBlocks = main.List([3]u8).init(main.globalAllocator);
var lightEmittingBlocks = main.List([3]u8).init(main.stackAllocator);
defer lightEmittingBlocks.deinit();
var x: u8 = 0;
while(x < chunk.chunkSize): (x += 1) {

View File

@ -88,7 +88,7 @@ pub const ChannelChunk = struct {
var neighborLists: [6]main.ListUnmanaged(Entry) = .{.{}} ** 6;
defer {
for(&neighborLists) |*list| {
list.deinit(lightQueue.allocator);
list.deinit(main.stackAllocator);
}
}
@ -108,7 +108,7 @@ pub const ChannelChunk = struct {
}
if(result.value == 0) continue;
if(nx < 0 or nx >= chunk.chunkSize or ny < 0 or ny >= chunk.chunkSize or nz < 0 or nz >= chunk.chunkSize) {
neighborLists[neighbor].append(lightQueue.allocator, result);
neighborLists[neighbor].append(main.stackAllocator, result);
continue;
}
const neighborIndex = chunk.getIndex(nx, ny, nz);
@ -136,7 +136,7 @@ pub const ChannelChunk = struct {
var constructiveList: main.ListUnmanaged(PositionEntry) = .{};
defer {
for(&neighborLists) |*list| {
list.deinit(lightQueue.allocator);
list.deinit(main.stackAllocator);
}
}
var isFirstIteration: bool = isFirstBlock;
@ -146,7 +146,7 @@ pub const ChannelChunk = struct {
const index = chunk.getIndex(entry.x, entry.y, entry.z);
if(entry.value != self.data[index].load(.Unordered)) {
if(self.data[index].load(.Unordered) != 0) {
constructiveList.append(lightQueue.allocator, .{.x = entry.x, .y = entry.y, .z = entry.z});
constructiveList.append(main.stackAllocator, .{.x = entry.x, .y = entry.y, .z = entry.z});
}
continue;
}
@ -163,7 +163,7 @@ pub const ChannelChunk = struct {
result.value -|= 8*|@as(u8, @intCast(self.ch.pos.voxelSize));
}
if(nx < 0 or nx >= chunk.chunkSize or ny < 0 or ny >= chunk.chunkSize or nz < 0 or nz >= chunk.chunkSize) {
neighborLists[neighbor].append(lightQueue.allocator, result);
neighborLists[neighbor].append(main.stackAllocator, result);
continue;
}
const neighborIndex = chunk.getIndex(nx, ny, nz);
@ -181,7 +181,7 @@ pub const ChannelChunk = struct {
for(0..6) |neighbor| {
if(neighborLists[neighbor].items.len == 0) continue;
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.ch.pos, self.ch.pos.voxelSize, @intCast(neighbor)) orelse continue;
constructiveEntries.append(lightQueue.allocator, .{
constructiveEntries.append(main.stackAllocator, .{
.mesh = neighborMesh,
.entries = neighborMesh.lightingData[@intFromEnum(self.channel)].propagateDestructiveFromNeighbor(lightQueue, neighborLists[neighbor].items, constructiveEntries),
});
@ -217,12 +217,7 @@ pub const ChannelChunk = struct {
}
pub fn propagateLights(self: *ChannelChunk, lights: []const [3]u8, comptime checkNeighbors: bool) void {
const buf = main.stackAllocator.alloc(u8, 1 << 16);
defer main.stackAllocator.free(buf);
var bufferFallback = main.utils.BufferFallbackAllocator.init(buf, main.globalAllocator);
var arena = main.utils.NeverFailingArenaAllocator.init(bufferFallback.allocator());
defer arena.deinit();
var lightQueue = main.utils.CircularBufferQueue(Entry).init(arena.allocator(), 1 << 10);
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
defer lightQueue.deinit();
for(lights) |pos| {
const index = chunk.getIndex(pos[0], pos[1], pos[2]);
@ -280,20 +275,15 @@ pub const ChannelChunk = struct {
}
pub fn propagateLightsDestructive(self: *ChannelChunk, lights: []const [3]u8) void {
const buf = main.stackAllocator.alloc(u8, 1 << 16);
defer main.stackAllocator.free(buf);
var bufferFallback = main.utils.BufferFallbackAllocator.init(buf, main.globalAllocator);
var arena = main.utils.NeverFailingArenaAllocator.init(bufferFallback.allocator());
defer arena.deinit();
var lightQueue = main.utils.CircularBufferQueue(Entry).init(arena.allocator(), 1 << 10);
var lightQueue = main.utils.CircularBufferQueue(Entry).init(main.stackAllocator, 1 << 12);
defer lightQueue.deinit();
for(lights) |pos| {
const index = chunk.getIndex(pos[0], pos[1], pos[2]);
lightQueue.enqueue(.{.x = @intCast(pos[0]), .y = @intCast(pos[1]), .z = @intCast(pos[2]), .value = self.data[index].load(.Unordered), .sourceDir = 6});
}
var constructiveEntries: main.ListUnmanaged(ChunkEntries) = .{};
defer constructiveEntries.deinit(arena.allocator());
constructiveEntries.append(arena.allocator(), .{
defer constructiveEntries.deinit(main.stackAllocator);
constructiveEntries.append(main.stackAllocator, .{
.mesh = null,
.entries = self.propagateDestructive(&lightQueue, &constructiveEntries, true),
});
@ -301,7 +291,7 @@ pub const ChannelChunk = struct {
const mesh = entries.mesh;
defer if(mesh) |_mesh| _mesh.decreaseRefCount();
var entryList = entries.entries;
defer entryList.deinit(arena.allocator());
defer entryList.deinit(main.stackAllocator);
const channelChunk = if(mesh) |_mesh| _mesh.lightingData[@intFromEnum(self.channel)] else self;
for(entryList.items) |entry| {
const index = chunk.getIndex(entry.x, entry.y, entry.z);

View File

@ -531,9 +531,9 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
network.Protocols.genericUpdate.sendRenderDistance(conn, renderDistance);
}
var meshRequests = main.List(chunk.ChunkPosition).init(main.globalAllocator);
var meshRequests = main.List(chunk.ChunkPosition).init(main.stackAllocator);
defer meshRequests.deinit();
var mapRequests = main.List(LightMap.MapFragmentPosition).init(main.globalAllocator);
var mapRequests = main.List(LightMap.MapFragmentPosition).init(main.stackAllocator);
defer mapRequests.deinit();
const olderPx = lastPx;
@ -568,7 +568,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
};
// TODO: Is there a way to combine this with minecraft's approach?
var searchList = std.PriorityQueue(OcclusionData, void, OcclusionData.compare).init(main.globalAllocator.allocator, {});
var searchList = std.PriorityQueue(OcclusionData, void, OcclusionData.compare).init(main.stackAllocator.allocator, {});
defer searchList.deinit();
{
var firstPos = chunk.ChunkPosition{
@ -601,7 +601,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V
firstPos.voxelSize *= 2;
}
}
var nodeList = main.List(*ChunkMeshNode).init(main.globalAllocator);
var nodeList = main.List(*ChunkMeshNode).init(main.stackAllocator);
defer nodeList.deinit();
const projRotMat = game.projectionMatrix.mul(game.camera.viewMatrix);
while(searchList.removeOrNull()) |data| {

View File

@ -146,10 +146,10 @@ pub const Biome = struct {
const structures = json.getChild("structures");
var vegetation = main.ListUnmanaged(StructureModel){};
defer vegetation.deinit(main.globalAllocator);
defer vegetation.deinit(main.stackAllocator);
for(structures.toSlice()) |elem| {
if(StructureModel.initModel(elem)) |model| {
vegetation.append(main.globalAllocator, model);
vegetation.append(main.stackAllocator, model);
}
}
self.vegetationModels = main.globalAllocator.dupe(StructureModel, vegetation.items);

View File

@ -30,7 +30,7 @@ pub fn deinit() void {
pub fn generateMapFragment(map: *ClimateMapFragment, worldSeed: u64) void {
var seed: u64 = worldSeed;
const generator = GenerationStructure.init(main.globalAllocator, map.pos.wx, map.pos.wz, ClimateMapFragment.mapSize, ClimateMapFragment.mapSize, terrain.biomes.byTypeBiomes, seed);
const generator = GenerationStructure.init(main.stackAllocator, map.pos.wx, map.pos.wz, ClimateMapFragment.mapSize, ClimateMapFragment.mapSize, terrain.biomes.byTypeBiomes, seed);
defer generator.deinit(main.stackAllocator);
generator.toMap(map, ClimateMapFragment.mapSize, ClimateMapFragment.mapSize, worldSeed);
@ -327,7 +327,7 @@ const GenerationStructure = struct {
}
// Add some sub-biomes:
var extraBiomes = main.List(BiomePoint).init(main.globalAllocator);
var extraBiomes = main.List(BiomePoint).init(main.stackAllocator);
defer extraBiomes.deinit();
for(self.chunks.mem) |chunk| {
for(chunk.biomesSortedByX) |biome| {

View File

@ -269,8 +269,8 @@ const WorldIO = struct {
/// Load the seed, which is needed before custom item and ore generation.
pub fn loadWorldSeed(self: WorldIO) !u64 {
const worldData: JsonElement = try self.dir.readToJson(main.globalAllocator, "world.dat");
defer worldData.free(main.globalAllocator);
const worldData: JsonElement = try self.dir.readToJson(main.stackAllocator, "world.dat");
defer worldData.free(main.stackAllocator);
if(worldData.get(u32, "version", 0) != worldDataVersion) {
std.log.err("Cannot read world file version {}. Expected version {}.", .{worldData.get(u32, "version", 0), worldDataVersion});
return error.OldWorld;
@ -279,8 +279,8 @@ const WorldIO = struct {
}
pub fn loadWorldData(self: WorldIO) !void {
const worldData: JsonElement = try self.dir.readToJson(main.globalAllocator, "world.dat");
defer worldData.free(main.globalAllocator);
const worldData: JsonElement = try self.dir.readToJson(main.stackAllocator, "world.dat");
defer worldData.free(main.stackAllocator);
const entityJson = worldData.getChild("entities");
_ = entityJson;
@ -300,15 +300,15 @@ const WorldIO = struct {
}
pub fn saveWorldData(self: WorldIO) !void {
const worldData: JsonElement = JsonElement.initObject(main.globalAllocator);
defer worldData.free(main.globalAllocator);
const worldData: JsonElement = JsonElement.initObject(main.stackAllocator);
defer worldData.free(main.stackAllocator);
worldData.put("version", worldDataVersion);
worldData.put("seed", self.world.seed);
worldData.put("doGameTimeCycle", self.world.doGameTimeCycle);
worldData.put("gameTime", self.world.gameTime);
// TODO:
// worldData.put("entityCount", world.getEntities().length);
const spawnData = JsonElement.initObject(main.globalAllocator);
const spawnData = JsonElement.initObject(main.stackAllocator);
spawnData.put("x", self.world.spawn[0]);
spawnData.put("y", self.world.spawn[1]);
spawnData.put("z", self.world.spawn[2]);
@ -366,7 +366,7 @@ pub const ServerWorld = struct {
self.itemDropManager.init(main.globalAllocator, self, self.gravity);
errdefer self.itemDropManager.deinit();
var loadArena = main.utils.NeverFailingArenaAllocator.init(main.globalAllocator);
var loadArena = main.utils.NeverFailingArenaAllocator.init(main.stackAllocator);
defer loadArena.deinit();
const arenaAllocator = loadArena.allocator();
var buf: [32768]u8 = undefined;
@ -438,8 +438,8 @@ pub const ServerWorld = struct {
pub fn findPlayer(self: *ServerWorld, user: *User) void {
var buf: [1024]u8 = undefined;
const playerData = files.readToJson(main.globalAllocator, std.fmt.bufPrint(&buf, "saves/{s}/player/{s}.json", .{self.name, user.name}) catch "") catch .JsonNull; // TODO: Utils.escapeFolderName(user.name)
defer playerData.free(main.globalAllocator);
const playerData = files.readToJson(main.stackAllocator, std.fmt.bufPrint(&buf, "saves/{s}/player/{s}.json", .{self.name, user.name}) catch "") catch .JsonNull; // TODO: Utils.escapeFolderName(user.name)
defer playerData.free(main.stackAllocator);
const player = &user.player;
if(playerData == .JsonNull) {
// Generate a new player:
@ -473,8 +473,8 @@ pub const ServerWorld = struct {
// savePlayers();
// chunkManager.forceSave();
// ChunkIO.save();
const itemDropJson = self.itemDropManager.store(main.globalAllocator);
defer itemDropJson.free(main.globalAllocator);
const itemDropJson = self.itemDropManager.store(main.stackAllocator);
defer itemDropJson.free(main.stackAllocator);
var buf: [32768]u8 = undefined;
try files.writeJson(try std.fmt.bufPrint(&buf, "saves/{s}/items.json", .{self.name}), itemDropJson);
}

View File

@ -41,13 +41,13 @@ pub var developerAutoEnterWorld: []const u8 = "";
pub fn init() void {
const json: JsonElement = main.files.readToJson(main.globalAllocator, "settings.json") catch |err| {
const json: JsonElement = main.files.readToJson(main.stackAllocator, "settings.json") catch |err| {
if(err != error.FileNotFound) {
std.log.err("Could not read settings file: {s}", .{@errorName(err)});
}
return;
};
defer json.free(main.globalAllocator);
defer json.free(main.stackAllocator);
inline for(@typeInfo(@This()).Struct.decls) |decl| {
const is_const = @typeInfo(@TypeOf(&@field(@This(), decl.name))).Pointer.is_const; // Sadly there is no direct way to check if a declaration is const.
@ -78,8 +78,8 @@ pub fn init() void {
}
pub fn deinit() void {
const jsonObject = JsonElement.initObject(main.globalAllocator);
defer jsonObject.free(main.globalAllocator);
const jsonObject = JsonElement.initObject(main.stackAllocator);
defer jsonObject.free(main.stackAllocator);
inline for(@typeInfo(@This()).Struct.decls) |decl| {
const is_const = @typeInfo(@TypeOf(&@field(@This(), decl.name))).Pointer.is_const; // Sadly there is no direct way to check if a declaration is const.
@ -104,9 +104,9 @@ pub fn deinit() void {
}
// keyboard settings:
const keyboard = JsonElement.initObject(main.globalAllocator);
const keyboard = JsonElement.initObject(main.stackAllocator);
for(&main.KeyBoard.keys) |key| {
const keyJson = JsonElement.initObject(main.globalAllocator);
const keyJson = JsonElement.initObject(main.stackAllocator);
keyJson.put("key", key.key);
keyJson.put("mouseButton", key.mouseButton);
keyJson.put("scancode", key.scancode);

View File

@ -8,7 +8,7 @@ const main = @import("main.zig");
pub const Compression = struct {
pub fn deflate(allocator: NeverFailingAllocator, data: []const u8) []u8 {
var result = main.List(u8).init(allocator);
var comp = std.compress.deflate.compressor(main.globalAllocator.allocator, result.writer(), .{.level = .default_compression}) catch unreachable;
var comp = std.compress.deflate.compressor(main.stackAllocator.allocator, result.writer(), .{.level = .default_compression}) catch unreachable;
_ = comp.write(data) catch unreachable;
comp.close() catch unreachable;
comp.deinit();
@ -25,9 +25,9 @@ pub const Compression = struct {
}
pub fn pack(sourceDir: std.fs.Dir, writer: anytype) !void {
var comp = try std.compress.deflate.compressor(main.globalAllocator.allocator, writer, .{.level = .default_compression});
var comp = try std.compress.deflate.compressor(main.stackAllocator.allocator, writer, .{.level = .default_compression});
defer comp.deinit();
var walker = try sourceDir.walk(main.globalAllocator.allocator);
var walker = try sourceDir.walk(main.stackAllocator.allocator);
defer walker.deinit();
while(try walker.next()) |entry| {
@ -61,7 +61,7 @@ pub const Compression = struct {
pub fn unpack(outDir: std.fs.Dir, input: []const u8) !void {
var stream = std.io.fixedBufferStream(input);
var decomp = try std.compress.deflate.decompressor(main.globalAllocator.allocator, stream.reader(), null);
var decomp = try std.compress.deflate.decompressor(main.stackAllocator.allocator, stream.reader(), null);
defer decomp.deinit();
const reader = decomp.reader();
const _data = try reader.readAllAlloc(main.stackAllocator.allocator, std.math.maxInt(usize));
@ -373,26 +373,23 @@ pub fn CircularBufferQueue(comptime T: type) type {
/// Allows for stack-like allocations in a fast and safe way.
/// It is safe in the sense that a regular allocator will be used when the buffer is full.
pub const StackAllocator = struct {
const Allocation = struct{start: u32, len: u32};
const AllocationTrailer = packed struct{wasFreed: bool, previousAllocationTrailer: u31};
backingAllocator: NeverFailingAllocator,
buffer: []align(4096) u8,
allocationList: main.List(Allocation),
index: usize,
pub fn init(backingAllocator: NeverFailingAllocator, size: u32) StackAllocator {
pub fn init(backingAllocator: NeverFailingAllocator, size: u31) StackAllocator {
return .{
.backingAllocator = backingAllocator,
.buffer = backingAllocator.alignedAlloc(u8, 4096, size),
.allocationList = main.List(Allocation).init(backingAllocator),
.index = 0,
};
}
pub fn deinit(self: StackAllocator) void {
if(self.allocationList.items.len != 0) {
if(self.index != 0) {
std.log.err("Memory leak in Stack Allocator", .{});
}
self.allocationList.deinit();
self.backingAllocator.free(self.buffer);
}
@ -423,6 +420,16 @@ pub const StackAllocator = struct {
return compare - bufferStart;
}
fn getTrueAllocationEnd(start: usize, len: usize) usize {
const trailerStart = std.mem.alignForward(usize, start + len, @alignOf(AllocationTrailer));
return trailerStart + @sizeOf(AllocationTrailer);
}
fn getTrailerBefore(self: *StackAllocator, end: usize) *AllocationTrailer {
const trailerStart = end - @sizeOf(AllocationTrailer);
return @ptrCast(@alignCast(self.buffer[trailerStart..].ptr));
}
/// Attempt to allocate exactly `len` bytes aligned to `1 << ptr_align`.
///
/// `ret_addr` is optionally provided as the first return address of the
@ -430,11 +437,12 @@ pub const StackAllocator = struct {
/// has been provided.
fn alloc(ctx: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8 {
const self: *StackAllocator = @ptrCast(@alignCast(ctx));
if(len >= self.buffer.len) return self.backingAllocator.rawAlloc(len, ptr_align, ret_addr);
const start = std.mem.alignForward(usize, self.index, @as(usize, 1) << @intCast(ptr_align));
if(start + len >= self.buffer.len) return self.backingAllocator.rawAlloc(len, ptr_align, ret_addr);
self.allocationList.append(.{.start = @intCast(start), .len = @intCast(len)});
self.index = start + len;
const end = getTrueAllocationEnd(start, len);
if(end >= self.buffer.len) return self.backingAllocator.rawAlloc(len, ptr_align, ret_addr);
const trailer = self.getTrailerBefore(end);
trailer.* = .{.wasFreed = false, .previousAllocationTrailer = @intCast(self.index)};
self.index = end;
return self.buffer.ptr + start;
}
@ -456,16 +464,18 @@ pub const StackAllocator = struct {
fn resize(ctx: *anyopaque, buf: []u8, buf_align: u8, new_len: usize, ret_addr: usize) bool {
const self: *StackAllocator = @ptrCast(@alignCast(ctx));
if(self.isInsideBuffer(buf)) {
const top = &self.allocationList.items[self.allocationList.items.len - 1];
std.debug.assert(top.start == self.indexInBuffer(buf)); // Can only resize the top element.
std.debug.assert(top.len == buf.len);
std.debug.assert(self.index >= top.start + top.len);
if(top.start + new_len >= self.buffer.len) {
return false;
}
self.index -= top.len;
self.index += new_len;
top.len = @intCast(new_len);
const start = self.indexInBuffer(buf);
const end = getTrueAllocationEnd(start, buf.len);
if(end != self.index) return false;
const newEnd = getTrueAllocationEnd(start, new_len);
if(newEnd >= self.buffer.len) return false;
const trailer = self.getTrailerBefore(end);
std.debug.assert(!trailer.wasFreed);
const newTrailer = self.getTrailerBefore(newEnd);
newTrailer.* = .{.wasFreed = false, .previousAllocationTrailer = trailer.previousAllocationTrailer};
self.index = newEnd;
return true;
} else {
return self.backingAllocator.rawResize(buf, buf_align, new_len, ret_addr);
@ -486,11 +496,24 @@ pub const StackAllocator = struct {
fn free(ctx: *anyopaque, buf: []u8, buf_align: u8, ret_addr: usize) void {
const self: *StackAllocator = @ptrCast(@alignCast(ctx));
if(self.isInsideBuffer(buf)) {
const top = self.allocationList.pop();
std.debug.assert(top.start == self.indexInBuffer(buf)); // Can only free the top element.
std.debug.assert(top.len == buf.len);
std.debug.assert(self.index >= top.start + top.len);
self.index = top.start;
const start = self.indexInBuffer(buf);
const end = getTrueAllocationEnd(start, buf.len);
const trailer = self.getTrailerBefore(end);
std.debug.assert(!trailer.wasFreed); // Double Free
if(end == self.index) {
self.index = trailer.previousAllocationTrailer;
if(self.index != 0) {
var previousTrailer = self.getTrailerBefore(trailer.previousAllocationTrailer);
while(previousTrailer.wasFreed) {
self.index = previousTrailer.previousAllocationTrailer;
if(self.index == 0) break;
previousTrailer = self.getTrailerBefore(previousTrailer.previousAllocationTrailer);
}
}
} else {
trailer.wasFreed = true;
}
} else {
self.backingAllocator.rawFree(buf, buf_align, ret_addr);
}