aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/argument.zig21
-rw-r--r--src/main.zig55
-rw-r--r--src/scheduler.zig60
3 files changed, 113 insertions, 23 deletions
diff --git a/src/argument.zig b/src/argument.zig
index 37d9045..b553352 100644
--- a/src/argument.zig
+++ b/src/argument.zig
@@ -22,6 +22,8 @@ fn help(err: ?anyerror) noreturn {
\\
\\ -n, --non-empty Only output texts which are non-empty.
\\
+ \\ -m, --min-length n Minimum length of sentential string.
+ \\
\\ recognize [grammar] [options]
\\ Options:
\\ -i, --input entry Specify input source, if the path
@@ -74,12 +76,13 @@ pub const Entry = struct {
name: []const u8,
file: std.fs.File,
- pub fn open(path: []const u8, flags: std.fs.File.OpenFlags) Self {
+ pub fn open(path: []const u8, writer: bool) Self {
var cwd = std.fs.cwd();
return Self {
.name = path,
- .file = cwd.openFile(path, flags) catch |e| help(e)
+ .file = (if (writer) cwd.createFile(path, .{})
+ else cwd.openFile(path, .{})) catch |e| help(e)
};
}
@@ -115,7 +118,7 @@ pub const RecognizeArgs = struct {
pub const GenerateArgs = struct {
count: usize,
- empty: bool,
+ min_length: usize,
output: Entry,
grammar: Grammar,
};
@@ -145,7 +148,7 @@ pub const Args = union(Mode) {
while (args.next()) |arg| {
if (check_flags(arg, &[_][]const u8 { "-i", "--input" })) {
- input = Entry.open(check(args.next()), .{});
+ input = Entry.open(check(args.next()), false);
} else help(error.InvalidArgument);
}
@@ -160,22 +163,24 @@ pub const Args = union(Mode) {
.generate => {
var count: usize = 1;
var output: ?Entry = null;
- var empty: bool = true;
+ var min_length: usize = 0;
while (args.next()) |arg| {
if (check_flags(arg, &[_][]const u8 { "-o", "--output" })) {
- output = Entry.open(check(args.next()), .{ .mode = .write_only });
+ output = Entry.open(check(args.next()), true);
} else if (check_flags(arg, &[_][]const u8 { "-c", "--count" })) {
count = parse_int(check(args.next()));
} else if (check_flags(arg, &[_][]const u8 { "-n", "--non-empty" })) {
- empty = false;
+ min_length = 1;
+ } else if (check_flags(arg, &[_][]const u8 { "-m", "--min-length" })) {
+ min_length = parse_int(check(args.next()));
} else help(error.InvalidArgument);
}
return Self {
.generate = .{
.count = count,
- .empty = empty,
+ .min_length = min_length,
.output = output orelse Entry.stdout(),
.grammar = grammar,
},
diff --git a/src/main.zig b/src/main.zig
index c1d63c0..ac52f8a 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -4,6 +4,7 @@ pub const gss = @import("gss.zig");
pub const recognizer = @import("recognizer.zig");
pub const argument = @import("argument.zig");
pub const Generator = @import("generator.zig").Generator;
+pub const Scheduler = @import("scheduler.zig").Scheduler;
const Args = argument.Args;
const RecognizeArgs = argument.RecognizeArgs;
@@ -83,26 +84,50 @@ fn recognize(args: *RecognizeArgs, allocator: std.mem.Allocator) !void {
try bufwriter.flush();
}
-fn generate(args: *GenerateArgs, allocator: std.mem.Allocator) !void {
- var writer = args.output.file.writer();
- var count: usize = 0;
+const RandomGenerator = Generator(struct {
+ const Self = @This();
- var generator = Generator(struct {
- const Self = @This();
+ pub fn next(_: *Self, n: usize) usize {
+ return std.crypto.random.uintLessThan(usize, n);
+ }
+});
- pub fn next(_: *Self, n: usize) usize {
- return std.crypto.random.uintLessThan(usize, n);
+pub fn generate_word(
+ args: *GenerateArgs,
+ generator: *RandomGenerator,
+ allocator: std.mem.Allocator
+) []const u8 {
+ while (true) {
+ const text = generator.sentential_from_grammar(
+ &args.grammar,
+ 10000,
+ allocator
+ ) catch continue;
+ if (text.len >= args.min_length) {
+ return text;
}
- }){};
- while (count < args.count) {
- const text = try generator.sentential_from_grammar(&args.grammar, 1000, allocator);
- defer allocator.free(text);
+ allocator.free(text);
+ }
+}
- if (args.empty or text.len > 0) {
- try writer.print("{s}\n", .{text});
- count += 1;
- }
+fn generate(args: *GenerateArgs, allocator: std.mem.Allocator) !void {
+ var writer = args.output.file.writer();
+
+ var scheduler: Scheduler(generate_word) = undefined;
+ try scheduler.init(allocator);
+ var generator = RandomGenerator {};
+
+ for (0..args.count) |_| {
+ try scheduler.push_task(.{args, &generator, allocator});
+ }
+
+ const results = try scheduler.deinit();
+ defer allocator.free(results);
+
+ for (results) |result| {
+ try writer.print("{s}\n", .{result});
+ allocator.free(result);
}
}
diff --git a/src/scheduler.zig b/src/scheduler.zig
new file mode 100644
index 0000000..b2ab0db
--- /dev/null
+++ b/src/scheduler.zig
@@ -0,0 +1,60 @@
+const std = @import("std");
+
+pub fn Scheduler(function: anytype) type {
+ const FuncType = @TypeOf(function);
+ const func_info = @typeInfo(FuncType).Fn;
+ const R = func_info.return_type orelse std.builtin.Type.Void;
+ const ArgType = std.meta.ArgsTuple(FuncType);
+
+ const wrapper = struct {
+ pub fn call(args: ArgType, result: *R) void {
+ result.* = @call(.auto, function, args);
+ }
+ }.call;
+
+ return struct {
+ const Self = @This();
+
+ allocator: std.mem.Allocator,
+ pool: std.Thread.Pool,
+ wait_group: std.Thread.WaitGroup,
+ results: std.ArrayList(*R),
+
+ pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
+ self.allocator = allocator;
+ self.results = std.ArrayList(*R).init(allocator);
+ self.wait_group.reset();
+
+ try self.pool.init(.{
+ .allocator = allocator,
+ });
+ }
+
+ pub fn push_task(self: *Self, args: ArgType) !void {
+ const result = try self.allocator.create(R);
+ try self.results.append(result);
+ self.pool.spawnWg(
+ &self.wait_group,
+ wrapper,
+ .{ args, result }
+ );
+ }
+
+ pub fn deinit(self: *Self) ![]R {
+ self.pool.waitAndWork(&self.wait_group);
+ self.pool.deinit();
+
+ const results = try self.allocator.alloc(R, self.results.items.len);
+
+ for (self.results.items, 0..) |result, index| {
+ results[index] = result.*;
+ self.allocator.destroy(result);
+ }
+
+ self.results.deinit();
+ self.* = undefined;
+
+ return results;
+ }
+ };
+}