From 79f0c9cee9e5cd4413a65ae96a32872330e308ad Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 14 Mar 2018 21:36:50 +0100 Subject: Refactored clap to use inline loops where possible. Time to study the differences in the assemply --- clap.zig | 110 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 47 deletions(-) (limited to 'clap.zig') diff --git a/clap.zig b/clap.zig index f390229..6e3e7a8 100644 --- a/clap.zig +++ b/clap.zig @@ -22,16 +22,16 @@ pub fn Option(comptime Result: type, comptime ParseError: type) type { IgnoresRequired }; - parser: fn(&Result, []const u8) ParseError!void, + parse: fn(&Result, []const u8) ParseError!void, help: []const u8, kind: Kind, takes_value: bool, short: ?u8, long: ?[]const u8, - pub fn init(parser: fn(&Result, []const u8) ParseError!void) Self { + pub fn init(parse_fn: fn(&Result, []const u8) ParseError!void) Self { return Self { - .parser = parser, + .parse = parse_fn, .help = "", .kind = Kind.Optional, .takes_value = false, @@ -82,10 +82,12 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default // This limits the user to 128 required arguments, which is more than // enough. const required_mask = comptime blk: { + var required_index : u128 = 0; var required_res : u128 = 0; for (options) |option, i| { if (option.kind == OptionT.Kind.Required) { - required_res = (required_res << 1) | 0x1; + required_res |= 0x1 << required_index; + required_index += 1; } } @@ -93,7 +95,17 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default }; return struct { - fn parse(args: []const []const u8) !Result { + fn newRequired(option: &const OptionT, old_required: u128, index: usize) u128 { + switch (option.kind) { + OptionT.Kind.Required => { + return bits.set(u128, old_required, u7(index), false); + }, + OptionT.Kind.IgnoresRequired => return 0, + else => return old_required, + } + } + + pub fn parse(args: []const []const u8) !Result { var result = *defaults; var required = required_mask; @@ -111,57 +123,61 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default const arg = pair.arg; const kind = pair.kind; - var required_index : usize = 0; - for (options) |option, op_i| { + success: { + var required_index = usize(0); + switch (kind) { Arg.Kind.None => { - if (option.short != null) continue; - if (option.long != null) continue; - - try option.parser(&result, arg); - - switch (option.kind) { - OptionT.Kind.Required => { - required = bits.set(u128, required, u7(required_index), false); - required_index += 1; - }, - OptionT.Kind.IgnoresRequired => { - required = 0; - required_index += 1; - }, - else => {} + inline for (options) |option| { + defer if (option.kind == OptionT.Kind.Required) required_index += 1; + if (option.short != null) continue; + if (option.long != null) continue; + + try option.parse(&result, arg); + required = newRequired(option, required, required_index); + break :success; } - - break; }, Arg.Kind.Short => { - const short = option.short ?? continue; - if (arg.len != 1 or arg[0] != short) continue; + inline for (options) |option| { + defer if (option.kind == OptionT.Kind.Required) required_index += 1; + const short = option.short ?? continue; + if (arg.len == 1 and arg[0] == short) { + if (option.takes_value) { + arg_i += 1; + if (args.len <= arg_i) return error.OptionMissingValue; + + try option.parse(&result, args[arg_i]); + } else { + try option.parse(&result, []u8{}); + } + + required = newRequired(option, required, required_index); + break :success; + } + } }, Arg.Kind.Long => { - const long = option.long ?? continue; - if (!mem.eql(u8, long, arg)) continue; + inline for (options) |option| { + defer if (option.kind == OptionT.Kind.Required) required_index += 1; + const long = option.long ?? continue; + if (mem.eql(u8, arg, long)) { + if (option.takes_value) { + arg_i += 1; + if (args.len <= arg_i) return error.OptionMissingValue; + + try option.parse(&result, args[arg_i]); + } else { + try option.parse(&result, []u8{}); + } + + required = newRequired(option, required, required_index); + break :success; + } + } } } - if (option.takes_value) arg_i += 1; - if (args.len <= arg_i) return error.MissingValueToArgument; - try option.parser(&result, args[arg_i]); - - switch (option.kind) { - OptionT.Kind.Required => { - required = bits.set(u128, required, u7(required_index), false); - required_index += 1; - }, - OptionT.Kind.IgnoresRequired => { - required = 0; - required_index += 1; - }, - else => {} - } - - break; - } else { return error.InvalidArgument; } } @@ -294,7 +310,7 @@ test "clap.parse.Example" { Case { .args = [][]const u8 { "-g" }, .res = Color { .r = 0, .g = 0, .b = 0 }, - .err = error.MissingValueToArgument, + .err = error.OptionMissingValue, }, }; -- cgit v1.2.3