Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
zig-cache/
docs/
.zig-cache/
docs/
13 changes: 9 additions & 4 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ pub fn build(b: *std.Build) void {
const mode_str = @tagName(test_mode);
const tests = b.addTest(.{
.name = mode_str ++ " ",
.root_source_file = b.path("src/test.zig"),
.target = target,
.optimize = test_mode,
.root_module = b.createModule(.{
.root_source_file = b.path("src/test.zig"),
.target = target,
.optimize = test_mode,
}),
});

const run_test_step = b.addRunArtifact(tests);
Expand All @@ -21,7 +23,10 @@ pub fn build(b: *std.Build) void {
}

const tests = b.addTest(.{
.root_source_file = b.path("src/sparse_set.zig"),
.root_module = b.createModule(.{
.root_source_file = b.path("src/sparse_set.zig"),
.target = target,
}),
});

const install_docs = b.addInstallDirectory(.{
Expand Down
194 changes: 105 additions & 89 deletions src/sparse_set.zig
Original file line number Diff line number Diff line change
Expand Up @@ -167,16 +167,14 @@ pub fn SparseSet(comptime config: SparseSetConfig) type {
return self.dense_to_sparse[0..self.dense_count];
}

// A bit of a hack to comptime add a function
// TODO: Rewrite after https://github.com/ziglang/zig/issues/1717
pub usingnamespace switch (value_layout) {
.InternalArrayOfStructs => struct {
/// Returns a slice that can be used to loop over the values.
pub fn toValueSlice(self: Self) []ValueT {
return self.values[0..self.dense_count];
}
},
else => struct {},
/// Returns a slice that can be used to loop over the values.
fn _toValueSlice(self: Self) []ValueT {
return self.values[0..self.dense_count];
}

pub const toValueSlice = switch (value_layout) {
.InternalArrayOfStructs => _toValueSlice,
else => {},
};

/// Returns how many dense indices are still available
Expand Down Expand Up @@ -239,62 +237,66 @@ pub fn SparseSet(comptime config: SparseSetConfig) type {
return self.add(sparse);
}

// TODO: Rewrite after https://github.com/ziglang/zig/issues/1717
pub usingnamespace switch (value_layout) {
.InternalArrayOfStructs => struct {
/// Registers the sparse value and matches it to a dense index
/// Grows .dense_to_sparse and .values if needed and resizing is allowed.
/// Note: If resizing is allowed, you must use an allocator that you are sure
/// will never fail for your use cases.
/// If that is not an option, use addOrError.
pub fn addValue(self: *Self, sparse: SparseT, value: ValueT) DenseT {
if (allow_resize == .ResizeAllowed) {
if (self.dense_count == self.capacity_dense) {
self.capacity_dense = self.capacity_dense * 2;
self.dense_to_sparse = self.allocator.realloc(self.dense_to_sparse, self.capacity_dense) catch unreachable;
if (value_layout == .InternalArrayOfStructs) {
self.values = self.allocator.realloc(self.values, self.capacity_dense) catch unreachable;
}
}
/// Registers the sparse value and matches it to a dense index
/// Grows .dense_to_sparse and .values if needed and resizing is allowed.
/// Note: If resizing is allowed, you must use an allocator that you are sure
/// will never fail for your use cases.
/// If that is not an option, use addOrError.
fn _addValue(self: *Self, sparse: SparseT, value: ValueT) DenseT {
if (allow_resize == .ResizeAllowed) {
if (self.dense_count == self.capacity_dense) {
self.capacity_dense = self.capacity_dense * 2;
self.dense_to_sparse = self.allocator.realloc(self.dense_to_sparse, self.capacity_dense) catch unreachable;
if (value_layout == .InternalArrayOfStructs) {
self.values = self.allocator.realloc(self.values, self.capacity_dense) catch unreachable;
}

assert(sparse < self.capacity_sparse);
assert(self.dense_count < self.capacity_dense);
assert(!self.hasSparse(sparse));
self.dense_to_sparse[self.dense_count] = sparse;
self.sparse_to_dense[sparse] = @intCast(self.dense_count);
self.values[self.dense_count] = value;
self.dense_count += 1;
return @intCast(self.dense_count - 1);
}
}

/// May return error.OutOfBounds or error.AlreadyRegistered, otherwise calls add.
/// Grows .dense_to_sparse and .values if needed and resizing is allowed.
pub fn addValueOrError(self: *Self, sparse: SparseT, value: ValueT) !DenseT {
if (sparse >= self.capacity_sparse) {
return error.OutOfBounds;
}
assert(sparse < self.capacity_sparse);
assert(self.dense_count < self.capacity_dense);
assert(!self.hasSparse(sparse));
self.dense_to_sparse[self.dense_count] = sparse;
self.sparse_to_dense[sparse] = @intCast(self.dense_count);
self.values[self.dense_count] = value;
self.dense_count += 1;
return @intCast(self.dense_count - 1);
}

if (try self.hasSparseOrError(sparse)) {
return error.AlreadyRegistered;
}
pub const addValue = switch (value_layout) {
.InternalArrayOfStructs => _addValue,
else => {},
};

if (self.dense_count == self.capacity_dense) {
if (allow_resize == .ResizeAllowed) {
self.capacity_dense = self.capacity_dense * 2;
self.dense_to_sparse = try self.allocator.realloc(self.dense_to_sparse, self.capacity_dense);
if (value_layout == .InternalArrayOfStructs) {
self.values = try self.allocator.realloc(self.values, self.capacity_dense);
}
} else {
return error.OutOfBounds;
}
}
/// May return error.OutOfBounds or error.AlreadyRegistered, otherwise calls add.
/// Grows .dense_to_sparse and .values if needed and resizing is allowed.
fn _addValueOrError(self: *Self, sparse: SparseT, value: ValueT) !DenseT {
if (sparse >= self.capacity_sparse) {
return error.OutOfBounds;
}

return self.addValue(sparse, value);
if (try self.hasSparseOrError(sparse)) {
return error.AlreadyRegistered;
}

if (self.dense_count == self.capacity_dense) {
if (allow_resize == .ResizeAllowed) {
self.capacity_dense = self.capacity_dense * 2;
self.dense_to_sparse = try self.allocator.realloc(self.dense_to_sparse, self.capacity_dense);
if (value_layout == .InternalArrayOfStructs) {
self.values = try self.allocator.realloc(self.values, self.capacity_dense);
}
} else {
return error.OutOfBounds;
}
},
else => struct {},
}

return self.addValue(sparse, value);
}

pub const addValueOrError = switch (value_layout) {
.InternalArrayOfStructs => _addValueOrError,
else => {},
};

/// Removes the sparse/dense index, and replaces it with the last ones.
Expand Down Expand Up @@ -406,39 +408,53 @@ pub fn SparseSet(comptime config: SparseSetConfig) type {
return self.getByDense(dense);
}

// TODO: Rewrite after https://github.com/ziglang/zig/issues/1717
pub usingnamespace switch (value_layout) {
.InternalArrayOfStructs => struct {
/// Returns a pointer to the SOA value corresponding to the sparse parameter.
pub fn getValueBySparse(self: Self, sparse: SparseT) *ValueT {
assert(self.hasSparse(sparse));
const dense = self.sparse_to_dense[sparse];
return &self.values[dense];
}
/// Returns a pointer to the SOA value corresponding to the sparse parameter.
fn _getValueBySparse(self: Self, sparse: SparseT) *ValueT {
assert(self.hasSparse(sparse));
const dense = self.sparse_to_dense[sparse];
return &self.values[dense];
}

/// First tries hasSparse, then returns getValueBySparse().
pub fn getValueBySparseOrError(self: Self, sparse: SparseT) !*ValueT {
if (!try self.hasSparseOrError(sparse)) {
return error.NotRegistered;
}
return self.getValueBySparse(sparse);
}
pub const getValueBySparse = switch (value_layout) {
.InternalArrayOfStructs => _getValueBySparse,
else => {},
};

/// Returns a pointer to the SOA value corresponding to the sparse parameter.
pub fn getValueByDense(self: Self, dense: DenseT) *ValueT {
assert(dense < self.dense_count);
return &self.values[dense];
}
/// First tries hasSparse, then returns getValueBySparse().
fn _getValueBySparseOrError(self: Self, sparse: SparseT) !*ValueT {
if (!try self.hasSparseOrError(sparse)) {
return error.NotRegistered;
}
return self.getValueBySparse(sparse);
}

/// Returns error.OutOfBounds or getValueByDense().
pub fn getValueByDenseOrError(self: Self, dense: DenseT) !*ValueT {
if (dense >= self.dense_count) {
return error.OutOfBounds;
}
return self.getValueByDense(dense);
}
},
else => struct {},
pub const getValueBySparseOrError = switch (value_layout) {
.InternalArrayOfStructs => _getValueBySparseOrError,
else => {},
};

/// Returns a pointer to the SOA value corresponding to the sparse parameter.
fn _getValueByDense(self: Self, dense: DenseT) *ValueT {
assert(dense < self.dense_count);
return &self.values[dense];
}

pub const getValueByDense = switch (value_layout) {
.InternalArrayOfStructs => _getValueByDense,
else => {},
};

/// Returns error.OutOfBounds or getValueByDense().
fn _getValueByDenseOrError(self: Self, dense: DenseT) !*ValueT {
if (dense >= self.dense_count) {
return error.OutOfBounds;
}
return self.getValueByDense(dense);
}

pub const getValueByDenseOrError = switch (value_layout) {
.InternalArrayOfStructs => _getValueByDenseOrError,
else => {},
};
};
}
Expand Down