add nil ids to slotmap
This commit is contained in:
parent
69ae88c37d
commit
3cfd12d8ba
@ -62,7 +62,7 @@ const Tilesheet = struct {
|
||||
pub fn init(gpa: Allocator, image: Gfx.ImageData, width: u32, height: u32, tile_size: Vec2) !Tilesheet {
|
||||
const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height);
|
||||
errdefer gpa.free(sprites);
|
||||
@memset(sprites, Gfx.getNilSprite());
|
||||
@memset(sprites, .nil);
|
||||
|
||||
return Tilesheet{
|
||||
.sprites = sprites,
|
||||
@ -82,11 +82,11 @@ const Tilesheet = struct {
|
||||
pub fn get(self: Tilesheet, x: u32, y: u32) Gfx.Sprite.Id {
|
||||
if (x >= self.width or y >= self.height) {
|
||||
log.warn("Attempt to get tile which is out of bounds", .{});
|
||||
return Gfx.getNilSprite();
|
||||
return .nil;
|
||||
}
|
||||
|
||||
const sprite_index = y * self.width + x;
|
||||
if (self.sprites[sprite_index] == Gfx.getNilSprite()) {
|
||||
if (self.sprites[sprite_index] == Gfx.Sprite.Id.nil) {
|
||||
const sprite = Gfx.initSprite(.{ .padding = 1 });
|
||||
Gfx.setSprite(sprite, .{
|
||||
.image = self.image,
|
||||
|
||||
82
src/platform/audio.zig
Normal file
82
src/platform/audio.zig
Normal file
@ -0,0 +1,82 @@
|
||||
const std = @import("std");
|
||||
const log = std.log.scoped(.audio);
|
||||
|
||||
const sokol = @import("sokol");
|
||||
const sapp = sokol.app;
|
||||
const saudio = sokol.audio;
|
||||
|
||||
const tracy = @import("tracy");
|
||||
|
||||
const SlotMapType = @import("./slot_map.zig").SlotMapType;
|
||||
|
||||
const State = struct {
|
||||
sounds: Sound.SlotMap
|
||||
};
|
||||
|
||||
var g_state: State = undefined;
|
||||
|
||||
pub const InitOptions = struct {
|
||||
logger: saudio.Logger = .{},
|
||||
buffer_frames: u32 = 2048,
|
||||
max_sounds: usize = 128,
|
||||
};
|
||||
|
||||
pub const Sound = struct {
|
||||
cb: Callback,
|
||||
userdata: *anyopaque,
|
||||
volume: f32 = 1,
|
||||
|
||||
pub const Callback = *const fn(sound: *Sound, samples: *std.ArrayList(f32)) void;
|
||||
|
||||
const SlotMap = SlotMapType(u8, u16, Sound);
|
||||
pub const Id = SlotMap.Id;
|
||||
};
|
||||
|
||||
pub fn init(gpa: std.mem.Allocator, opts: InitOptions) !void {
|
||||
const channels = 1; // TODO: Stereo audio
|
||||
const self = &g_state;
|
||||
|
||||
const sounds_buffer = try gpa.alloc(Sound.SlotMap.Slot, opts.max_sounds);
|
||||
errdefer gpa.free(sounds_buffer);
|
||||
self.* = State{
|
||||
.sounds = .init(sounds_buffer)
|
||||
};
|
||||
|
||||
saudio.setup(.{
|
||||
.stream_userdata_cb = sokolStreamCallback,
|
||||
.logger = opts.logger,
|
||||
.num_channels = channels,
|
||||
.buffer_frames = @intCast(opts.buffer_frames),
|
||||
});
|
||||
|
||||
const sample_rate: f32 = @floatFromInt(saudio.sampleRate());
|
||||
const max_latency_s: f32 = @as(f32, @floatFromInt(opts.buffer_frames)) / sample_rate;
|
||||
const max_latency_ns: i64 = @intFromFloat(max_latency_s * std.time.ns_per_s);
|
||||
|
||||
log.debug("Init:", .{});
|
||||
log.debug("- sample_rate: {}", .{saudio.sampleRate()});
|
||||
log.debug("- channels: {}", .{saudio.channels()});
|
||||
log.debug("- buffer_frames: {}", .{saudio.bufferFrames()});
|
||||
log.debug("- max_latency: {f}", .{std.Io.Duration.fromNanoseconds(max_latency_ns)});
|
||||
}
|
||||
|
||||
pub fn deinit(gpa: std.mem.Allocator) void {
|
||||
var self = &g_state;
|
||||
|
||||
saudio.shutdown();
|
||||
|
||||
gpa.free(self.sounds.slots.allocatedSlice());
|
||||
}
|
||||
|
||||
pub fn addSound() Sound.Id {
|
||||
}
|
||||
|
||||
pub fn removeSound() void {
|
||||
}
|
||||
|
||||
fn sokolStreamCallback(buffer: [*c]f32, num_frames: i32, num_channels: i32, user_data: ?*anyopaque) callconv(.c) void {
|
||||
_ = buffer; // autofix
|
||||
_ = num_frames; // autofix
|
||||
_ = num_channels; // autofix
|
||||
_ = user_data; // autofix
|
||||
}
|
||||
@ -49,19 +49,15 @@ const State = struct {
|
||||
|
||||
textures_buffer: [Texture.max_textures]Texture.SlotMap.Slot,
|
||||
textures: Texture.SlotMap,
|
||||
nil_texture: Texture.Id,
|
||||
|
||||
spritesheets_buffer: [Spritesheet.max_spritesheets]Spritesheet.SlotMap.Slot,
|
||||
spritesheets: Spritesheet.SlotMap,
|
||||
nil_spritesheet: Spritesheet.Id,
|
||||
|
||||
sprites_buffer: [Sprite.max_sprites]Sprite.SlotMap.Slot,
|
||||
sprites: Sprite.SlotMap,
|
||||
nil_sprite: Sprite.Id,
|
||||
|
||||
fonts_buffer: [Font.max_fonts]Font.SlotMap.Slot,
|
||||
fonts: Font.SlotMap,
|
||||
nil_font: Font.Id,
|
||||
};
|
||||
|
||||
var g_state: State = undefined;
|
||||
@ -173,67 +169,17 @@ pub fn init(gpa: std.mem.Allocator, logger: sg.Logger) !void {
|
||||
|
||||
.textures_buffer = undefined,
|
||||
.textures = .init(&self.textures_buffer),
|
||||
.nil_texture = undefined,
|
||||
|
||||
.sprites_buffer = undefined,
|
||||
.sprites = .init(&self.sprites_buffer),
|
||||
.nil_sprite = undefined,
|
||||
|
||||
.spritesheets_buffer = undefined,
|
||||
.spritesheets = .init(&self.spritesheets_buffer),
|
||||
.nil_spritesheet = undefined,
|
||||
|
||||
.fonts_buffer = undefined,
|
||||
.fonts = .init(&self.fonts_buffer),
|
||||
.nil_font = undefined,
|
||||
};
|
||||
|
||||
self.nil_texture = self.textures.insertAssumeCapacity();
|
||||
{
|
||||
const nil_texture = self.textures.getAssumeExists(self.nil_texture);
|
||||
nil_texture.* = Texture{
|
||||
.dynamic = false,
|
||||
.updated_at = null,
|
||||
.image = .{ .id = sg.invalid_id },
|
||||
.view = .{ .id = sg.invalid_id },
|
||||
};
|
||||
}
|
||||
|
||||
self.nil_spritesheet = self.spritesheets.insertAssumeCapacity();
|
||||
{
|
||||
const nil_spritesheet = self.spritesheets.getAssumeExists(self.nil_spritesheet);
|
||||
nil_spritesheet.* = Spritesheet{
|
||||
.texture = self.nil_texture,
|
||||
.format = .rgba8,
|
||||
.size = .init(0, 0),
|
||||
.needs_repack = false,
|
||||
.needs_texture_rebuild = false,
|
||||
.nodes = undefined,
|
||||
.packer = null,
|
||||
};
|
||||
}
|
||||
|
||||
self.nil_sprite = self.sprites.insertAssumeCapacity();
|
||||
{
|
||||
const nil_sprite = self.sprites.getAssumeExists(self.nil_sprite);
|
||||
nil_sprite.* = Sprite{
|
||||
.spritesheet = self.nil_spritesheet,
|
||||
.data = .none,
|
||||
.position = null,
|
||||
.padding = 0
|
||||
};
|
||||
}
|
||||
|
||||
self.nil_font = self.fonts.insertAssumeCapacity();
|
||||
{
|
||||
const nil_font = self.fonts.getAssumeExists(self.nil_font);
|
||||
nil_font.* = Font{
|
||||
.spritesheet = self.nil_spritesheet,
|
||||
.stb = null,
|
||||
.cache = .init(),
|
||||
};
|
||||
}
|
||||
|
||||
self.default_spritesheet = initSpritesheet(.{});
|
||||
self.default_font_spritesheet = initSpritesheet(.{ .format = .r8 });
|
||||
|
||||
@ -612,13 +558,13 @@ pub fn initTexture(opts: TextureOptions) Texture.Id {
|
||||
const self = &g_state;
|
||||
const id = self.textures.insertUndefined() catch {
|
||||
log.warn("Failed to create texture, limit reached! limit: {}", .{self.textures.slots.capacity});
|
||||
return self.nil_texture;
|
||||
return .nil;
|
||||
};
|
||||
|
||||
const view = sg.allocView();
|
||||
if (sg.queryViewState(view) != .ALLOC) {
|
||||
log.warn("Failed to alloc texture view", .{});
|
||||
return self.nil_texture;
|
||||
return .nil;
|
||||
}
|
||||
|
||||
const texture = self.textures.getAssumeExists(id);
|
||||
@ -665,10 +611,6 @@ pub fn deinitTexture(id: Texture.Id) void {
|
||||
|
||||
pub fn setTexture(id: Texture.Id, texture_data: ImageData) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
const texture = self.textures.get(id) orelse {
|
||||
log.warn("Attempt to set texture that doesn't exist: {}", .{id});
|
||||
return;
|
||||
@ -808,8 +750,7 @@ pub fn draw(opts: DrawOptions) void {
|
||||
var quad = opts.quad;
|
||||
|
||||
var view: sg.View = .{ .id = sg.invalid_id };
|
||||
if (opts.texture != self.nil_texture and self.textures.exists(opts.texture)) {
|
||||
const texture = self.textures.getAssumeExists(opts.texture);
|
||||
if (self.textures.get(opts.texture)) |texture| {
|
||||
view = texture.view;
|
||||
}
|
||||
|
||||
@ -862,17 +803,11 @@ const SpriteOptions = struct {
|
||||
padding: u32 = 0,
|
||||
};
|
||||
|
||||
// TODO: I don't like this getter, maybe nil_sprite should be a public global variable.
|
||||
pub fn getNilSprite() Sprite.Id {
|
||||
const self = &g_state;
|
||||
return self.nil_sprite;
|
||||
}
|
||||
|
||||
pub fn initSprite(opts: SpriteOptions) Sprite.Id {
|
||||
const self = &g_state;
|
||||
const id = self.sprites.insertUndefined() catch {
|
||||
log.warn("Failed to create sprite, limit reached! limit: {}", .{self.sprites.slots.capacity});
|
||||
return self.nil_sprite;
|
||||
return .nil;
|
||||
};
|
||||
|
||||
const sprite = self.sprites.getAssumeExists(id);
|
||||
@ -888,10 +823,6 @@ pub fn initSprite(opts: SpriteOptions) Sprite.Id {
|
||||
|
||||
pub fn deinitSprite(id: Sprite.Id) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_sprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.sprites.exists(id)) {
|
||||
const sprite = self.sprites.getAssumeExists(id);
|
||||
if (sprite.data) |data| {
|
||||
@ -912,10 +843,6 @@ const SetSpriteOptions = struct {
|
||||
|
||||
pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_sprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sprite = self.sprites.get(id) orelse {
|
||||
log.warn("Attempt to set sprite that doesn't exist: {}", .{id});
|
||||
return;
|
||||
@ -1048,10 +975,6 @@ fn repackSpritesheet(id: Spritesheet.Id) void {
|
||||
|
||||
fn repackSpritesheetIfNeeded(id: Spritesheet.Id) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_spritesheet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const spritesheet = self.spritesheets.get(id) orelse {
|
||||
log.warn("Attempt to pack spritesheet that doesn't exist: {f}", .{id});
|
||||
return;
|
||||
@ -1066,10 +989,6 @@ fn repackSpritesheetIfNeeded(id: Spritesheet.Id) void {
|
||||
|
||||
fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_spritesheet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const spritesheet = self.spritesheets.get(id) orelse return;
|
||||
if (!spritesheet.needs_texture_rebuild) {
|
||||
return;
|
||||
@ -1156,10 +1075,6 @@ fn ensureSpritePacked(id: Sprite.Id) bool {
|
||||
|
||||
pub fn getSpriteUVRect(id: Sprite.Id) ?Rect {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_sprite) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sprite = self.sprites.get(id) orelse return null;
|
||||
const sprite_data = sprite.data orelse return null;
|
||||
|
||||
@ -1195,7 +1110,6 @@ pub fn drawSpriteQuad(id: Sprite.Id, points: Quad, color: Color) void {
|
||||
quad.vertices[3].position = points.positions[3];
|
||||
|
||||
var texture: ?Texture.Id = null;
|
||||
if (id != self.nil_sprite) {
|
||||
if (getSpriteUVRect(id)) |sprite_uv| {
|
||||
quad.setUVRect(sprite_uv);
|
||||
|
||||
@ -1203,10 +1117,9 @@ pub fn drawSpriteQuad(id: Sprite.Id, points: Quad, color: Color) void {
|
||||
const spritesheet = self.spritesheets.getAssumeExists(sprite.spritesheet);
|
||||
texture = spritesheet.texture;
|
||||
}
|
||||
}
|
||||
|
||||
draw(.{
|
||||
.texture = texture orelse self.nil_texture,
|
||||
.texture = texture orelse .nil,
|
||||
.quad = quad
|
||||
});
|
||||
}
|
||||
@ -1224,7 +1137,7 @@ pub fn initSpritesheet(opts: SpriteSheetOptions) Spritesheet.Id {
|
||||
const self = &g_state;
|
||||
const id = self.spritesheets.insertUndefined() catch {
|
||||
log.warn("Failed to create spritesheet, limit reached! limit: {}", .{self.spritesheets.slots.capacity});
|
||||
return self.nil_spritesheet;
|
||||
return .nil;
|
||||
};
|
||||
|
||||
const spritesheet = self.spritesheets.getAssumeExists(id);
|
||||
@ -1243,10 +1156,6 @@ pub fn initSpritesheet(opts: SpriteSheetOptions) Spritesheet.Id {
|
||||
|
||||
pub fn deinitSpritesheet(id: Spritesheet.Id) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_spritesheet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.spritesheets.get(id)) {
|
||||
const spritesheet = self.spritesheets.getAssumeExists(id);
|
||||
deinitTexture(spritesheet.texture);
|
||||
@ -1258,7 +1167,7 @@ pub fn initFont() Font.Id {
|
||||
const self = &g_state;
|
||||
const id = self.fonts.insertUndefined() catch {
|
||||
log.warn("Failed to create font, limit reached! limit: {}", .{self.fonts.slots.capacity});
|
||||
return self.nil_font;
|
||||
return .nil;
|
||||
};
|
||||
|
||||
const font = self.fonts.getAssumeExists(id);
|
||||
@ -1273,10 +1182,6 @@ pub fn initFont() Font.Id {
|
||||
|
||||
pub fn deinitFont(id: Font.Id) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_font) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.fonts.get(id)) |font| {
|
||||
font.cache.deinit();
|
||||
self.fonts.removeAssumeExists(id);
|
||||
@ -1285,10 +1190,6 @@ pub fn deinitFont(id: Font.Id) void {
|
||||
|
||||
pub fn setFont(id: Font.Id, ttf_data: [:0]const u8) void {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_font) {
|
||||
return;
|
||||
}
|
||||
|
||||
const font = self.fonts.get(id) orelse {
|
||||
log.warn("Attempt to set font that doesn't exist: {}", .{id});
|
||||
return;
|
||||
@ -1312,17 +1213,9 @@ pub fn setFont(id: Font.Id, ttf_data: [:0]const u8) void {
|
||||
font.cache = .init();
|
||||
}
|
||||
|
||||
fn getFont(id: Font.Id) ?*Font {
|
||||
const self = &g_state;
|
||||
if (id == self.nil_font) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self.fonts.get(id);
|
||||
}
|
||||
|
||||
pub fn getGlyphIndex(id: Font.Id, codepoint: u21) ?GlyphIndex {
|
||||
const font = getFont(id) orelse return null;
|
||||
const self = &g_state;
|
||||
const font = self.fonts.get(id) orelse return null;
|
||||
const stb_font = font.stb orelse return null;
|
||||
|
||||
if (stb_font.findGlyphIndex(codepoint)) |index| {
|
||||
@ -1334,14 +1227,16 @@ pub fn getGlyphIndex(id: Font.Id, codepoint: u21) ?GlyphIndex {
|
||||
}
|
||||
|
||||
pub fn getFontPixelScale(id: Font.Id, height: f32) f32 {
|
||||
const font = getFont(id) orelse return 0;
|
||||
const self = &g_state;
|
||||
const font = self.fonts.get(id) orelse return 0;
|
||||
const stb_font = font.stb orelse return 0;
|
||||
|
||||
return stb_font.scaleForPixelHeight(height);
|
||||
}
|
||||
|
||||
pub fn getFontAscent(id: Font.Id, height: f32) f32 {
|
||||
const font = getFont(id) orelse return 0;
|
||||
const self = &g_state;
|
||||
const font = self.fonts.get(id) orelse return 0;
|
||||
const stb_font = font.stb orelse return 0;
|
||||
|
||||
const vmetrics = stb_font.getFontVMetrics();
|
||||
@ -1351,7 +1246,7 @@ pub fn getFontAscent(id: Font.Id, height: f32) f32 {
|
||||
|
||||
pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Font.Glyph {
|
||||
const self = &g_state;
|
||||
const font = getFont(id) orelse return null;
|
||||
const font = self.fonts.get(id) orelse return null;
|
||||
const stb_font = font.stb orelse return null;
|
||||
|
||||
// TODO: Allow specifying a different scale for x and y
|
||||
@ -1374,7 +1269,7 @@ pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Fo
|
||||
const box_width: u32 = @intCast(glyph.box.x1 - glyph.box.x0);
|
||||
const box_height: u32 = @intCast(glyph.box.y1 - glyph.box.y0);
|
||||
if (box_width > 0 and box_height > 0) {
|
||||
assert(glyph.sprite == self.nil_sprite);
|
||||
assert(glyph.sprite == Sprite.Id.nil);
|
||||
glyph.sprite = initSprite(.{ .spritesheet = font.spritesheet, .padding = 1 });
|
||||
|
||||
assert(box_width < Font.Glyph.max_width);
|
||||
@ -1395,7 +1290,7 @@ pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Fo
|
||||
);
|
||||
setSprite(glyph.sprite, .{ .image = bitmap });
|
||||
} else {
|
||||
glyph.sprite = self.nil_sprite;
|
||||
glyph.sprite = .nil;
|
||||
}
|
||||
}
|
||||
glyph.used_this_frame = true;
|
||||
@ -1431,7 +1326,7 @@ pub const TextRunLayout = struct {
|
||||
pub fn next(self: *TextRunLayout, glyph_index: GlyphIndex) ?GlyphRect {
|
||||
const glyph = getGlyph(self.font, glyph_index, self.scale_x, self.scale_y) orelse return null;
|
||||
|
||||
const font = getFont(self.font) orelse return null;
|
||||
const font = g_state.fonts.get(self.font) orelse return null;
|
||||
const stb_font = font.stb orelse return null;
|
||||
|
||||
if (self.prev_glyph) |prev_glyph| {
|
||||
@ -1494,8 +1389,6 @@ pub const DrawTextOptions = struct {
|
||||
};
|
||||
|
||||
pub fn drawText(id: Font.Id, opts: DrawTextOptions) void {
|
||||
const self = &g_state;
|
||||
|
||||
var layout = TextRunLayout.init(id, opts.height);
|
||||
|
||||
var pos = opts.pos;
|
||||
@ -1513,9 +1406,6 @@ pub fn drawText(id: Font.Id, opts: DrawTextOptions) void {
|
||||
while (iter.nextCodepoint()) |codepoint| {
|
||||
const glyph_index = getGlyphIndex(id, codepoint) orelse continue;
|
||||
const glyph_layout = layout.next(glyph_index) orelse continue;
|
||||
if (glyph_layout.sprite == self.nil_sprite) {
|
||||
continue;
|
||||
}
|
||||
|
||||
drawSprite(
|
||||
glyph_layout.sprite,
|
||||
@ -1619,9 +1509,6 @@ pub const TextBuilder = struct {
|
||||
|
||||
pub fn draw(self: *TextBuilder, pos: Vec2) void {
|
||||
for (self.glyphs.items) |glyph| {
|
||||
if (glyph.sprite == g_state.nil_sprite) {
|
||||
continue;
|
||||
}
|
||||
drawSprite(glyph.sprite, glyph.rect.pos.add(pos), glyph.rect.size, glyph.color);
|
||||
}
|
||||
}
|
||||
@ -2276,7 +2163,7 @@ pub const Font = struct {
|
||||
.x1 = 0,
|
||||
.y1 = 0,
|
||||
},
|
||||
.sprite = g_state.nil_sprite,
|
||||
.sprite = .nil,
|
||||
.used_this_frame = false
|
||||
};
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ const shd = @import("shader");
|
||||
pub const ImGUI = @import("./imgui.zig");
|
||||
pub const Gfx = @import("./graphics.zig");
|
||||
pub const Input = @import("./input.zig");
|
||||
pub const Audio = @import("./audio.zig");
|
||||
|
||||
const EmbeddedAssets = @import("embedded_assets");
|
||||
|
||||
@ -66,6 +67,9 @@ fn PlatformType(App: type) type {
|
||||
try Gfx.init(self.gpa, .{
|
||||
.func = sokolLogCallback
|
||||
});
|
||||
try Audio.init(self.gpa, .{
|
||||
.logger = .{ .func = sokolLogCallback }
|
||||
});
|
||||
ImGUI.init(.{
|
||||
.func = sokolLogCallback
|
||||
});
|
||||
@ -445,6 +449,7 @@ fn PlatformType(App: type) type {
|
||||
|
||||
ImGUI.deinit();
|
||||
Gfx.deinit();
|
||||
Audio.deinit(self.gpa);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -50,9 +50,18 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
generation: Generation,
|
||||
index: Index,
|
||||
|
||||
pub const nil = Id{
|
||||
.generation = std.math.maxInt(Generation),
|
||||
.index = std.math.maxInt(Index),
|
||||
};
|
||||
|
||||
pub fn format(self: Id, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
if (self == Id.nil) {
|
||||
try writer.print("Id({s}){{ nil }}", .{ @typeName(Value) });
|
||||
} else {
|
||||
try writer.print("Id({s}){{ {}, {} }}", .{ @typeName(Value), self.index, self.generation });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
@ -129,10 +138,12 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
assert(!slot.used);
|
||||
slot.used = true;
|
||||
|
||||
return Id{
|
||||
const result = Id{
|
||||
.index = @intCast(index),
|
||||
.generation = slot.generation
|
||||
};
|
||||
assert(result != Id.nil);
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn insertUndefined(self: *Self) Allocator.Error!Id {
|
||||
@ -178,6 +189,14 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
slot.used = false;
|
||||
slot.generation +%= 1;
|
||||
self.insertHole(id.index);
|
||||
|
||||
const next_id = Id{
|
||||
.generation = id.generation,
|
||||
.index = id.index,
|
||||
};
|
||||
if (next_id == Id.nil) {
|
||||
slot.generation +%= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(self: *Self, id: Id) bool {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user