Fix compile errors in slot map remove function
This commit is contained in:
parent
52278ab8e0
commit
38dadb6d05
|
@ -6,6 +6,10 @@ const math = @import("./math.zig");
|
||||||
|
|
||||||
const stack = @import("./stack.zig");
|
const stack = @import("./stack.zig");
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Retruns a set of dense slots that may store `Element`s indexable by a [Slot], where `key` defines how many bits the
|
||||||
|
/// [Slot] used is made from.
|
||||||
|
///
|
||||||
pub fn Dense(comptime key: Key, comptime Element: type) type {
|
pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
const KeySlot = Slot(key);
|
const KeySlot = Slot(key);
|
||||||
const Index = math.Unsigned(key.index_bits);
|
const Index = math.Unsigned(key.index_bits);
|
||||||
|
@ -19,20 +23,12 @@ pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn fetch(self: Self, slot: KeySlot) ?*Element {
|
///
|
||||||
if (slot.index >= self.values.len) {
|
/// Clears all elements from the slots in `self`.
|
||||||
return null;
|
///
|
||||||
}
|
/// *Note* that clearing the slots is not the same as deinitializing them, as it does not deallocate any memory
|
||||||
|
/// that has already been allocated to the slots structure.
|
||||||
const redirect = &self.slots[slot.index];
|
///
|
||||||
|
|
||||||
if (slot.salt != redirect.salt) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &self.values[redirect.index];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(self: *Self) void {
|
pub fn clear(self: *Self) void {
|
||||||
self.next_free = 0;
|
self.next_free = 0;
|
||||||
self.values = self.values[0 .. 0];
|
self.values = self.values[0 .. 0];
|
||||||
|
@ -49,18 +45,66 @@ pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Frees all memory allocated by `allocator` to self.
|
||||||
|
///
|
||||||
|
/// *Note*: if `self` already contains allocated memory then `allocator` must reference the same [io.Allocator]
|
||||||
|
/// that was used to create the already-allocated memory.
|
||||||
|
///
|
||||||
pub fn deinit(self: *Self, allocator: io.Allocator) void {
|
pub fn deinit(self: *Self, allocator: io.Allocator) void {
|
||||||
io.deallocate(allocator, self.values.ptr);
|
io.deallocate(allocator, self.values.ptr);
|
||||||
io.deallocate(allocator, self.slots);
|
io.deallocate(allocator, self.slots);
|
||||||
io.deallocate(allocator, self.erase);
|
io.deallocate(allocator, self.erase);
|
||||||
|
|
||||||
|
self.values = &.{};
|
||||||
|
self.slots = null;
|
||||||
|
self.erase = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to fetch the element identified referenced by `slot` from `self`, returning it or `null` if `slot`
|
||||||
|
/// does not reference a valid element.
|
||||||
|
///
|
||||||
|
pub fn fetch(self: Self, slot: KeySlot) ?*Element {
|
||||||
|
if (slot.index >= self.values.len) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirect = &self.slots[slot.index];
|
||||||
|
|
||||||
|
if (slot.salt != redirect.salt) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &self.values[redirect.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to transactionally grow `self` by `growth_amount` using `allocator`, returning a
|
||||||
|
/// [io.AllocationError] if it failed.
|
||||||
|
///
|
||||||
|
/// Should growing fail, `self` is left in an unmodified state.
|
||||||
|
///
|
||||||
|
/// *Note*: if `self` already contains allocated memory then `allocator` must reference the same [io.Allocator]
|
||||||
|
/// that was used to create the already-allocated memory.
|
||||||
|
///
|
||||||
pub fn grow(self: *Self, allocator: io.Allocator, growth_amount: usize) io.AllocationError!void {
|
pub fn grow(self: *Self, allocator: io.Allocator, growth_amount: usize) io.AllocationError!void {
|
||||||
const grown_capacity = self.capacity + growth_amount;
|
const grown_capacity = self.capacity + growth_amount;
|
||||||
|
const values = try io.allocate_many(Element, grown_capacity, allocator);
|
||||||
|
|
||||||
self.values = try io.reallocate(allocator, self.values, grown_capacity);
|
errdefer io.deallocate(allocator, values);
|
||||||
self.slots = (try io.reallocate(allocator, self.slots.?[0 .. self.values.len], grown_capacity)).ptr;
|
|
||||||
self.erase = (try io.reallocate(allocator, self.erase.?[0 .. self.values.len], grown_capacity)).ptr;
|
const slots = try io.allocate_many(KeySlot, grown_capacity, allocator);
|
||||||
|
|
||||||
|
errdefer io.deallocate(allocator, slots);
|
||||||
|
|
||||||
|
const erase = try io.allocate_many(Index, grown_capacity, allocator);
|
||||||
|
|
||||||
|
errdefer io.deallocate(allocator, slots);
|
||||||
|
|
||||||
|
self.values = values;
|
||||||
|
self.slots = slots.ptr;
|
||||||
|
self.erase = erase.ptr;
|
||||||
self.capacity = grown_capacity;
|
self.capacity = grown_capacity;
|
||||||
|
|
||||||
// Add new values to the freelist
|
// Add new values to the freelist
|
||||||
|
@ -76,6 +120,13 @@ pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to insert `value` into `self`, growing the internal buffer with `allocator` if it is full and
|
||||||
|
/// returning a `Slot` of `key` referencing the inserted element or a [io.AllocationError] if it failed.
|
||||||
|
///
|
||||||
|
/// *Note*: if `self` already contains allocated memory then `allocator` must reference the same [io.Allocator]
|
||||||
|
/// that was used to create the already-allocated memory.
|
||||||
|
///
|
||||||
pub fn insert(self: *Self, allocator: io.Allocator, value: Element) io.AllocationError!KeySlot {
|
pub fn insert(self: *Self, allocator: io.Allocator, value: Element) io.AllocationError!KeySlot {
|
||||||
if (self.values.len == self.capacity) {
|
if (self.values.len == self.capacity) {
|
||||||
try self.grow(allocator, math.max(usize, 1, self.capacity));
|
try self.grow(allocator, math.max(usize, 1, self.capacity));
|
||||||
|
@ -97,8 +148,12 @@ pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to remove the element referenced by `slot` from `self`, returning `true` if it was successful or
|
||||||
|
/// `false` if `slot` does not reference a valid slot.
|
||||||
|
///
|
||||||
pub fn remove(self: *Self, slot: KeySlot) bool {
|
pub fn remove(self: *Self, slot: KeySlot) bool {
|
||||||
const redirect = &self.slots[slot.index];
|
const redirect = &self.slots.?[slot.index];
|
||||||
|
|
||||||
if (slot.salt != redirect.salt) {
|
if (slot.salt != redirect.salt) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -109,17 +164,17 @@ pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
self.values = self.values[0 .. (self.values.len - 1)];
|
self.values = self.values[0 .. (self.values.len - 1)];
|
||||||
|
|
||||||
if (self.values.len > 0) {
|
if (self.values.len > 0) {
|
||||||
const free_data = &self.data[free_index];
|
const free_value = &self.values[free_index];
|
||||||
const free_erase = &self.erase[free_index];
|
const free_erase = &self.erase.?[free_index];
|
||||||
const last_data = &self.data[self.values.len];
|
const last_value = &self.values[self.values.len];
|
||||||
const last_erase = &self.erase[self.values.len];
|
const last_erase = &self.erase.?[self.values.len];
|
||||||
|
|
||||||
free_data.* = last_data.*;
|
free_value.* = last_value.*;
|
||||||
free_erase.* = last_erase.*;
|
free_erase.* = last_erase.*;
|
||||||
self.slots[free_erase.*].index = free_index;
|
self.slots.?[free_erase.*].index = free_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect.salt = math.max(redirect.salt +% 1, 1);
|
redirect.salt = math.max(Index, redirect.salt +% 1, 1);
|
||||||
redirect.index = self.next_free;
|
redirect.index = self.next_free;
|
||||||
self.next_free = slot.index;
|
self.next_free = slot.index;
|
||||||
|
|
||||||
|
@ -128,11 +183,17 @@ pub fn Dense(comptime key: Key, comptime Element: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Describes the memory layout of an element-slot mapping.
|
||||||
|
///
|
||||||
pub const Key = struct {
|
pub const Key = struct {
|
||||||
index_bits: usize,
|
index_bits: usize,
|
||||||
salt_bits: usize,
|
salt_bits: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// References a slot in a slot mapping.
|
||||||
|
///
|
||||||
pub fn Slot(comptime key: Key) type {
|
pub fn Slot(comptime key: Key) type {
|
||||||
return extern struct {
|
return extern struct {
|
||||||
index: math.Unsigned(key.index_bits),
|
index: math.Unsigned(key.index_bits),
|
||||||
|
@ -140,6 +201,9 @@ pub fn Slot(comptime key: Key) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// [Key] that uses the same number of bits as a [usize].
|
||||||
|
///
|
||||||
pub const addressable_key = Key{
|
pub const addressable_key = Key{
|
||||||
.index_bits = (@bitSizeOf(usize) / 2),
|
.index_bits = (@bitSizeOf(usize) / 2),
|
||||||
.salt_bits = (@bitSizeOf(usize) / 2),
|
.salt_bits = (@bitSizeOf(usize) / 2),
|
||||||
|
|
Loading…
Reference in New Issue