From d3a5a2e5ef1ff791b26c154166ec66f9016d4544 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 13:57:26 +0300 Subject: [PATCH 01/11] chore: migrate examples/basic.zig to 0.16 --- examples/basic.zig | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/examples/basic.zig b/examples/basic.zig index 877f801..f414c4b 100644 --- a/examples/basic.zig +++ b/examples/basic.zig @@ -1,17 +1,13 @@ const std = @import("std"); const Regex = @import("regex").Regex; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("\n=== Zig Regex Examples ===\n\n", .{}); // Example 1: Simple literal matching { std.debug.print("Example 1: Literal matching\n", .{}); - var regex = try Regex.compile(allocator, "hello"); + var regex = try Regex.compile(init.gpa, "hello"); defer regex.deinit(); const matches = try regex.isMatch("hello"); @@ -22,7 +18,7 @@ pub fn main() !void { // Example 2: Alternation { std.debug.print("Example 2: Alternation (cat|dog)\n", .{}); - var regex = try Regex.compile(allocator, "cat|dog"); + var regex = try Regex.compile(init.gpa, "cat|dog"); defer regex.deinit(); std.debug.print(" 'cat' matches: {}\n", .{try regex.isMatch("cat")}); @@ -34,7 +30,7 @@ pub fn main() !void { // Example 3: Star quantifier { std.debug.print("Example 3: Star quantifier (a*)\n", .{}); - var regex = try Regex.compile(allocator, "a*"); + var regex = try Regex.compile(init.gpa, "a*"); defer regex.deinit(); std.debug.print(" '' matches: {}\n", .{try regex.isMatch("")}); @@ -46,12 +42,12 @@ pub fn main() !void { // Example 4: Finding matches { std.debug.print("Example 4: Finding matches\n", .{}); - var regex = try Regex.compile(allocator, "world"); + var regex = try Regex.compile(init.gpa, "world"); defer regex.deinit(); if (try regex.find("hello world")) |match_result| { var mut_match = match_result; - defer mut_match.deinit(allocator); + defer mut_match.deinit(init.gpa); std.debug.print(" Found '{s}' at position {d}-{d}\n", .{ match_result.slice, match_result.start, match_result.end }); } std.debug.print("\n", .{}); @@ -60,11 +56,11 @@ pub fn main() !void { // Example 5: Replace { std.debug.print("Example 5: Replace\n", .{}); - var regex = try Regex.compile(allocator, "world"); + var regex = try Regex.compile(init.gpa, "world"); defer regex.deinit(); - const result = try regex.replace(allocator, "hello world", "Zig"); - defer allocator.free(result); + const result = try regex.replace(init.gpa, "hello world", "Zig"); + defer init.gpa.free(result); std.debug.print(" Replaced: '{s}'\n", .{result}); std.debug.print("\n", .{}); From 53f676304746b78ba230d498dbfc5433cb2dd475 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 14:23:30 +0300 Subject: [PATCH 02/11] chore: migrate array instantiation to .empty --- src/builder.zig | 4 ++-- src/lint.zig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder.zig b/src/builder.zig index 309c657..ffd319f 100644 --- a/src/builder.zig +++ b/src/builder.zig @@ -29,7 +29,7 @@ pub const Builder = struct { pub fn init(allocator: std.mem.Allocator) Builder { return .{ .allocator = allocator, - .parts = std.ArrayList([]const u8){}, + .parts = .empty, }; } @@ -304,7 +304,7 @@ pub const Composer = struct { pub fn init(allocator: std.mem.Allocator) Composer { return .{ .allocator = allocator, - .patterns = std.ArrayList([]const u8){}, + .patterns = .empty, }; } diff --git a/src/lint.zig b/src/lint.zig index 5134194..b918e85 100644 --- a/src/lint.zig +++ b/src/lint.zig @@ -63,7 +63,7 @@ pub const Lint = struct { pub fn init(allocator: std.mem.Allocator, pattern: []const u8) Lint { return .{ .allocator = allocator, - .warnings = std.ArrayList(Warning){}, + .warnings = .empty, .pattern = pattern, }; } From 7e539627cd2430a5424cccfecd2d9a31e7e4b100 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 14:31:34 +0300 Subject: [PATCH 03/11] chore: migrate examples_advanced_features.zig to 0.16 --- examples/advanced_features.zig | 50 ++++++++++++++++------------------ 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/examples/advanced_features.zig b/examples/advanced_features.zig index e9112ab..1f89812 100644 --- a/examples/advanced_features.zig +++ b/examples/advanced_features.zig @@ -6,11 +6,7 @@ const Composer = @import("regex").Composer; const Lint = @import("regex").Lint; const ComplexityAnalyzer = @import("regex").ComplexityAnalyzer; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("\n=== Advanced Regex Features Examples ===\n\n", .{}); // Example 1: Builder API - Type-safe pattern construction @@ -19,7 +15,7 @@ pub fn main() !void { std.debug.print("Example 1: Builder API for Type-Safe Construction\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var builder = Builder.init(allocator); + var builder = Builder.init(init.gpa); defer builder.deinit(); // Build a pattern for email validation @@ -35,11 +31,11 @@ pub fn main() !void { _ = try builder.endOfLine(); const pattern = try builder.build(); - defer allocator.free(pattern); + defer init.gpa.free(pattern); std.debug.print("Built pattern: {s}\n", .{pattern}); - var regex = try Regex.compile(allocator, pattern); + var regex = try Regex.compile(init.gpa, pattern); defer regex.deinit(); const test_emails = [_][]const u8{ @@ -64,21 +60,21 @@ pub fn main() !void { std.debug.print("───────────────────────────────────────────────\n", .{}); // Use predefined patterns - const email_pattern = try Patterns.email(allocator); - defer allocator.free(email_pattern); + const email_pattern = try Patterns.email(init.gpa); + defer init.gpa.free(email_pattern); - const url_pattern = try Patterns.url(allocator); - defer allocator.free(url_pattern); + const url_pattern = try Patterns.url(init.gpa); + defer init.gpa.free(url_pattern); - const phone_pattern = try Patterns.phoneUS(allocator); - defer allocator.free(phone_pattern); + const phone_pattern = try Patterns.phoneUS(init.gpa); + defer init.gpa.free(phone_pattern); std.debug.print("Email pattern: {s}\n", .{email_pattern}); std.debug.print("URL pattern: {s}\n", .{url_pattern}); std.debug.print("Phone pattern: {s}\n\n", .{phone_pattern}); // Test phone number pattern - var phone_regex = try Regex.compile(allocator, phone_pattern); + var phone_regex = try Regex.compile(init.gpa, phone_pattern); defer phone_regex.deinit(); const test_phones = [_][]const u8{ @@ -103,7 +99,7 @@ pub fn main() !void { std.debug.print("Example 3: Pattern Composition\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var composer = Composer.init(allocator); + var composer = Composer.init(init.gpa); defer composer.deinit(); // Compose multiple patterns with OR @@ -112,11 +108,11 @@ pub fn main() !void { _ = try composer.add("bird"); const alternatives = try composer.alternatives(); - defer allocator.free(alternatives); + defer init.gpa.free(alternatives); std.debug.print("Composed pattern (OR): {s}\n", .{alternatives}); - var regex = try Regex.compile(allocator, alternatives); + var regex = try Regex.compile(init.gpa, alternatives); defer regex.deinit(); const test_strings = [_][]const u8{ @@ -145,7 +141,7 @@ pub fn main() !void { const problematic_pattern = "(a+)+b"; std.debug.print("Analyzing pattern: \"{s}\"\n\n", .{problematic_pattern}); - var lint = Lint.init(allocator, problematic_pattern); + var lint = Lint.init(init.gpa, problematic_pattern); defer lint.deinit(); try lint.analyze(); @@ -157,7 +153,7 @@ pub fn main() !void { const good_pattern = "^[a-z]+$"; std.debug.print("Analyzing pattern: \"{s}\"\n\n", .{good_pattern}); - var lint2 = Lint.init(allocator, good_pattern); + var lint2 = Lint.init(init.gpa, good_pattern); defer lint2.deinit(); try lint2.analyze(); @@ -198,7 +194,7 @@ pub fn main() !void { std.debug.print("───────────────────────────────────────────────\n", .{}); // Build a complex pattern using the builder - var builder = Builder.init(allocator); + var builder = Builder.init(init.gpa); defer builder.deinit(); std.debug.print("Building a URL validator:\n", .{}); @@ -215,13 +211,13 @@ pub fn main() !void { _ = try builder.endOfLine(); const url_pattern_built = try builder.build(); - defer allocator.free(url_pattern_built); + defer init.gpa.free(url_pattern_built); std.debug.print("Built pattern: {s}\n\n", .{url_pattern_built}); // Lint the pattern std.debug.print("Linting the pattern:\n", .{}); - var lint = Lint.init(allocator, url_pattern_built); + var lint = Lint.init(init.gpa, url_pattern_built); defer lint.deinit(); try lint.analyze(); @@ -232,7 +228,7 @@ pub fn main() !void { std.debug.print("Complexity: {s} (score: {d})\n\n", .{ @tagName(complexity.getLevel()), complexity.complexity_score }); // Test the pattern - var regex = try Regex.compile(allocator, url_pattern_built); + var regex = try Regex.compile(init.gpa, url_pattern_built); defer regex.deinit(); const test_urls = [_][]const u8{ @@ -257,7 +253,7 @@ pub fn main() !void { std.debug.print("Example 7: Complex Pattern with Builder\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var builder = Builder.init(allocator); + var builder = Builder.init(init.gpa); defer builder.deinit(); // Build a pattern for matching IPv4 addresses @@ -301,11 +297,11 @@ pub fn main() !void { _ = try builder.endOfLine(); const ipv4_pattern = try builder.build(); - defer allocator.free(ipv4_pattern); + defer init.gpa.free(ipv4_pattern); std.debug.print("Built pattern: {s}\n\n", .{ipv4_pattern}); - var regex = try Regex.compile(allocator, ipv4_pattern); + var regex = try Regex.compile(init.gpa, ipv4_pattern); defer regex.deinit(); const test_ips = [_][]const u8{ From 0edca00a226cdf4e5f6eed40195f8a2469d2d681 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 14:48:44 +0300 Subject: [PATCH 04/11] chore: migrate examples/debug_visualization.zig to 0.16 --- examples/debug_visualization.zig | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/examples/debug_visualization.zig b/examples/debug_visualization.zig index f2f0a4b..8930479 100644 --- a/examples/debug_visualization.zig +++ b/examples/debug_visualization.zig @@ -4,11 +4,7 @@ const debug = @import("regex").debug; const Parser = @import("regex").parser.Parser; const Optimizer = @import("regex").optimizer.Optimizer; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("\n=== Regex Debugging and Analysis Examples ===\n\n", .{}); const patterns = [_][]const u8{ @@ -25,7 +21,7 @@ pub fn main() !void { std.debug.print("───────────────────────────────────────────────\n", .{}); // Example 1: Show optimization info - var regex = Regex.compile(allocator, pattern) catch |err| { + var regex = Regex.compile(init.gpa, pattern) catch |err| { std.debug.print(" ❌ Compilation error: {}\n\n", .{err}); continue; }; @@ -54,15 +50,15 @@ pub fn main() !void { // Example 2: Pattern analysis { - var parser = Parser.init(allocator, pattern) catch continue; + var parser = Parser.init(init.gpa, pattern) catch continue; var tree = parser.parse() catch continue; defer tree.deinit(); - var opt = Optimizer.init(allocator); + var opt = Optimizer.init(init.gpa); var opt_info = try opt.analyze(tree.root); - defer opt_info.deinit(allocator); + defer opt_info.deinit(init.gpa); - var analyzer = debug.PatternAnalyzer.init(allocator); + var analyzer = debug.PatternAnalyzer.init(init.gpa); var analysis = try analyzer.analyze(pattern, &tree, &opt_info); defer analysis.deinit(); @@ -88,7 +84,7 @@ pub fn main() !void { std.debug.print("───────────────────────────────────────────────\n", .{}); const test_pattern = "hello.*world"; - var test_regex = try Regex.compile(allocator, test_pattern); + var test_regex = try Regex.compile(init.gpa, test_pattern); defer test_regex.deinit(); const test_inputs = [_][]const u8{ From a29b4ae4d2f3cdf231ae707468de91deb944f96f Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 14:52:19 +0300 Subject: [PATCH 05/11] chore: migrate examples/error_handling.zig to 0.16 --- examples/error_handling.zig | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/examples/error_handling.zig b/examples/error_handling.zig index 9a9be1c..b8636db 100644 --- a/examples/error_handling.zig +++ b/examples/error_handling.zig @@ -4,20 +4,16 @@ const ErrorContext = @import("regex").ErrorContext; const ErrorHelper = @import("regex").ErrorHelper; const RegexError = @import("regex").RegexError; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("\n=== Regex Error Handling Examples ===\n\n", .{}); // Example 1: Invalid patterns with helpful error messages const invalid_patterns = [_][]const u8{ - "abc(def", // Unmatched parenthesis - "abc[def", // Unmatched bracket - "abc+(", // Invalid quantifier usage - "abc\\q", // Invalid escape sequence - "[z-a]", // Invalid character range + "abc(def", // Unmatched parenthesis + "abc[def", // Unmatched bracket + "abc+(", // Invalid quantifier usage + "abc\\q", // Invalid escape sequence + "[z-a]", // Invalid character range "(a(b(c(d(e(f(g(h(i(j(k(l(m(n(o(p(q", // Too many nested groups }; @@ -26,7 +22,7 @@ pub fn main() !void { std.debug.print("Testing pattern: \"{s}\"\n", .{pattern}); std.debug.print("───────────────────────────────────────────────\n", .{}); - if (Regex.compile(allocator, pattern)) |regex_value| { + if (Regex.compile(init.gpa, pattern)) |regex_value| { var regex = regex_value; defer regex.deinit(); std.debug.print("✓ Pattern compiled successfully (unexpected)\n\n", .{}); @@ -53,7 +49,7 @@ pub fn main() !void { const user_pattern = "hello|world"; std.debug.print("User provided pattern: \"{s}\"\n", .{user_pattern}); - if (Regex.compile(allocator, user_pattern)) |regex_value| { + if (Regex.compile(init.gpa, user_pattern)) |regex_value| { var regex = regex_value; defer regex.deinit(); std.debug.print("✓ Pattern compiled successfully\n", .{}); @@ -84,7 +80,7 @@ pub fn main() !void { const problematic_pattern = "abc[def"; std.debug.print("Problematic pattern: \"{s}\"\n", .{problematic_pattern}); - if (Regex.compile(allocator, problematic_pattern)) |regex_value| { + if (Regex.compile(init.gpa, problematic_pattern)) |regex_value| { var regex = regex_value; regex.deinit(); } else |err| { @@ -95,7 +91,7 @@ pub fn main() !void { const fixed_pattern = "abc[def]"; std.debug.print("Fixed pattern: \"{s}\"\n", .{fixed_pattern}); - if (Regex.compile(allocator, fixed_pattern)) |regex_value| { + if (Regex.compile(init.gpa, fixed_pattern)) |regex_value| { var regex = regex_value; defer regex.deinit(); std.debug.print("✓ Fixed pattern compiles successfully!\n", .{}); @@ -119,7 +115,7 @@ pub fn main() !void { for (patterns_to_validate) |pattern| { std.debug.print("Validating: \"{s}\" ... ", .{pattern}); - if (Regex.compile(allocator, pattern)) |regex_value| { + if (Regex.compile(init.gpa, pattern)) |regex_value| { var regex = regex_value; regex.deinit(); std.debug.print("✓ Valid\n", .{}); From 1d0779ae1cad323c504ab6b030b1a95a0aa7453b Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 15:19:11 +0300 Subject: [PATCH 06/11] chore: migrate profiling.zig to Io interface and Io timestamps --- src/profiling.zig | 53 +++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/profiling.zig b/src/profiling.zig index 42d655a..9b9c664 100644 --- a/src/profiling.zig +++ b/src/profiling.zig @@ -5,11 +5,11 @@ pub const Profiler = struct { allocator: std.mem.Allocator, enabled: bool, metrics: Metrics, - start_time: ?std.time.Instant, + start_time: ?std.Io.Timestamp, pub const Metrics = struct { - compilation_time_ns: u64 = 0, - match_time_ns: u64 = 0, + compilation_time_ns: i96 = 0, + match_time_ns: i96 = 0, match_count: usize = 0, nfa_states_created: usize = 0, backtrack_count: usize = 0, @@ -49,41 +49,42 @@ pub const Profiler = struct { } }; - pub fn init(allocator: std.mem.Allocator, enabled: bool) Profiler { + pub fn init(allocator: std.mem.Allocator, io: std.Io, enabled: bool) Profiler { return .{ .allocator = allocator, .enabled = enabled, .metrics = Metrics{}, - .start_time = if (enabled) std.time.Instant.now() catch null else null, + // TODO: No clue what to actually pass as a clock + .start_time = if (enabled) std.Io.Timestamp.now(io, .real) else null, }; } /// Start timing a compilation phase - pub fn startCompilation(self: *Profiler) void { + pub fn startCompilation(self: *Profiler, io: std.Io) void { if (!self.enabled) return; - self.start_time = std.time.Instant.now() catch null; + self.start_time = std.Io.Timestamp.now(io, .real); } /// End timing a compilation phase - pub fn endCompilation(self: *Profiler) void { + pub fn endCompilation(self: *Profiler, io: std.Io) void { if (!self.enabled) return; const start = self.start_time orelse return; - const now = std.time.Instant.now() catch return; - self.metrics.compilation_time_ns += now.since(start); + const now = std.Io.Timestamp.now(io, .real); + self.metrics.compilation_time_ns += start.durationTo(now).nanoseconds; } /// Start timing a match operation - pub fn startMatch(self: *Profiler) void { + pub fn startMatch(self: *Profiler, io: std.Io) void { if (!self.enabled) return; - self.start_time = std.time.Instant.now() catch null; + self.start_time = std.Io.Timestamp.now(io, .real); } /// End timing a match operation - pub fn endMatch(self: *Profiler) void { + pub fn endMatch(self: *Profiler, io: std.Io) void { if (!self.enabled) return; const start = self.start_time orelse return; - const now = std.time.Instant.now() catch return; - self.metrics.match_time_ns += now.since(start); + const now = std.Io.Timestamp.now(io, .real); + self.metrics.match_time_ns += start.durationTo(now).nanoseconds; self.metrics.match_count += 1; } @@ -140,9 +141,9 @@ pub const Profiler = struct { } /// Reset all metrics - pub fn reset(self: *Profiler) void { + pub fn reset(self: *Profiler, io: std.Io) void { self.metrics.reset(); - self.start_time = if (self.enabled) std.time.Instant.now() catch null else null; + self.start_time = if (self.enabled) std.Io.Timestamp.now(io, .real); } /// Print metrics to stderr @@ -156,26 +157,26 @@ pub const Profiler = struct { pub const ScopedTimer = struct { profiler: *Profiler, timer_type: TimerType, - start: ?std.time.Instant, + start: ?std.Io.Timestamp, pub const TimerType = enum { compilation, match, }; - pub fn init(profiler: *Profiler, timer_type: TimerType) ScopedTimer { + pub fn init(profiler: *Profiler, io: std.Io, timer_type: TimerType) ScopedTimer { return .{ .profiler = profiler, .timer_type = timer_type, - .start = if (profiler.enabled) std.time.Instant.now() catch null else null, + .start = if (profiler.enabled) std.Io.Timestamp.now(io, .real) else null, }; } - pub fn deinit(self: *ScopedTimer) void { + pub fn deinit(self: *ScopedTimer, io: std.Io) void { if (!self.profiler.enabled) return; const start = self.start orelse return; - const now = std.time.Instant.now() catch return; - const elapsed = now.since(start); + const now = std.Io.Timestamp.now(io, .real); + const elapsed = start.durationTo(now).nanoseconds; switch (self.timer_type) { .compilation => self.profiler.metrics.compilation_time_ns += elapsed, .match => { @@ -188,7 +189,8 @@ pub const ScopedTimer = struct { test "profiler basic operations" { const allocator = std.testing.allocator; - var profiler = Profiler.init(allocator, true); + const io = std.testing.io; + var profiler = Profiler.init(allocator, io, true); profiler.startCompilation(); // Do some work (just loop to consume time) @@ -210,7 +212,8 @@ test "profiler basic operations" { test "scoped timer" { const allocator = std.testing.allocator; - var profiler = Profiler.init(allocator, true); + const io = std.testing.io; + var profiler = Profiler.init(allocator, io, true); { var timer = ScopedTimer.init(&profiler, .match); From 1bb3c735d6bbecce676556749e7645acc0e1bc09 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 15:19:11 +0300 Subject: [PATCH 07/11] chore: migrate examples/profiling_example.zig to 0.16 --- examples/profiling_example.zig | 69 ++++++++++++++++------------------ 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/examples/profiling_example.zig b/examples/profiling_example.zig index 558a6e1..71c605c 100644 --- a/examples/profiling_example.zig +++ b/examples/profiling_example.zig @@ -3,11 +3,7 @@ const Regex = @import("regex").Regex; const Profiler = @import("regex").Profiler; const ScopedTimer = @import("regex").ScopedTimer; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("\n=== Regex Profiling Examples ===\n\n", .{}); // Example 1: Basic profiling @@ -16,12 +12,12 @@ pub fn main() !void { std.debug.print("Example 1: Basic profiling\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var profiler = Profiler.init(allocator, true); + var profiler = Profiler.init(init.gpa, init.io, true); // Profile compilation - profiler.startCompilation(); - var regex = try Regex.compile(allocator, "hello.*world"); - profiler.endCompilation(); + profiler.startCompilation(init.io); + var regex = try Regex.compile(init.gpa, "hello.*world"); + profiler.endCompilation(init.io); defer regex.deinit(); // Profile multiple matches @@ -33,9 +29,9 @@ pub fn main() !void { }; for (test_inputs) |input| { - profiler.startMatch(); + profiler.startMatch(init.io); _ = try regex.isMatch(input); - profiler.endMatch(); + profiler.endMatch(init.io); } std.debug.print("\n", .{}); @@ -48,13 +44,13 @@ pub fn main() !void { std.debug.print("Example 2: Scoped timers\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var profiler = Profiler.init(allocator, true); + var profiler = Profiler.init(init.gpa, init.io, true); { - var timer = ScopedTimer.init(&profiler, .compilation); - defer timer.deinit(); + var timer = ScopedTimer.init(&profiler, init.io, .compilation); + defer timer.deinit(init.io); - var regex = try Regex.compile(allocator, "[a-z]+@[a-z]+\\.[a-z]+"); + var regex = try Regex.compile(init.gpa, "[a-z]+@[a-z]+\\.[a-z]+"); regex.deinit(); } @@ -69,33 +65,34 @@ pub fn main() !void { std.debug.print("───────────────────────────────────────────────\n", .{}); const patterns = [_][]const u8{ - "hello", // Literal - should have prefix optimization - ".*hello", // No prefix - slower - "hello.*world", // Prefix optimization + "hello", // Literal - should have prefix optimization + ".*hello", // No prefix - slower + "hello.*world", // Prefix optimization }; const test_text = ("some random text " ** 10) ++ "hello world"; for (patterns) |pattern| { - var profiler = Profiler.init(allocator, true); + var profiler = Profiler.init(init.gpa, init.io, true); std.debug.print("\nPattern: \"{s}\"\n", .{pattern}); - var regex = try Regex.compile(allocator, pattern); + var regex = try Regex.compile(init.gpa, pattern); defer regex.deinit(); // Run multiple matches const iterations = 1000; var i: usize = 0; while (i < iterations) : (i += 1) { - profiler.startMatch(); + profiler.startMatch(init.io); _ = try regex.isMatch(test_text); - profiler.endMatch(); + profiler.endMatch(init.io); } const metrics = profiler.getMetrics(); - const avg_ns = metrics.match_time_ns / iterations; - std.debug.print("Average match time: {d}μs ({d} iterations)\n", .{ avg_ns / 1000, iterations }); + // TODO: figure out if this is correct + const avg_ns = @divTrunc(metrics.match_time_ns, iterations); + std.debug.print("Average match time: {d}μs ({d} iterations)\n", .{ @divTrunc(avg_ns, 1000), iterations }); } } @@ -105,12 +102,12 @@ pub fn main() !void { std.debug.print("Example 4: Memory tracking\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var profiler = Profiler.init(allocator, true); + var profiler = Profiler.init(init.gpa, init.io, true); const complex_pattern = "(a|b)+c(d|e)*f"; std.debug.print("Pattern: \"{s}\"\n", .{complex_pattern}); - var regex = try Regex.compile(allocator, complex_pattern); + var regex = try Regex.compile(init.gpa, complex_pattern); defer regex.deinit(); // Simulate memory tracking (in real implementation, this would be integrated) @@ -131,30 +128,30 @@ pub fn main() !void { const test_pattern = "hello"; // Baseline - var baseline_profiler = Profiler.init(allocator, true); + var baseline_profiler = Profiler.init(init.gpa, init.io, true); { - var regex = try Regex.compile(allocator, baseline_pattern); + var regex = try Regex.compile(init.gpa, baseline_pattern); defer regex.deinit(); var i: usize = 0; while (i < 100) : (i += 1) { - baseline_profiler.startMatch(); + baseline_profiler.startMatch(init.io); _ = try regex.isMatch("hello world"); - baseline_profiler.endMatch(); + baseline_profiler.endMatch(init.io); } } // Test - var test_profiler = Profiler.init(allocator, true); + var test_profiler = Profiler.init(init.gpa, init.io, true); { - var regex = try Regex.compile(allocator, test_pattern); + var regex = try Regex.compile(init.gpa, test_pattern); defer regex.deinit(); var i: usize = 0; while (i < 100) : (i += 1) { - test_profiler.startMatch(); + test_profiler.startMatch(init.io); _ = try regex.isMatch("hello world"); - test_profiler.endMatch(); + test_profiler.endMatch(init.io); } } @@ -162,8 +159,8 @@ pub fn main() !void { const test_time = test_profiler.getMetrics().match_time_ns; const diff_percent = @as(f64, @floatFromInt(test_time)) / @as(f64, @floatFromInt(baseline_time)) * 100.0 - 100.0; - std.debug.print("\nBaseline time: {d}μs\n", .{baseline_time / 1000}); - std.debug.print("Test time: {d}μs\n", .{test_time / 1000}); + std.debug.print("\nBaseline time: {d}μs\n", .{@divTrunc(baseline_time, 1000)}); + std.debug.print("Test time: {d}μs\n", .{@divTrunc(test_time, 1000)}); std.debug.print("Difference: {d:.1}%\n", .{diff_percent}); if (diff_percent > 10.0) { From 313ac11e5bda7b2c3957637b27de4dae6eb09b34 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 15:46:07 +0300 Subject: [PATCH 08/11] chore: migrate examples/thread_safety_example.zig to 0.16 --- examples/thread_safety.zig | 45 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/examples/thread_safety.zig b/examples/thread_safety.zig index 0b40b1a..f5c6271 100644 --- a/examples/thread_safety.zig +++ b/examples/thread_safety.zig @@ -3,11 +3,7 @@ const Regex = @import("regex").Regex; const SharedRegex = @import("regex").SharedRegex; const RegexCache = @import("regex").RegexCache; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("\n=== Regex Thread Safety Examples ===\n\n", .{}); // Example 1: Basic concurrent matching @@ -17,7 +13,7 @@ pub fn main() !void { std.debug.print("───────────────────────────────────────────────\n", .{}); // Compile once - var regex = try Regex.compile(allocator, "\\d+"); + var regex = try Regex.compile(init.gpa, "\\d+"); defer regex.deinit(); const Worker = struct { @@ -63,7 +59,7 @@ pub fn main() !void { std.debug.print("Example 2: SharedRegex with reference counting\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var shared = try SharedRegex.init(allocator, "test"); + var shared = try SharedRegex.init(init.gpa, "test"); defer shared.deinit(); const Worker = struct { @@ -128,7 +124,7 @@ pub fn main() !void { var threads: [thread_count]std.Thread = undefined; for (&threads, 0..) |*thread, i| { - thread.* = try std.Thread.spawn(.{}, Worker.run, .{ allocator, i }); + thread.* = try std.Thread.spawn(.{}, Worker.run, .{ init.gpa, i }); } for (threads) |thread| { @@ -144,12 +140,12 @@ pub fn main() !void { std.debug.print("Example 4: Performance with concurrent matching\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var regex = try Regex.compile(allocator, "test"); + var regex = try Regex.compile(init.gpa, "test"); defer regex.deinit(); const Worker = struct { - fn run(r: *const Regex) usize { - var timer = std.time.Timer.start() catch return 0; + fn run(r: *const Regex, io: std.Io) i64 { + const start = std.Io.Timestamp.now(io, .real); var count: usize = 0; var i: usize = 0; @@ -159,37 +155,40 @@ pub fn main() !void { } else |_| {} } - const elapsed_ms = timer.read() / 1_000_000; - return elapsed_ms; + const end = std.Io.Timestamp.now(io, .real); + const elapsed = start.durationTo(end); + return elapsed.toMilliseconds(); } }; // Sequential baseline - const sequential_time = Worker.run(®ex); + const sequential_time = Worker.run(®ex, init.io); std.debug.print("Sequential: 10,000 matches in {d}ms\n", .{sequential_time}); // Parallel execution const thread_count = 4; var threads: [thread_count]std.Thread = undefined; - var times: [thread_count]usize = undefined; + var times: [thread_count]i64 = undefined; const ParallelWorker = struct { - fn run(r: *const Regex, time_ptr: *usize) void { - time_ptr.* = Worker.run(r); + fn run(r: *const Regex, io: std.Io, time_ptr: *i64) void { + time_ptr.* = Worker.run(r, io); } }; - var parallel_timer = try std.time.Timer.start(); + // TODO: there is probably a better/correct-er way to do this with io + const start = std.Io.Timestamp.now(init.io, .real); for (&threads, 0..) |*thread, i| { - thread.* = try std.Thread.spawn(.{}, ParallelWorker.run, .{ ®ex, ×[i] }); + thread.* = try std.Thread.spawn(.{}, ParallelWorker.run, .{ ®ex, init.io, ×[i] }); } for (threads) |thread| { thread.join(); } - const total_parallel = parallel_timer.read() / 1_000_000; + const end = std.Io.Timestamp.now(init.io, .real); + const total_parallel = start.durationTo(end).toMilliseconds(); std.debug.print("Parallel ({d} threads): 40,000 matches in {d}ms\n", .{ thread_count, total_parallel }); std.debug.print("Individual thread times: ", .{}); @@ -206,13 +205,13 @@ pub fn main() !void { std.debug.print("Example 5: Multiple patterns with concurrent access\n", .{}); std.debug.print("───────────────────────────────────────────────\n", .{}); - var email_regex = try Regex.compile(allocator, "[a-z]+@[a-z]+\\.[a-z]+"); + var email_regex = try Regex.compile(init.gpa, "[a-z]+@[a-z]+\\.[a-z]+"); defer email_regex.deinit(); - var phone_regex = try Regex.compile(allocator, "\\d{3}-\\d{4}"); + var phone_regex = try Regex.compile(init.gpa, "\\d{3}-\\d{4}"); defer phone_regex.deinit(); - var url_regex = try Regex.compile(allocator, "https?://"); + var url_regex = try Regex.compile(init.gpa, "https?://"); defer url_regex.deinit(); const Worker = struct { From 1bbac643181448036345dbc15babd01cd2eb0c3c Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 15:58:42 +0300 Subject: [PATCH 09/11] chore: migrate benchmarks/simple.zig to 0.16 --- benchmarks/simple.zig | 68 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/benchmarks/simple.zig b/benchmarks/simple.zig index 7d1b8b7..472a3ea 100644 --- a/benchmarks/simple.zig +++ b/benchmarks/simple.zig @@ -1,45 +1,41 @@ const std = @import("std"); const Regex = @import("regex").Regex; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("=== Simple Regex Benchmarks ===\n\n", .{}); // Test 1: Literal matching { std.debug.print("Test 1: Literal matching...\n", .{}); - var regex = try Regex.compile(allocator, "hello"); + var regex = try Regex.compile(init.gpa, "hello"); defer regex.deinit(); - var timer = try std.time.Timer.start(); - const start = timer.read(); - + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; while (i < iterations) : (i += 1) { _ = try regex.isMatch("hello world"); } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); + std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } // Test 2: Quantifiers { std.debug.print("Test 2: Quantifiers (a+)...\n", .{}); - var regex = try Regex.compile(allocator, "a+"); + var regex = try Regex.compile(init.gpa, "a+"); defer regex.deinit(); - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; @@ -47,23 +43,24 @@ pub fn main() !void { _ = try regex.isMatch("aaaa"); } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); + std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } // Test 3: Character classes { std.debug.print("Test 3: Digit matching (\\d+)...\n", .{}); - var regex = try Regex.compile(allocator, "\\d+"); + var regex = try Regex.compile(init.gpa, "\\d+"); defer regex.deinit(); - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; @@ -71,23 +68,24 @@ pub fn main() !void { _ = try regex.isMatch("12345"); } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); + std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } // Test 4: Case-insensitive { std.debug.print("Test 4: Case-insensitive matching...\n", .{}); - var regex = try Regex.compileWithFlags(allocator, "hello", .{ .case_insensitive = true }); + var regex = try Regex.compileWithFlags(init.gpa, "hello", .{ .case_insensitive = true }); defer regex.deinit(); - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; @@ -95,12 +93,14 @@ pub fn main() !void { _ = try regex.isMatch("HELLO"); } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); + std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } From 0f9acd4978a5567bcdf46085890a4202403ed782 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 16:06:28 +0300 Subject: [PATCH 10/11] chore: migrate benchmarks/prefix_optimization.zig to 0.16 --- benchmarks/prefix_optimization.zig | 88 +++++++++++++++--------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/benchmarks/prefix_optimization.zig b/benchmarks/prefix_optimization.zig index 69911f6..b16bbcf 100644 --- a/benchmarks/prefix_optimization.zig +++ b/benchmarks/prefix_optimization.zig @@ -1,11 +1,7 @@ const std = @import("std"); const Regex = @import("regex").Regex; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - +pub fn main(init: std.process.Init) !void { std.debug.print("=== Literal Prefix Optimization Benchmarks ===\n\n", .{}); // Create a long text where the pattern appears at the end @@ -14,7 +10,7 @@ pub fn main() !void { // Test 1: Pattern with literal prefix (should use optimization) { std.debug.print("Test 1: Literal prefix optimization (FOUND_IT!)...\n", .{}); - var regex = try Regex.compile(allocator, "FOUND_IT!"); + var regex = try Regex.compile(init.gpa, "FOUND_IT!"); defer regex.deinit(); // Print optimization info @@ -24,31 +20,32 @@ pub fn main() !void { std.debug.print(" ✗ No literal prefix found\n", .{}); } - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; while (i < iterations) : (i += 1) { if (try regex.find(long_text)) |match| { var mut_match = match; - mut_match.deinit(allocator); + mut_match.deinit(init.gpa); } } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); + std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } // Test 2: Pattern without useful prefix (no optimization) - using fewer iterations { std.debug.print("Test 2: No prefix optimization (.*FOUND)...\n", .{}); - var regex = try Regex.compile(allocator, ".*FOUND"); + var regex = try Regex.compile(init.gpa, ".*FOUND"); defer regex.deinit(); if (regex.opt_info.literal_prefix) |prefix| { @@ -57,8 +54,7 @@ pub fn main() !void { std.debug.print(" ✗ No literal prefix found (slower performance expected)\n", .{}); } - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); // Use fewer iterations since this is much slower without optimization const iterations: usize = 100; @@ -66,16 +62,18 @@ pub fn main() !void { while (i < iterations) : (i += 1) { if (try regex.find(long_text)) |match| { var mut_match = match; - mut_match.deinit(allocator); + mut_match.deinit(init.gpa); } } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); + std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } @@ -83,7 +81,7 @@ pub fn main() !void { { std.debug.print("Test 3: Prefix with complex suffix (hello.*world)...\n", .{}); const text_with_hello = "blah blah " ** 50 ++ "hello there world"; - var regex = try Regex.compile(allocator, "hello.*world"); + var regex = try Regex.compile(init.gpa, "hello.*world"); defer regex.deinit(); if (regex.opt_info.literal_prefix) |prefix| { @@ -92,31 +90,31 @@ pub fn main() !void { std.debug.print(" ✗ No literal prefix found\n", .{}); } - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; while (i < iterations) : (i += 1) { if (try regex.find(text_with_hello)) |match| { var mut_match = match; - mut_match.deinit(allocator); + mut_match.deinit(init.gpa); } } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } // Test 4: Anchored patterns { std.debug.print("Test 4: Start-anchored pattern (^hello)...\n", .{}); - var regex = try Regex.compile(allocator, "^hello"); + var regex = try Regex.compile(init.gpa, "^hello"); defer regex.deinit(); if (regex.opt_info.anchored_start) { @@ -127,8 +125,7 @@ pub fn main() !void { } const text = "hello world"; - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; @@ -136,12 +133,13 @@ pub fn main() !void { _ = try regex.isMatch(text); } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } @@ -149,31 +147,31 @@ pub fn main() !void { { std.debug.print("Test 5: Email pattern (user@example.com)...\n", .{}); const email_text = "Contact us at " ++ ("some filler text here. " ** 20) ++ "user@example.com for support"; - var regex = try Regex.compile(allocator, "user@example.com"); + var regex = try Regex.compile(init.gpa, "user@example.com"); defer regex.deinit(); if (regex.opt_info.literal_prefix) |prefix| { - std.debug.print(" ✓ Using literal prefix: \"{s}\" (min_len={d})\n", .{prefix, regex.opt_info.min_length}); + std.debug.print(" ✓ Using literal prefix: \"{s}\" (min_len={d})\n", .{ prefix, regex.opt_info.min_length }); } - var timer = try std.time.Timer.start(); - const start = timer.read(); + const start = std.Io.Timestamp.now(init.io, .real); const iterations: usize = 10000; var i: usize = 0; while (i < iterations) : (i += 1) { if (try regex.find(email_text)) |match| { var mut_match = match; - mut_match.deinit(allocator); + mut_match.deinit(init.gpa); } } - const elapsed = timer.read() - start; - const avg_ns = elapsed / iterations; + const end = std.Io.Timestamp.now(init.io, .real); + const elapsed = start.durationTo(end); + const avg_ns = @divTrunc(elapsed.nanoseconds, iterations); std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{ iterations, - @as(f64, @floatFromInt(elapsed)) / 1_000_000.0, - @as(f64, @floatFromInt(avg_ns)) / 1000.0, + @as(f64, @floatFromInt(elapsed.toMilliseconds())), + @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms, }); } From 28bf80e622c4a3d477f482f36b368873a51350c1 Mon Sep 17 00:00:00 2001 From: Illya Laifu Date: Sun, 19 Apr 2026 16:38:41 +0300 Subject: [PATCH 11/11] chore: migrate tests to 0.16 --- build.zig | 1 + src/profiling.zig | 8 ++++---- tests/thread_safety.zig | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/build.zig b/build.zig index 27391ef..85a184d 100644 --- a/build.zig +++ b/build.zig @@ -39,6 +39,7 @@ pub fn build(b: *std.Build) void { // Later on we'll use this module as the root module of a test executable // which requires us to specify a target. .target = target, + .link_libc = true, }); // Here we define an executable. An executable needs to have a root module diff --git a/src/profiling.zig b/src/profiling.zig index 9b9c664..e5094d6 100644 --- a/src/profiling.zig +++ b/src/profiling.zig @@ -192,13 +192,13 @@ test "profiler basic operations" { const io = std.testing.io; var profiler = Profiler.init(allocator, io, true); - profiler.startCompilation(); + profiler.startCompilation(io); // Do some work (just loop to consume time) var i: usize = 0; while (i < 1000) : (i += 1) { _ = i * i; } - profiler.endCompilation(); + profiler.endCompilation(io); profiler.recordStateCreation(5); profiler.recordBacktrack(); @@ -216,8 +216,8 @@ test "scoped timer" { var profiler = Profiler.init(allocator, io, true); { - var timer = ScopedTimer.init(&profiler, .match); - defer timer.deinit(); + var timer = ScopedTimer.init(&profiler, io, .match); + defer timer.deinit(io); // Do some work var i: usize = 0; while (i < 1000) : (i += 1) { diff --git a/tests/thread_safety.zig b/tests/thread_safety.zig index 2e6ff09..8675971 100644 --- a/tests/thread_safety.zig +++ b/tests/thread_safety.zig @@ -191,7 +191,8 @@ test "RegexCache basic operations" { test "thread-safe allocator with concurrent matching" { // Use thread-safe allocator for concurrent access - var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; + var gpa = std.heap.DebugAllocator(.{ .thread_safe = true }){}; + // TODO: can use this for leak detection defer _ = gpa.deinit(); const allocator = gpa.allocator(); @@ -222,7 +223,7 @@ test "thread-safe allocator with concurrent matching" { } test "concurrent matching different patterns" { - var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; + var gpa = std.heap.DebugAllocator(.{ .thread_safe = true }){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); @@ -272,7 +273,7 @@ test "concurrent matching different patterns" { } test "stress test: many threads many matches" { - var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; + var gpa = std.heap.DebugAllocator(.{ .thread_safe = true }){}; defer _ = gpa.deinit(); const allocator = gpa.allocator();