authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-01-30 22:25:33+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-30 18:07:02-05:00
logd27678fe83f8c7d61cc41c7300d68fe502dd4999
treecbae08db94e94949f681d7a0246dabb951aa43c7
parent13f782426660f49eb6ee7561ecee9237c22b4dc9

fmt: Refactor the arg fetching code

* Error out if the requested index is out-of-bound * Tidy-up all the arg-related variables in a struct

1 files changed, 31 insertions(+), 28 deletions(-)

lib/std/fmt.zig+31-28
......@@ -21,17 +21,6 @@ pub const FormatOptions = struct {
2121 fill: u8 = ' ',
2222};
2323
24fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int, comptime next_arg: *comptime_int) comptime_int {
25 if (maybe_pos_arg) |pos_arg| {
26 used_pos_args.* |= 1 << pos_arg;
27 return pos_arg;
28 } else {
29 const arg = next_arg.*;
30 next_arg.* += 1;
31 return arg;
32 }
33}
34
3524fn peekIsAlign(comptime fmt: []const u8) bool {
3625 // Should only be called during a state transition to the format segment.
3726 comptime assert(fmt[0] == ':');
......@@ -113,12 +102,36 @@ pub fn format(
113102
114103 comptime var start_index = 0;
115104 comptime var state = State.Start;
116 comptime var next_arg = 0;
117105 comptime var maybe_pos_arg: ?comptime_int = null;
118 comptime var used_pos_args: ArgSetType = 0;
119106 comptime var specifier_start = 0;
120107 comptime var specifier_end = 0;
121108 comptime var options = FormatOptions{};
109 comptime var arg_state: struct {
110 next_arg: usize = 0,
111 used_args: ArgSetType = 0,
112 args_len: usize = args.len,
113
114 fn hasUnusedArgs(comptime self: *@This()) bool {
115 return (@popCount(ArgSetType, self.used_args) != self.args_len);
116 }
117
118 fn nextArg(comptime self: *@This(), comptime pos_arg: ?comptime_int) comptime_int {
119 const next_idx = pos_arg orelse blk: {
120 const arg = self.next_arg;
121 self.next_arg += 1;
122 break :blk arg;
123 };
124
125 if (next_idx >= self.args_len) {
126 @compileError("Too few arguments");
127 }
128
129 // Mark this argument as used
130 self.used_args |= 1 << next_idx;
131
132 return next_idx;
133 }
134 } = .{};
122135
123136 inline for (fmt) |c, i| {
124137 switch (state) {
......@@ -166,11 +179,7 @@ pub fn format(
166179 }
167180 },
168181 '}' => {
169 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
170
171 if (arg_to_print >= args.len) {
172 @compileError("Too few arguments");
173 }
182 const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
174183
175184 try formatType(
176185 args[arg_to_print],
......@@ -203,7 +212,7 @@ pub fn format(
203212 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
204213 },
205214 '}' => {
206 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
215 const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
207216
208217 try formatType(
209218 args[arg_to_print],
......@@ -250,7 +259,7 @@ pub fn format(
250259 state = .FormatPrecision;
251260 },
252261 '}' => {
253 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
262 const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
254263
255264 try formatType(
256265 args[arg_to_print],
......@@ -278,7 +287,7 @@ pub fn format(
278287 options.precision.? += c - '0';
279288 },
280289 '}' => {
281 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
290 const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
282291
283292 try formatType(
284293 args[arg_to_print],
......@@ -299,13 +308,7 @@ pub fn format(
299308 }
300309 }
301310 comptime {
302 // All arguments must have been printed but we allow mixing positional and fixed to achieve this.
303 var i: usize = 0;
304 inline while (i < next_arg) : (i += 1) {
305 used_pos_args |= 1 << i;
306 }
307
308 if (@popCount(ArgSetType, used_pos_args) != args.len) {
311 if (comptime arg_state.hasUnusedArgs()) {
309312 @compileError("Unused arguments");
310313 }
311314 if (state != State.Start) {