ReviewOS

also looking at this

zig-utils/zig-regex

Migrate to zig 0.16

#5
Closed illya-laifu wants to merge zig-0.16-migrations into main
13 files +222 -239
benchmarks/prefix_optimization.zigmodified+43-45
Changes to benchmarks/prefix_optimization.zig
@@ -1,11 +1,7 @@
11const std = ;
22const Regex = .Regex;
33
4pub fn main() !void {
5 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
6 defer _ = gpa.deinit();
7 const allocator = gpa.allocator();
8
4pub fn main(init: std.process.Init) !void {
95 std.debug.print("=== Literal Prefix Optimization Benchmarks ===\n\n", .{});
106
117 // Create a long text where the pattern appears at the end
@@ -14,7 +10,7 @@ pub fn main() !void {
1410 // Test 1: Pattern with literal prefix (should use optimization)
1511 {
1612 std.debug.print("Test 1: Literal prefix optimization (FOUND_IT!)...\n", .{});
17 var regex = try Regex.compile(allocator, "FOUND_IT!");
13 var regex = try Regex.compile(init.gpa, "FOUND_IT!");
1814 defer regex.deinit();
1915
2016 // Print optimization info
@@ -24,31 +20,32 @@ pub fn main() !void {
2420 std.debug.print(" ✗ No literal prefix found\n", .{});
2521 }
2622
27 var timer = try std.time.Timer.start();
28 const start = timer.read();
23 const start = std.Io.Timestamp.now(init.io, .real);
2924
3025 const iterations: usize = 10000;
3126 var i: usize = 0;
3227 while (i < iterations) : (i += 1) {
3328 if (try regex.find(long_text)) |match| {
3429 var mut_match = match;
35 mut_match.deinit(allocator);
30 mut_match.deinit(init.gpa);
3631 }
3732 }
3833
39 const elapsed = timer.read() - start;
40 const avg_ns = elapsed / iterations;
34 const end = std.Io.Timestamp.now(init.io, .real);
35 const elapsed = start.durationTo(end);
36 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
37
4138 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
4239 iterations,
43 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
44 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
40 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
41 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
4542 });
4643 }
4744
4845 // Test 2: Pattern without useful prefix (no optimization) - using fewer iterations
4946 {
5047 std.debug.print("Test 2: No prefix optimization (.*FOUND)...\n", .{});
51 var regex = try Regex.compile(allocator, ".*FOUND");
48 var regex = try Regex.compile(init.gpa, ".*FOUND");
5249 defer regex.deinit();
5350
5451 if (regex.opt_info.literal_prefix) |prefix| {
@@ -57,8 +54,7 @@ pub fn main() !void {
5754 std.debug.print(" ✗ No literal prefix found (slower performance expected)\n", .{});
5855 }
5956
60 var timer = try std.time.Timer.start();
61 const start = timer.read();
57 const start = std.Io.Timestamp.now(init.io, .real);
6258
6359 // Use fewer iterations since this is much slower without optimization
6460 const iterations: usize = 100;
@@ -66,16 +62,18 @@ pub fn main() !void {
6662 while (i < iterations) : (i += 1) {
6763 if (try regex.find(long_text)) |match| {
6864 var mut_match = match;
69 mut_match.deinit(allocator);
65 mut_match.deinit(init.gpa);
7066 }
7167 }
7268
73 const elapsed = timer.read() - start;
74 const avg_ns = elapsed / iterations;
69 const end = std.Io.Timestamp.now(init.io, .real);
70 const elapsed = start.durationTo(end);
71 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
72
7573 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
7674 iterations,
77 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
78 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
75 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
76 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
7977 });
8078 }
8179
@@ -83,7 +81,7 @@ pub fn main() !void {
8381 {
8482 std.debug.print("Test 3: Prefix with complex suffix (hello.*world)...\n", .{});
8583 const text_with_hello = "blah blah " ** 50 ++ "hello there world";
86 var regex = try Regex.compile(allocator, "hello.*world");
84 var regex = try Regex.compile(init.gpa, "hello.*world");
8785 defer regex.deinit();
8886
8987 if (regex.opt_info.literal_prefix) |prefix| {
@@ -92,31 +90,31 @@ pub fn main() !void {
9290 std.debug.print(" ✗ No literal prefix found\n", .{});
9391 }
9492
95 var timer = try std.time.Timer.start();
96 const start = timer.read();
93 const start = std.Io.Timestamp.now(init.io, .real);
9794
9895 const iterations: usize = 10000;
9996 var i: usize = 0;
10097 while (i < iterations) : (i += 1) {
10198 if (try regex.find(text_with_hello)) |match| {
10299 var mut_match = match;
103 mut_match.deinit(allocator);
100 mut_match.deinit(init.gpa);
104101 }
105102 }
106103
107 const elapsed = timer.read() - start;
108 const avg_ns = elapsed / iterations;
104 const end = std.Io.Timestamp.now(init.io, .real);
105 const elapsed = start.durationTo(end);
106 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
109107 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
110108 iterations,
111 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
112 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
109 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
110 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
113111 });
114112 }
115113
116114 // Test 4: Anchored patterns
117115 {
118116 std.debug.print("Test 4: Start-anchored pattern (^hello)...\n", .{});
119 var regex = try Regex.compile(allocator, "^hello");
117 var regex = try Regex.compile(init.gpa, "^hello");
120118 defer regex.deinit();
121119
122120 if (regex.opt_info.anchored_start) {
@@ -127,8 +125,7 @@ pub fn main() !void {
127125 }
128126
129127 const text = "hello world";
130 var timer = try std.time.Timer.start();
131 const start = timer.read();
128 const start = std.Io.Timestamp.now(init.io, .real);
132129
133130 const iterations: usize = 10000;
134131 var i: usize = 0;
@@ -136,12 +133,13 @@ pub fn main() !void {
136133 _ = try regex.isMatch(text);
137134 }
138135
139 const elapsed = timer.read() - start;
140 const avg_ns = elapsed / iterations;
136 const end = std.Io.Timestamp.now(init.io, .real);
137 const elapsed = start.durationTo(end);
138 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
141139 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
142140 iterations,
143 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
144 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
141 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
142 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
145143 });
146144 }
147145
@@ -149,31 +147,31 @@ pub fn main() !void {
149147 {
150148 std.debug.print("Test 5: Email pattern (user@example.com)...\n", .{});
151149 const email_text = "Contact us at " ++ ("some filler text here. " ** 20) ++ "user@example.com for support";
152 var regex = try Regex.compile(allocator, "user@example.com");
150 var regex = try Regex.compile(init.gpa, "user@example.com");
153151 defer regex.deinit();
154152
155153 if (regex.opt_info.literal_prefix) |prefix| {
156 std.debug.print(" ✓ Using literal prefix: \"{s}\" (min_len={d})\n", .{prefix, regex.opt_info.min_length});
154 std.debug.print(" ✓ Using literal prefix: \"{s}\" (min_len={d})\n", .{ prefix, regex.opt_info.min_length });
157155 }
158156
159 var timer = try std.time.Timer.start();
160 const start = timer.read();
157 const start = std.Io.Timestamp.now(init.io, .real);
161158
162159 const iterations: usize = 10000;
163160 var i: usize = 0;
164161 while (i < iterations) : (i += 1) {
165162 if (try regex.find(email_text)) |match| {
166163 var mut_match = match;
167 mut_match.deinit(allocator);
164 mut_match.deinit(init.gpa);
168165 }
169166 }
170167
171 const elapsed = timer.read() - start;
172 const avg_ns = elapsed / iterations;
168 const end = std.Io.Timestamp.now(init.io, .real);
169 const elapsed = start.durationTo(end);
170 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
173171 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
174172 iterations,
175 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
176 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
173 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
174 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
177175 });
178176 }
179177
benchmarks/simple.zigmodified+34-34
Changes to benchmarks/simple.zig
@@ -1,45 +1,41 @@
11const std = ;
22const Regex = .Regex;
33
4pub fn main() !void {
5 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
6 defer _ = gpa.deinit();
7 const allocator = gpa.allocator();
8
4pub fn main(init: std.process.Init) !void {
95 std.debug.print("=== Simple Regex Benchmarks ===\n\n", .{});
106
117 // Test 1: Literal matching
128 {
139 std.debug.print("Test 1: Literal matching...\n", .{});
14 var regex = try Regex.compile(allocator, "hello");
10 var regex = try Regex.compile(init.gpa, "hello");
1511 defer regex.deinit();
1612
17 var timer = try std.time.Timer.start();
18 const start = timer.read();
19
13 const start = std.Io.Timestamp.now(init.io, .real);
2014 const iterations: usize = 10000;
2115 var i: usize = 0;
2216 while (i < iterations) : (i += 1) {
2317 _ = try regex.isMatch("hello world");
2418 }
2519
26 const elapsed = timer.read() - start;
27 const avg_ns = elapsed / iterations;
20 const end = std.Io.Timestamp.now(init.io, .real);
21 const elapsed = start.durationTo(end);
22
23 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
24
2825 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
2926 iterations,
30 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
31 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
27 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
28 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
3229 });
3330 }
3431
3532 // Test 2: Quantifiers
3633 {
3734 std.debug.print("Test 2: Quantifiers (a+)...\n", .{});
38 var regex = try Regex.compile(allocator, "a+");
35 var regex = try Regex.compile(init.gpa, "a+");
3936 defer regex.deinit();
4037
41 var timer = try std.time.Timer.start();
42 const start = timer.read();
38 const start = std.Io.Timestamp.now(init.io, .real);
4339
4440 const iterations: usize = 10000;
4541 var i: usize = 0;
@@ -47,23 +43,24 @@ pub fn main() !void {
4743 _ = try regex.isMatch("aaaa");
4844 }
4945
50 const elapsed = timer.read() - start;
51 const avg_ns = elapsed / iterations;
46 const end = std.Io.Timestamp.now(init.io, .real);
47 const elapsed = start.durationTo(end);
48 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
49
5250 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
5351 iterations,
54 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
55 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
52 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
53 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
5654 });
5755 }
5856
5957 // Test 3: Character classes
6058 {
6159 std.debug.print("Test 3: Digit matching (\\d+)...\n", .{});
62 var regex = try Regex.compile(allocator, "\\d+");
60 var regex = try Regex.compile(init.gpa, "\\d+");
6361 defer regex.deinit();
6462
65 var timer = try std.time.Timer.start();
66 const start = timer.read();
63 const start = std.Io.Timestamp.now(init.io, .real);
6764
6865 const iterations: usize = 10000;
6966 var i: usize = 0;
@@ -71,23 +68,24 @@ pub fn main() !void {
7168 _ = try regex.isMatch("12345");
7269 }
7370
74 const elapsed = timer.read() - start;
75 const avg_ns = elapsed / iterations;
71 const end = std.Io.Timestamp.now(init.io, .real);
72 const elapsed = start.durationTo(end);
73 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
74
7675 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
7776 iterations,
78 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
79 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
77 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
78 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
8079 });
8180 }
8281
8382 // Test 4: Case-insensitive
8483 {
8584 std.debug.print("Test 4: Case-insensitive matching...\n", .{});
86 var regex = try Regex.compileWithFlags(allocator, "hello", .{ .case_insensitive = true });
85 var regex = try Regex.compileWithFlags(init.gpa, "hello", .{ .case_insensitive = true });
8786 defer regex.deinit();
8887
89 var timer = try std.time.Timer.start();
90 const start = timer.read();
88 const start = std.Io.Timestamp.now(init.io, .real);
9189
9290 const iterations: usize = 10000;
9391 var i: usize = 0;
@@ -95,12 +93,14 @@ pub fn main() !void {
9593 _ = try regex.isMatch("HELLO");
9694 }
9795
98 const elapsed = timer.read() - start;
99 const avg_ns = elapsed / iterations;
96 const end = std.Io.Timestamp.now(init.io, .real);
97 const elapsed = start.durationTo(end);
98 const avg_ns = @divTrunc(elapsed.nanoseconds, iterations);
99
100100 std.debug.print(" {d} iterations in {d:.2}ms ({d:.2}µs/op)\n\n", .{
101101 iterations,
102 @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
103 @as(f64, @floatFromInt(avg_ns)) / 1000.0,
102 @as(f64, @floatFromInt(elapsed.toMilliseconds())),
103 @as(f64, @floatFromInt(avg_ns)) / std.time.us_per_ms,
104104 });
105105 }
106106
build.zigmodified+1-0
Changes to build.zig
@@ -39,6 +39,7 @@ pub fn build(b: *std.Build) void {
3939 // Later on we'll use this module as the root module of a test executable
4040 // which requires us to specify a target.
4141 .target = target,
42 .link_libc = true,
4243 });
4344
4445 // Here we define an executable. An executable needs to have a root module
examples/advanced_features.zigmodified+23-27
Changes to examples/advanced_features.zig
@@ -6,11 +6,7 @@ const Composer = .Composer;
66const Lint = .Lint;
77const ComplexityAnalyzer = .ComplexityAnalyzer;
88
9pub fn main() !void {
10 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
11 defer _ = gpa.deinit();
12 const allocator = gpa.allocator();
13
9pub fn main(init: std.process.Init) !void {
1410 std.debug.print("\n=== Advanced Regex Features Examples ===\n\n", .{});
1511
1612 // Example 1: Builder API - Type-safe pattern construction
@@ -19,7 +15,7 @@ pub fn main() !void {
1915 std.debug.print("Example 1: Builder API for Type-Safe Construction\n", .{});
2016 std.debug.print("───────────────────────────────────────────────\n", .{});
2117
22 var builder = Builder.init(allocator);
18 var builder = Builder.init(init.gpa);
2319 defer builder.deinit();
2420
2521 // Build a pattern for email validation
renamed throughout · 13 hidden lines
Changes to examples/advanced_features.zig
@@ -35,11 +31,11 @@ pub fn main() !void { renamed throughout
3531 _ = try builder.endOfLine();
3632
3733 const pattern = try builder.build();
38 defer allocator.free(pattern);
34 defer init.gpa.free(pattern);
3935
4036 std.debug.print("Built pattern: {s}\n", .{pattern});
4137
42 var regex = try Regex.compile(allocator, pattern);
38 var regex = try Regex.compile(init.gpa, pattern);
4339 defer regex.deinit();
4440
4541 const test_emails = [_][]const u8{
renamed throughout · 28 hidden lines
Changes to examples/advanced_features.zig
@@ -64,21 +60,21 @@ pub fn main() !void { renamed throughout
6460 std.debug.print("───────────────────────────────────────────────\n", .{});
6561
6662 // Use predefined patterns
67 const email_pattern = try Patterns.email(allocator);
68 defer allocator.free(email_pattern);
63 const email_pattern = try Patterns.email(init.gpa);
64 defer init.gpa.free(email_pattern);
6965
70 const url_pattern = try Patterns.url(allocator);
71 defer allocator.free(url_pattern);
66 const url_pattern = try Patterns.url(init.gpa);
67 defer init.gpa.free(url_pattern);
7268
73 const phone_pattern = try Patterns.phoneUS(allocator);
74 defer allocator.free(phone_pattern);
69 const phone_pattern = try Patterns.phoneUS(init.gpa);
70 defer init.gpa.free(phone_pattern);
7571
7672 std.debug.print("Email pattern: {s}\n", .{email_pattern});
7773 std.debug.print("URL pattern: {s}\n", .{url_pattern});
7874 std.debug.print("Phone pattern: {s}\n\n", .{phone_pattern});
7975
8076 // Test phone number pattern
81 var phone_regex = try Regex.compile(allocator, phone_pattern);
77 var phone_regex = try Regex.compile(init.gpa, phone_pattern);
8278 defer phone_regex.deinit();
8379
8480 const test_phones = [_][]const u8{
Changes to examples/advanced_features.zig
@@ -103,7 +99,7 @@ pub fn main() !void {
10399 std.debug.print("Example 3: Pattern Composition\n", .{});
104100 std.debug.print("───────────────────────────────────────────────\n", .{});
105101
106 var composer = Composer.init(allocator);
102 var composer = Composer.init(init.gpa);
107103 defer composer.deinit();
108104
109105 // Compose multiple patterns with OR
renamed throughout · 13 hidden lines
Changes to examples/advanced_features.zig
@@ -112,11 +108,11 @@ pub fn main() !void { renamed throughout
112108 _ = try composer.add("bird");
113109
114110 const alternatives = try composer.alternatives();
115 defer allocator.free(alternatives);
111 defer init.gpa.free(alternatives);
116112
117113 std.debug.print("Composed pattern (OR): {s}\n", .{alternatives});
118114
119 var regex = try Regex.compile(allocator, alternatives);
115 var regex = try Regex.compile(init.gpa, alternatives);
120116 defer regex.deinit();
121117
122118 const test_strings = [_][]const u8{
Changes to examples/advanced_features.zig
@@ -145,7 +141,7 @@ pub fn main() !void {
145141 const problematic_pattern = "(a+)+b";
146142 std.debug.print("Analyzing pattern: \"{s}\"\n\n", .{problematic_pattern});
147143
148 var lint = Lint.init(allocator, problematic_pattern);
144 var lint = Lint.init(init.gpa, problematic_pattern);
149145 defer lint.deinit();
150146
151147 try lint.analyze();
@@ -157,7 +153,7 @@ pub fn main() !void {
157153 const good_pattern = "^[a-z]+$";
158154 std.debug.print("Analyzing pattern: \"{s}\"\n\n", .{good_pattern});
159155
160 var lint2 = Lint.init(allocator, good_pattern);
156 var lint2 = Lint.init(init.gpa, good_pattern);
161157 defer lint2.deinit();
162158
163159 try lint2.analyze();
@@ -198,7 +194,7 @@ pub fn main() !void {
198194 std.debug.print("───────────────────────────────────────────────\n", .{});
199195
200196 // Build a complex pattern using the builder
201 var builder = Builder.init(allocator);
197 var builder = Builder.init(init.gpa);
202198 defer builder.deinit();
203199
204200 std.debug.print("Building a URL validator:\n", .{});
renamed throughout · 15 hidden lines
Changes to examples/advanced_features.zig
@@ -215,13 +211,13 @@ pub fn main() !void { renamed throughout
215211 _ = try builder.endOfLine();
216212
217213 const url_pattern_built = try builder.build();
218 defer allocator.free(url_pattern_built);
214 defer init.gpa.free(url_pattern_built);
219215
220216 std.debug.print("Built pattern: {s}\n\n", .{url_pattern_built});
221217
222218 // Lint the pattern
223219 std.debug.print("Linting the pattern:\n", .{});
224 var lint = Lint.init(allocator, url_pattern_built);
220 var lint = Lint.init(init.gpa, url_pattern_built);
225221 defer lint.deinit();
226222
227223 try lint.analyze();
Changes to examples/advanced_features.zig
@@ -232,7 +228,7 @@ pub fn main() !void {
232228 std.debug.print("Complexity: {s} (score: {d})\n\n", .{ @tagName(complexity.getLevel()), complexity.complexity_score });
233229
234230 // Test the pattern
235 var regex = try Regex.compile(allocator, url_pattern_built);
231 var regex = try Regex.compile(init.gpa, url_pattern_built);
236232 defer regex.deinit();
237233
238234 const test_urls = [_][]const u8{
@@ -257,7 +253,7 @@ pub fn main() !void {
257253 std.debug.print("Example 7: Complex Pattern with Builder\n", .{});
258254 std.debug.print("───────────────────────────────────────────────\n", .{});
259255
260 var builder = Builder.init(allocator);
256 var builder = Builder.init(init.gpa);
261257 defer builder.deinit();
262258
263259 // Build a pattern for matching IPv4 addresses
renamed throughout · 13 hidden lines
Changes to examples/advanced_features.zig
@@ -301,11 +297,11 @@ pub fn main() !void { renamed throughout
301297 _ = try builder.endOfLine();
302298
303299 const ipv4_pattern = try builder.build();
304 defer allocator.free(ipv4_pattern);
300 defer init.gpa.free(ipv4_pattern);
305301
306302 std.debug.print("Built pattern: {s}\n\n", .{ipv4_pattern});
307303
308 var regex = try Regex.compile(allocator, ipv4_pattern);
304 var regex = try Regex.compile(init.gpa, ipv4_pattern);
309305 defer regex.deinit();
310306
311307 const test_ips = [_][]const u8{
examples/basic.zigmodified+9-13
Changes to examples/basic.zig
@@ -1,17 +1,13 @@
11const std = ;
22const Regex = .Regex;
33
4pub fn main() !void {
5 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
6 defer _ = gpa.deinit();
7 const allocator = gpa.allocator();
8
4pub fn main(init: std.process.Init) !void {
95 std.debug.print("\n=== Zig Regex Examples ===\n\n", .{});
106
117 // Example 1: Simple literal matching
128 {
139 std.debug.print("Example 1: Literal matching\n", .{});
14 var regex = try Regex.compile(allocator, "hello");
10 var regex = try Regex.compile(init.gpa, "hello");
1511 defer regex.deinit();
1612
1713 const matches = try regex.isMatch("hello");
@@ -22,7 +18,7 @@ pub fn main() !void {
2218 // Example 2: Alternation
2319 {
2420 std.debug.print("Example 2: Alternation (cat|dog)\n", .{});
25 var regex = try Regex.compile(allocator, "cat|dog");
21 var regex = try Regex.compile(init.gpa, "cat|dog");
2622 defer regex.deinit();
2723
2824 std.debug.print(" 'cat' matches: {}\n", .{try regex.isMatch("cat")});
@@ -34,7 +30,7 @@ pub fn main() !void {
3430 // Example 3: Star quantifier
3531 {
3632 std.debug.print("Example 3: Star quantifier (a*)\n", .{});
37 var regex = try Regex.compile(allocator, "a*");
33 var regex = try Regex.compile(init.gpa, "a*");
3834 defer regex.deinit();
3935
4036 std.debug.print(" '' matches: {}\n", .{try regex.isMatch("")});
renamed throughout · 14 hidden lines
Changes to examples/basic.zig
@@ -46,12 +42,12 @@ pub fn main() !void { renamed throughout
4642 // Example 4: Finding matches
4743 {
4844 std.debug.print("Example 4: Finding matches\n", .{});
49 var regex = try Regex.compile(allocator, "world");
45 var regex = try Regex.compile(init.gpa, "world");
5046 defer regex.deinit();
5147
5248 if (try regex.find("hello world")) |match_result| {
5349 var mut_match = match_result;
54 defer mut_match.deinit(allocator);
50 defer mut_match.deinit(init.gpa);
5551 std.debug.print(" Found '{s}' at position {d}-{d}\n", .{ match_result.slice, match_result.start, match_result.end });
5652 }
5753 std.debug.print("\n", .{});
renamed throughout · 14 hidden lines
Changes to examples/basic.zig
@@ -60,11 +56,11 @@ pub fn main() !void { renamed throughout
6056 // Example 5: Replace
6157 {
6258 std.debug.print("Example 5: Replace\n", .{});
63 var regex = try Regex.compile(allocator, "world");
59 var regex = try Regex.compile(init.gpa, "world");
6460 defer regex.deinit();
6561
66 const result = try regex.replace(allocator, "hello world", "Zig");
67 defer allocator.free(result);
62 const result = try regex.replace(init.gpa, "hello world", "Zig");
63 defer init.gpa.free(result);
6864
6965 std.debug.print(" Replaced: '{s}'\n", .{result});
7066 std.debug.print("\n", .{});
examples/debug_visualization.zigmodified+7-11
Changes to examples/debug_visualization.zig
@@ -4,11 +4,7 @@ const debug = .debug;
44const Parser = .parser.Parser;
55const Optimizer = .optimizer.Optimizer;
66
7pub fn main() !void {
8 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
9 defer _ = gpa.deinit();
10 const allocator = gpa.allocator();
11
7pub fn main(init: std.process.Init) !void {
128 std.debug.print("\n=== Regex Debugging and Analysis Examples ===\n\n", .{});
139
1410 const patterns = [_][]const u8{
@@ -25,7 +21,7 @@ pub fn main() !void {
2521 std.debug.print("───────────────────────────────────────────────\n", .{});
2622
2723 // Example 1: Show optimization info
28 var regex = Regex.compile(allocator, pattern) catch |err| {
24 var regex = Regex.compile(init.gpa, pattern) catch |err| {
2925 std.debug.print(" ❌ Compilation error: {}\n\n", .{err});
3026 continue;
3127 };
renamed throughout · 19 hidden lines
Changes to examples/debug_visualization.zig
@@ -54,15 +50,15 @@ pub fn main() !void { renamed throughout
5450
5551 // Example 2: Pattern analysis
5652 {
57 var parser = Parser.init(allocator, pattern) catch continue;
53 var parser = Parser.init(init.gpa, pattern) catch continue;
5854 var tree = parser.parse() catch continue;
5955 defer tree.deinit();
6056
61 var opt = Optimizer.init(allocator);
57 var opt = Optimizer.init(init.gpa);
6258 var opt_info = try opt.analyze(tree.root);
63 defer opt_info.deinit(allocator);
59 defer opt_info.deinit(init.gpa);
6460
65 var analyzer = debug.PatternAnalyzer.init(allocator);
61 var analyzer = debug.PatternAnalyzer.init(init.gpa);
6662 var analysis = try analyzer.analyze(pattern, &tree, &opt_info);
6763 defer analysis.deinit();
6864
Changes to examples/debug_visualization.zig
@@ -88,7 +84,7 @@ pub fn main() !void {
8884 std.debug.print("───────────────────────────────────────────────\n", .{});
8985
9086 const test_pattern = "hello.*world";
91 var test_regex = try Regex.compile(allocator, test_pattern);
87 var test_regex = try Regex.compile(init.gpa, test_pattern);
9288 defer test_regex.deinit();
9389
9490 const test_inputs = [_][]const u8{
examples/error_handling.zigmodified+11-15
Changes to examples/error_handling.zig
@@ -4,20 +4,16 @@ const ErrorContext = .ErrorContext;
44const ErrorHelper = .ErrorHelper;
55const RegexError = .RegexError;
66
7pub fn main() !void {
8 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
9 defer _ = gpa.deinit();
10 const allocator = gpa.allocator();
11
7pub fn main(init: std.process.Init) !void {
128 std.debug.print("\n=== Regex Error Handling Examples ===\n\n", .{});
139
1410 // Example 1: Invalid patterns with helpful error messages
1511 const invalid_patterns = [_][]const u8{
16 "abc(def", // Unmatched parenthesis
17 "abc[def", // Unmatched bracket
18 "abc+(", // Invalid quantifier usage
19 "abc\\q", // Invalid escape sequence
20 "[z-a]", // Invalid character range
12 "abc(def", // Unmatched parenthesis
13 "abc[def", // Unmatched bracket
14 "abc+(", // Invalid quantifier usage
15 "abc\\q", // Invalid escape sequence
16 "[z-a]", // Invalid character range
2117 "(a(b(c(d(e(f(g(h(i(j(k(l(m(n(o(p(q", // Too many nested groups
2218 };
2319
@@ -26,7 +22,7 @@ pub fn main() !void {
2622 std.debug.print("Testing pattern: \"{s}\"\n", .{pattern});
2723 std.debug.print("───────────────────────────────────────────────\n", .{});
2824
29 if (Regex.compile(allocator, pattern)) |regex_value| {
25 if (Regex.compile(init.gpa, pattern)) |regex_value| {
3026 var regex = regex_value;
3127 defer regex.deinit();
3228 std.debug.print("✓ Pattern compiled successfully (unexpected)\n\n", .{});
@@ -53,7 +49,7 @@ pub fn main() !void {
5349 const user_pattern = "hello|world";
5450 std.debug.print("User provided pattern: \"{s}\"\n", .{user_pattern});
5551
56 if (Regex.compile(allocator, user_pattern)) |regex_value| {
52 if (Regex.compile(init.gpa, user_pattern)) |regex_value| {
5753 var regex = regex_value;
5854 defer regex.deinit();
5955 std.debug.print("✓ Pattern compiled successfully\n", .{});
@@ -84,7 +80,7 @@ pub fn main() !void {
8480 const problematic_pattern = "abc[def";
8581 std.debug.print("Problematic pattern: \"{s}\"\n", .{problematic_pattern});
8682
87 if (Regex.compile(allocator, problematic_pattern)) |regex_value| {
83 if (Regex.compile(init.gpa, problematic_pattern)) |regex_value| {
8884 var regex = regex_value;
8985 regex.deinit();
9086 } else |err| {
@@ -95,7 +91,7 @@ pub fn main() !void {
9591 const fixed_pattern = "abc[def]";
9692 std.debug.print("Fixed pattern: \"{s}\"\n", .{fixed_pattern});
9793
98 if (Regex.compile(allocator, fixed_pattern)) |regex_value| {
94 if (Regex.compile(init.gpa, fixed_pattern)) |regex_value| {
9995 var regex = regex_value;
10096 defer regex.deinit();
10197 std.debug.print("✓ Fixed pattern compiles successfully!\n", .{});
@@ -119,7 +115,7 @@ pub fn main() !void {
119115
120116 for (patterns_to_validate) |pattern| {
121117 std.debug.print("Validating: \"{s}\" ... ", .{pattern});
122 if (Regex.compile(allocator, pattern)) |regex_value| {
118 if (Regex.compile(init.gpa, pattern)) |regex_value| {
123119 var regex = regex_value;
124120 regex.deinit();
125121 std.debug.print("✓ Valid\n", .{});
examples/profiling_example.zigmodified+33-36
Changes to examples/profiling_example.zig
@@ -3,11 +3,7 @@ const Regex = .Regex;
33const Profiler = .Profiler;
44const ScopedTimer = .ScopedTimer;
55
6pub fn main() !void {
7 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
8 defer _ = gpa.deinit();
9 const allocator = gpa.allocator();
10
6pub fn main(init: std.process.Init) !void {
117 std.debug.print("\n=== Regex Profiling Examples ===\n\n", .{});
128
139 // Example 1: Basic profiling
@@ -16,12 +12,12 @@ pub fn main() !void {
1612 std.debug.print("Example 1: Basic profiling\n", .{});
1713 std.debug.print("───────────────────────────────────────────────\n", .{});
1814
19 var profiler = Profiler.init(allocator, true);
15 var profiler = Profiler.init(init.gpa, init.io, true);
2016
2117 // Profile compilation
22 profiler.startCompilation();
23 var regex = try Regex.compile(allocator, "hello.*world");
24 profiler.endCompilation();
18 profiler.startCompilation(init.io);
19 var regex = try Regex.compile(init.gpa, "hello.*world");
20 profiler.endCompilation(init.io);
2521 defer regex.deinit();
2622
2723 // Profile multiple matches
@@ -33,9 +29,9 @@ pub fn main() !void {
3329 };
3430
3531 for (test_inputs) |input| {
36 profiler.startMatch();
32 profiler.startMatch(init.io);
3733 _ = try regex.isMatch(input);
38 profiler.endMatch();
34 profiler.endMatch(init.io);
3935 }
4036
4137 std.debug.print("\n", .{});
@@ -48,13 +44,13 @@ pub fn main() !void {
4844 std.debug.print("Example 2: Scoped timers\n", .{});
4945 std.debug.print("───────────────────────────────────────────────\n", .{});
5046
51 var profiler = Profiler.init(allocator, true);
47 var profiler = Profiler.init(init.gpa, init.io, true);
5248
5349 {
54 var timer = ScopedTimer.init(&profiler, .compilation);
55 defer timer.deinit();
50 var timer = ScopedTimer.init(&profiler, init.io, .compilation);
51 defer timer.deinit(init.io);
5652
57 var regex = try Regex.compile(allocator, "[a-z]+@[a-z]+\\.[a-z]+");
53 var regex = try Regex.compile(init.gpa, "[a-z]+@[a-z]+\\.[a-z]+");
5854 regex.deinit();
5955 }
6056
@@ -69,33 +65,34 @@ pub fn main() !void {
6965 std.debug.print("───────────────────────────────────────────────\n", .{});
7066
7167 const patterns = [_][]const u8{
72 "hello", // Literal - should have prefix optimization
73 ".*hello", // No prefix - slower
74 "hello.*world", // Prefix optimization
68 "hello", // Literal - should have prefix optimization
69 ".*hello", // No prefix - slower
70 "hello.*world", // Prefix optimization
7571 };
7672
7773 const test_text = ("some random text " ** 10) ++ "hello world";
7874
7975 for (patterns) |pattern| {
80 var profiler = Profiler.init(allocator, true);
76 var profiler = Profiler.init(init.gpa, init.io, true);
8177
8278 std.debug.print("\nPattern: \"{s}\"\n", .{pattern});
8379
84 var regex = try Regex.compile(allocator, pattern);
80 var regex = try Regex.compile(init.gpa, pattern);
8581 defer regex.deinit();
8682
8783 // Run multiple matches
8884 const iterations = 1000;
8985 var i: usize = 0;
9086 while (i < iterations) : (i += 1) {
91 profiler.startMatch();
87 profiler.startMatch(init.io);
9288 _ = try regex.isMatch(test_text);
93 profiler.endMatch();
89 profiler.endMatch(init.io);
9490 }
9591
9692 const metrics = profiler.getMetrics();
97 const avg_ns = metrics.match_time_ns / iterations;
98 std.debug.print("Average match time: {d}μs ({d} iterations)\n", .{ avg_ns / 1000, iterations });
93 // TODO: figure out if this is correct
94 const avg_ns = @divTrunc(metrics.match_time_ns, iterations);
95 std.debug.print("Average match time: {d}μs ({d} iterations)\n", .{ @divTrunc(avg_ns, 1000), iterations });
9996 }
10097 }
10198
@@ -105,12 +102,12 @@ pub fn main() !void {
105102 std.debug.print("Example 4: Memory tracking\n", .{});
106103 std.debug.print("───────────────────────────────────────────────\n", .{});
107104
108 var profiler = Profiler.init(allocator, true);
105 var profiler = Profiler.init(init.gpa, init.io, true);
109106
110107 const complex_pattern = "(a|b)+c(d|e)*f";
111108 std.debug.print("Pattern: \"{s}\"\n", .{complex_pattern});
112109
113 var regex = try Regex.compile(allocator, complex_pattern);
110 var regex = try Regex.compile(init.gpa, complex_pattern);
114111 defer regex.deinit();
115112
116113 // Simulate memory tracking (in real implementation, this would be integrated)
@@ -131,30 +128,30 @@ pub fn main() !void {
131128 const test_pattern = "hello";
132129
133130 // Baseline
134 var baseline_profiler = Profiler.init(allocator, true);
131 var baseline_profiler = Profiler.init(init.gpa, init.io, true);
135132 {
136 var regex = try Regex.compile(allocator, baseline_pattern);
133 var regex = try Regex.compile(init.gpa, baseline_pattern);
137134 defer regex.deinit();
138135
139136 var i: usize = 0;
140137 while (i < 100) : (i += 1) {
141 baseline_profiler.startMatch();
138 baseline_profiler.startMatch(init.io);
142139 _ = try regex.isMatch("hello world");
143 baseline_profiler.endMatch();
140 baseline_profiler.endMatch(init.io);
144141 }
145142 }
146143
147144 // Test
148 var test_profiler = Profiler.init(allocator, true);
145 var test_profiler = Profiler.init(init.gpa, init.io, true);
149146 {
150 var regex = try Regex.compile(allocator, test_pattern);
147 var regex = try Regex.compile(init.gpa, test_pattern);
151148 defer regex.deinit();
152149
153150 var i: usize = 0;
154151 while (i < 100) : (i += 1) {
155 test_profiler.startMatch();
152 test_profiler.startMatch(init.io);
156153 _ = try regex.isMatch("hello world");
157 test_profiler.endMatch();
154 test_profiler.endMatch(init.io);
158155 }
159156 }
160157
@@ -162,8 +159,8 @@ pub fn main() !void {
162159 const test_time = test_profiler.getMetrics().match_time_ns;
163160 const diff_percent = @as(f64, @floatFromInt(test_time)) / @as(f64, @floatFromInt(baseline_time)) * 100.0 - 100.0;
164161
165 std.debug.print("\nBaseline time: {d}μs\n", .{baseline_time / 1000});
166 std.debug.print("Test time: {d}μs\n", .{test_time / 1000});
162 std.debug.print("\nBaseline time: {d}μs\n", .{@divTrunc(baseline_time, 1000)});
163 std.debug.print("Test time: {d}μs\n", .{@divTrunc(test_time, 1000)});
167164 std.debug.print("Difference: {d:.1}%\n", .{diff_percent});
168165
169166 if (diff_percent > 10.0) {
examples/thread_safety.zigmodified+22-23
Changes to examples/thread_safety.zig
@@ -3,11 +3,7 @@ const Regex = .Regex;
33const SharedRegex = .SharedRegex;
44const RegexCache = .RegexCache;
55
6pub fn main() !void {
7 var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){};
8 defer _ = gpa.deinit();
9 const allocator = gpa.allocator();
10
6pub fn main(init: std.process.Init) !void {
117 std.debug.print("\n=== Regex Thread Safety Examples ===\n\n", .{});
128
139 // Example 1: Basic concurrent matching
@@ -17,7 +13,7 @@ pub fn main() !void {
1713 std.debug.print("───────────────────────────────────────────────\n", .{});
1814
1915 // Compile once
20 var regex = try Regex.compile(allocator, "\\d+");
16 var regex = try Regex.compile(init.gpa, "\\d+");
2117 defer regex.deinit();
2218
2319 const Worker = struct {
@@ -63,7 +59,7 @@ pub fn main() !void {
6359 std.debug.print("Example 2: SharedRegex with reference counting\n", .{});
6460 std.debug.print("───────────────────────────────────────────────\n", .{});
6561
66 var shared = try SharedRegex.init(allocator, "test");
62 var shared = try SharedRegex.init(init.gpa, "test");
6763 defer shared.deinit();
6864
6965 const Worker = struct {
@@ -128,7 +124,7 @@ pub fn main() !void {
128124 var threads: [thread_count]std.Thread = undefined;
129125
130126 for (&threads, 0..) |*thread, i| {
131 thread.* = try std.Thread.spawn(.{}, Worker.run, .{ allocator, i });
127 thread.* = try std.Thread.spawn(.{}, Worker.run, .{ init.gpa, i });
132128 }
133129
134130 for (threads) |thread| {
@@ -144,12 +140,12 @@ pub fn main() !void {
144140 std.debug.print("Example 4: Performance with concurrent matching\n", .{});
145141 std.debug.print("───────────────────────────────────────────────\n", .{});
146142
147 var regex = try Regex.compile(allocator, "test");
143 var regex = try Regex.compile(init.gpa, "test");
148144 defer regex.deinit();
149145
150146 const Worker = struct {
151 fn run(r: *const Regex) usize {
152 var timer = std.time.Timer.start() catch return 0;
147 fn run(r: *const Regex, io: std.Io) i64 {
148 const start = std.Io.Timestamp.now(io, .real);
153149
154150 var count: usize = 0;
155151 var i: usize = 0;
@@ -159,37 +155,40 @@ pub fn main() !void {
159155 } else |_| {}
160156 }
161157
162 const elapsed_ms = timer.read() / 1_000_000;
163 return elapsed_ms;
158 const end = std.Io.Timestamp.now(io, .real);
159 const elapsed = start.durationTo(end);
160 return elapsed.toMilliseconds();
164161 }
165162 };
166163
167164 // Sequential baseline
168 const sequential_time = Worker.run(&regex);
165 const sequential_time = Worker.run(&regex, init.io);
169166 std.debug.print("Sequential: 10,000 matches in {d}ms\n", .{sequential_time});
170167
171168 // Parallel execution
172169 const thread_count = 4;
173170 var threads: [thread_count]std.Thread = undefined;
174 var times: [thread_count]usize = undefined;
171 var times: [thread_count]i64 = undefined;
175172
176173 const ParallelWorker = struct {
177 fn run(r: *const Regex, time_ptr: *usize) void {
178 time_ptr.* = Worker.run(r);
174 fn run(r: *const Regex, io: std.Io, time_ptr: *i64) void {
175 time_ptr.* = Worker.run(r, io);
179176 }
180177 };
181178
182 var parallel_timer = try std.time.Timer.start();
179 // TODO: there is probably a better/correct-er way to do this with io
180 const start = std.Io.Timestamp.now(init.io, .real);
183181
184182 for (&threads, 0..) |*thread, i| {
185 thread.* = try std.Thread.spawn(.{}, ParallelWorker.run, .{ &regex, &times[i] });
183 thread.* = try std.Thread.spawn(.{}, ParallelWorker.run, .{ &regex, init.io, &times[i] });
186184 }
187185
188186 for (threads) |thread| {
189187 thread.join();
190188 }
191189
192 const total_parallel = parallel_timer.read() / 1_000_000;
190 const end = std.Io.Timestamp.now(init.io, .real);
191 const total_parallel = start.durationTo(end).toMilliseconds();
193192
194193 std.debug.print("Parallel ({d} threads): 40,000 matches in {d}ms\n", .{ thread_count, total_parallel });
195194 std.debug.print("Individual thread times: ", .{});
renamed throughout · 16 hidden lines
Changes to examples/thread_safety.zig
@@ -206,13 +205,13 @@ pub fn main() !void { renamed throughout
206205 std.debug.print("Example 5: Multiple patterns with concurrent access\n", .{});
207206 std.debug.print("───────────────────────────────────────────────\n", .{});
208207
209 var email_regex = try Regex.compile(allocator, "[a-z]+@[a-z]+\\.[a-z]+");
208 var email_regex = try Regex.compile(init.gpa, "[a-z]+@[a-z]+\\.[a-z]+");
210209 defer email_regex.deinit();
211210
212 var phone_regex = try Regex.compile(allocator, "\\d{3}-\\d{4}");
211 var phone_regex = try Regex.compile(init.gpa, "\\d{3}-\\d{4}");
213212 defer phone_regex.deinit();
214213
215 var url_regex = try Regex.compile(allocator, "https?://");
214 var url_regex = try Regex.compile(init.gpa, "https?://");
216215 defer url_regex.deinit();
217216
218217 const Worker = struct {
src/builder.zigmodified+2-2
Changes to src/builder.zig
@@ -29,7 +29,7 @@ pub const Builder = struct {
2929 pub fn init(allocator: std.mem.Allocator) Builder {
3030 return .{
3131 .allocator = allocator,
32 .parts = std.ArrayList([]const u8){},
32 .parts = .empty,
3333 };
3434 }
3535
@@ -304,7 +304,7 @@ pub const Composer = struct {
304304 pub fn init(allocator: std.mem.Allocator) Composer {
305305 return .{
306306 .allocator = allocator,
307 .patterns = std.ArrayList([]const u8){},
307 .patterns = .empty,
308308 };
309309 }
310310
src/lint.zigmodified+1-1
Changes to src/lint.zig
@@ -63,7 +63,7 @@ pub const Lint = struct {
6363 pub fn init(allocator: std.mem.Allocator, pattern: []const u8) Lint {
6464 return .{
6565 .allocator = allocator,
66 .warnings = std.ArrayList(Warning){},
66 .warnings = .empty,
6767 .pattern = pattern,
6868 };
6969 }
src/profiling.zigmodified+32-29
Changes to src/profiling.zig
@@ -5,11 +5,11 @@ pub const Profiler = struct {
55 allocator: std.mem.Allocator,
66 enabled: bool,
77 metrics: Metrics,
8 start_time: ?std.time.Instant,
8 start_time: ?std.Io.Timestamp,
99
1010 pub const Metrics = struct {
11 compilation_time_ns: u64 = 0,
12 match_time_ns: u64 = 0,
11 compilation_time_ns: i96 = 0,
12 match_time_ns: i96 = 0,
1313 match_count: usize = 0,
1414 nfa_states_created: usize = 0,
1515 backtrack_count: usize = 0,
@@ -49,41 +49,42 @@ pub const Profiler = struct {
4949 }
5050 };
5151
52 pub fn init(allocator: std.mem.Allocator, enabled: bool) Profiler {
52 pub fn init(allocator: std.mem.Allocator, io: std.Io, enabled: bool) Profiler {
5353 return .{
5454 .allocator = allocator,
5555 .enabled = enabled,
5656 .metrics = Metrics{},
57 .start_time = if (enabled) std.time.Instant.now() catch null else null,
57 // TODO: No clue what to actually pass as a clock
58 .start_time = if (enabled) std.Io.Timestamp.now(io, .real) else null,
5859 };
5960 }
6061
6162 /// Start timing a compilation phase
62 pub fn startCompilation(self: *Profiler) void {
63 pub fn startCompilation(self: *Profiler, io: std.Io) void {
6364 if (!self.enabled) return;
64 self.start_time = std.time.Instant.now() catch null;
65 self.start_time = std.Io.Timestamp.now(io, .real);
6566 }
6667
6768 /// End timing a compilation phase
68 pub fn endCompilation(self: *Profiler) void {
69 pub fn endCompilation(self: *Profiler, io: std.Io) void {
6970 if (!self.enabled) return;
7071 const start = self.start_time orelse return;
71 const now = std.time.Instant.now() catch return;
72 self.metrics.compilation_time_ns += now.since(start);
72 const now = std.Io.Timestamp.now(io, .real);
73 self.metrics.compilation_time_ns += start.durationTo(now).nanoseconds;
7374 }
7475
7576 /// Start timing a match operation
76 pub fn startMatch(self: *Profiler) void {
77 pub fn startMatch(self: *Profiler, io: std.Io) void {
7778 if (!self.enabled) return;
78 self.start_time = std.time.Instant.now() catch null;
79 self.start_time = std.Io.Timestamp.now(io, .real);
7980 }
8081
8182 /// End timing a match operation
82 pub fn endMatch(self: *Profiler) void {
83 pub fn endMatch(self: *Profiler, io: std.Io) void {
8384 if (!self.enabled) return;
8485 const start = self.start_time orelse return;
85 const now = std.time.Instant.now() catch return;
86 self.metrics.match_time_ns += now.since(start);
86 const now = std.Io.Timestamp.now(io, .real);
87 self.metrics.match_time_ns += start.durationTo(now).nanoseconds;
8788 self.metrics.match_count += 1;
8889 }
8990
@@ -140,9 +141,9 @@ pub const Profiler = struct {
140141 }
141142
142143 /// Reset all metrics
143 pub fn reset(self: *Profiler) void {
144 pub fn reset(self: *Profiler, io: std.Io) void {
144145 self.metrics.reset();
145 self.start_time = if (self.enabled) std.time.Instant.now() catch null else null;
146 self.start_time = if (self.enabled) std.Io.Timestamp.now(io, .real);
146147 }
147148
148149 /// Print metrics to stderr
@@ -156,26 +157,26 @@ pub const Profiler = struct {
156157pub const ScopedTimer = struct {
157158 profiler: *Profiler,
158159 timer_type: TimerType,
159 start: ?std.time.Instant,
160 start: ?std.Io.Timestamp,
160161
161162 pub const TimerType = enum {
162163 compilation,
163164 match,
164165 };
165166
166 pub fn init(profiler: *Profiler, timer_type: TimerType) ScopedTimer {
167 pub fn init(profiler: *Profiler, io: std.Io, timer_type: TimerType) ScopedTimer {
167168 return .{
168169 .profiler = profiler,
169170 .timer_type = timer_type,
170 .start = if (profiler.enabled) std.time.Instant.now() catch null else null,
171 .start = if (profiler.enabled) std.Io.Timestamp.now(io, .real) else null,
171172 };
172173 }
173174
174 pub fn deinit(self: *ScopedTimer) void {
175 pub fn deinit(self: *ScopedTimer, io: std.Io) void {
175176 if (!self.profiler.enabled) return;
176177 const start = self.start orelse return;
177 const now = std.time.Instant.now() catch return;
178 const elapsed = now.since(start);
178 const now = std.Io.Timestamp.now(io, .real);
179 const elapsed = start.durationTo(now).nanoseconds;
179180 switch (self.timer_type) {
180181 .compilation => self.profiler.metrics.compilation_time_ns += elapsed,
181182 .match => {
@@ -188,15 +189,16 @@ pub const ScopedTimer = struct {
188189
189190test "profiler basic operations" {
190191 const allocator = std.testing.allocator;
191 var profiler = Profiler.init(allocator, true);
192 const io = std.testing.io;
193 var profiler = Profiler.init(allocator, io, true);
192194
193 profiler.startCompilation();
195 profiler.startCompilation(io);
194196 // Do some work (just loop to consume time)
195197 var i: usize = 0;
196198 while (i < 1000) : (i += 1) {
197199 _ = i * i;
198200 }
199 profiler.endCompilation();
201 profiler.endCompilation(io);
200202
201203 profiler.recordStateCreation(5);
202204 profiler.recordBacktrack();
@@ -210,11 +212,12 @@ test "profiler basic operations" {
210212
211213test "scoped timer" {
212214 const allocator = std.testing.allocator;
213 var profiler = Profiler.init(allocator, true);
215 const io = std.testing.io;
216 var profiler = Profiler.init(allocator, io, true);
214217
215218 {
216 var timer = ScopedTimer.init(&profiler, .match);
217 defer timer.deinit();
219 var timer = ScopedTimer.init(&profiler, io, .match);
220 defer timer.deinit(io);
218221 // Do some work
219222 var i: usize = 0;
220223 while (i < 1000) : (i += 1) {
tests/thread_safety.zigmodified+4-3
Changes to tests/thread_safety.zig
@@ -191,7 +191,8 @@ test "RegexCache basic operations" {
191191
192192test "thread-safe allocator with concurrent matching" {
193193 // Use thread-safe allocator for concurrent access
194 var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){};
194 var gpa = std.heap.DebugAllocator(.{ .thread_safe = true }){};
195 // TODO: can use this for leak detection
195196 defer _ = gpa.deinit();
196197 const allocator = gpa.allocator();
197198
@@ -222,7 +223,7 @@ test "thread-safe allocator with concurrent matching" {
222223}
223224
224225test "concurrent matching different patterns" {
225 var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){};
226 var gpa = std.heap.DebugAllocator(.{ .thread_safe = true }){};
226227 defer _ = gpa.deinit();
227228 const allocator = gpa.allocator();
228229
@@ -272,7 +273,7 @@ test "concurrent matching different patterns" {
272273}
273274
274275test "stress test: many threads many matches" {
275 var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){};
276 var gpa = std.heap.DebugAllocator(.{ .thread_safe = true }){};
276277 defer _ = gpa.deinit();
277278 const allocator = gpa.allocator();
278279