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
36 changes: 20 additions & 16 deletions src/array_hash_set/managed.zig
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,7 @@ test "benchmark" {
const allocator = std.testing.allocator;
const Iterations = 10_000;
const SetSize = 1000;
const io = std.testing.io;

// Setup
var base = try ArraySetManaged(u32).initCapacity(allocator, SetSize);
Expand All @@ -827,37 +828,40 @@ test "benchmark" {
for (0..SetSize) |i| _ = other.addAssumeCapacity(@intCast(i + SetSize / 2));

// Benchmark unionOf
var union_timer = try std.time.Timer.start();
const union_start = std.Io.Timestamp.now(io, .awake);
for (0..Iterations) |_| {
var result = try base.unionOf(other);
defer result.deinit();
}
const union_elapsed = union_timer.read();
const union_elapsed = union_start.untilNow(io, .awake);

std.debug.print("\nunionOf: {d} ops/sec ({d:.2} ns/op)\n", .{
Iterations * std.time.ns_per_s / union_elapsed,
@as(f64, @floatFromInt(union_elapsed)) / @as(f64, @floatFromInt(Iterations)),
@as(f64, @floatFromInt(Iterations * std.time.ns_per_s)) / @as(f64, @floatFromInt(union_elapsed.toNanoseconds())),
@as(f64, @floatFromInt(union_elapsed.toNanoseconds())) / @as(f64, @floatFromInt(Iterations)),
});

// Benchmark intersectionOf
var inter_timer = try std.time.Timer.start();
const inter_start = std.Io.Timestamp.now(io, .awake);
for (0..Iterations) |_| {
var result = try base.intersectionOf(other);
defer result.deinit();
}
const inter_elapsed = inter_timer.read();
std.debug.print("intersectionOf: {d} ops/sec ({d:.2} ns/op)\n", .{
Iterations * std.time.ns_per_s / inter_elapsed,
@as(f64, @floatFromInt(inter_elapsed)) / @as(f64, @floatFromInt(Iterations)),
const inter_elapsed = inter_start.untilNow(io, .awake);

std.debug.print("\nintersectionOf: {d} ops/sec ({d:.2} ns/op)\n", .{
@as(f64, @floatFromInt(Iterations * std.time.ns_per_s)) / @as(f64, @floatFromInt(inter_elapsed.toNanoseconds())),
@as(f64, @floatFromInt(inter_elapsed.toNanoseconds())) / @as(f64, @floatFromInt(Iterations)),
});

// Benchmark containsAll
var contains_timer = try std.time.Timer.start();
// Benchmark containsAll
const contains_start = std.Io.Timestamp.now(io, .awake);
for (0..Iterations) |_| {
_ = base.containsAll(other);
}
const contains_elapsed = contains_timer.read();
std.debug.print("containsAll: {d} ops/sec ({d:.2} ns/op)\n", .{
Iterations * std.time.ns_per_s / contains_elapsed,
@as(f64, @floatFromInt(contains_elapsed)) / @as(f64, @floatFromInt(Iterations)),
const contains_elapsed = contains_start.untilNow(io, .awake);

std.debug.print("\ncontainsAll: {d} ops/sec ({d:.2} ns/op)\n", .{
@as(f64, @floatFromInt(Iterations * std.time.ns_per_s)) / @as(f64, @floatFromInt(contains_elapsed.toNanoseconds())),
@as(f64, @floatFromInt(contains_elapsed.toNanoseconds())) / @as(f64, @floatFromInt(Iterations)),
});

}
71 changes: 27 additions & 44 deletions src/hash_set/unmanaged.zig
Original file line number Diff line number Diff line change
Expand Up @@ -242,22 +242,12 @@ pub fn HashSetUnmanagedWithContext(comptime E: type, comptime Context: type, com
/// differenceUpdate does an in-place mutation of this set
/// and other. This set will contain all elements of this set that are not
/// also elements of other.
pub fn differenceUpdate(self: *Self, allocator: Allocator, other: Self) Allocator.Error!void {
// In-place mutation invalidates iterators therefore a temp set is needed.
// So instead of a temp set, just invoke the regular full function which
// allocates and returns a set then swap out the map internally.

// Also, this saves a step of not having to possibly discard many elements
// from the self set.

// Just get a new set with the normal method.
const diffSet = try self.differenceOf(allocator, other);

// Destroy the internal map.
self.unmanaged.deinit(allocator);

// Swap it out with the new set.
self.unmanaged = diffSet.unmanaged;
pub fn differenceUpdate(self: *Self, other: Self) Allocator.Error!void {
var iter = other.iterator();

while (iter.next()) |key_ptr| {
_ = self.remove(key_ptr.*);
}
}

fn dump(self: Self) void {
Expand Down Expand Up @@ -334,21 +324,19 @@ pub fn HashSetUnmanagedWithContext(comptime E: type, comptime Context: type, com
/// to the current set from the other set keeping only
/// elements found in this Set and the other Set.
pub fn intersectionUpdate(self: *Self, allocator: Allocator, other: Self) Allocator.Error!void {
// In-place mutation invalidates iterators therefore a temp set is needed.
// So instead of a temp set, just invoke the regular full function which
// allocates and returns a set then swap out the map internally.

// Also, this saves a step of not having to possibly discard many elements
// from the self set.

// Just get a new set with the normal method.
const interSet = try self.intersectionOf(allocator, other);
var to_remove: std.ArrayList(E) = .empty;
defer to_remove.deinit(allocator);

// Destroy the internal map.
self.unmanaged.deinit(allocator);
var iter = self.iterator();
while (iter.next()) |key_ptr| {
if (!other.contains(key_ptr.*)) {
try to_remove.append(allocator, key_ptr.*);
}
}

// Swap it out with the new set.
self.unmanaged = interSet.unmanaged;
for (to_remove.items) |item| {
_ = self.remove(item);
}
}

/// isDisjoint returns true if the intersection between two sets is the null set.
Expand Down Expand Up @@ -483,21 +471,16 @@ pub fn HashSetUnmanagedWithContext(comptime E: type, comptime Context: type, com
/// symmetricDifferenceUpdate does an in-place mutation with all elements
/// which are in either this set or the other set but not in both.
pub fn symmetricDifferenceUpdate(self: *Self, allocator: Allocator, other: Self) Allocator.Error!void {
// In-place mutation invalidates iterators therefore a temp set is needed.
// So instead of a temp set, just invoke the regular full function which
// allocates and returns a set then swap out the map internally.

// Also, this saves a step of not having to possibly discard many elements
// from the self set.

// Just get a new set with the normal method.
const sd = try self.symmetricDifferenceOf(allocator, other);

// Destroy the internal map.
self.unmanaged.deinit(allocator);
var iter = other.iterator();
while (iter.next()) |key_ptr| {
const element = key_ptr.*;

// Swap it out with the new set.
self.unmanaged = sd.unmanaged;
if (self.contains(element)) {
_ = self.remove(element);
} else {
_ = try self.add(allocator, element);
}
}
}

/// union returns a new set with all elements in both sets.
Expand Down Expand Up @@ -812,7 +795,7 @@ test "in-place methods" {
defer f.deinit(testing.allocator);
_ = try f.appendSlice(testing.allocator, &.{ 1, 11, 111, 222, 2222, 1111 });

try e.differenceUpdate(testing.allocator, f);
try e.differenceUpdate(f);

try expectEqual(1, e.cardinality());
try expect(e.contains(11111));
Expand Down
Loading