Skip to content

Commit

Permalink
Merge pull request #14671 from ziglang/multi-object-for
Browse files Browse the repository at this point in the history
implement multi-object for loops
  • Loading branch information
andrewrk committed Feb 19, 2023
2 parents 346ec15 + 5fc6bbe commit 0bb178b
Show file tree
Hide file tree
Showing 253 changed files with 2,381 additions and 1,277 deletions.
2 changes: 1 addition & 1 deletion doc/docgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ const Tokenizer = struct {
.line_start = 0,
.line_end = 0,
};
for (self.buffer) |c, i| {
for (self.buffer, 0..) |c, i| {
if (i == token.start) {
loc.line_end = i;
while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
Expand Down
34 changes: 17 additions & 17 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -2367,7 +2367,7 @@ test "iterate over an array" {
var some_integers: [100]i32 = undefined;

test "modify an array" {
for (some_integers) |*item, i| {
for (&some_integers, 0..) |*item, i| {
item.* = @intCast(i32, i);
}
try expect(some_integers[10] == 10);
Expand Down Expand Up @@ -2408,7 +2408,7 @@ comptime {
// use compile-time code to initialize an array
var fancy_array = init: {
var initial_value: [10]Point = undefined;
for (initial_value) |*pt, i| {
for (&initial_value, 0..) |*pt, i| {
pt.* = Point{
.x = @intCast(i32, i),
.y = @intCast(i32, i) * 2,
Expand Down Expand Up @@ -2461,8 +2461,8 @@ test "multidimensional arrays" {
try expect(mat4x4[1][1] == 1.0);

// Here we iterate with for loops.
for (mat4x4) |row, row_index| {
for (row) |cell, column_index| {
for (mat4x4, 0..) |row, row_index| {
for (row, 0..) |cell, column_index| {
if (row_index == column_index) {
try expect(cell == 1.0);
}
Expand Down Expand Up @@ -3579,7 +3579,7 @@ test "tuple" {
} ++ .{false} ** 2;
try expect(values[0] == 1234);
try expect(values[4] == false);
inline for (values) |v, i| {
inline for (values, 0..) |v, i| {
if (i != 2) continue;
try expect(v);
}
Expand Down Expand Up @@ -4659,10 +4659,10 @@ test "for basics" {
}
try expect(sum == 20);

// To access the index of iteration, specify a second capture value.
// This is zero-indexed.
// To access the index of iteration, specify a second condition as well
// as a second capture value.
var sum2: i32 = 0;
for (items) |_, i| {
for (items, 0..) |_, i| {
try expect(@TypeOf(i) == usize);
sum2 += @intCast(i32, i);
}
Expand All @@ -4674,7 +4674,7 @@ test "for reference" {

// Iterate over the slice by reference by
// specifying that the capture value is a pointer.
for (items) |*value| {
for (&items) |*value| {
value.* += 1;
}

Expand Down Expand Up @@ -5659,7 +5659,7 @@ fn genFoos(allocator: Allocator, num: usize) ![]Foo {
var foos = try allocator.alloc(Foo, num);
errdefer allocator.free(foos);

for(foos) |*foo, i| {
for (foos, 0..) |*foo, i| {
foo.data = try allocator.create(u32);
// This errdefer does not last between iterations
errdefer allocator.destroy(foo.data);
Expand Down Expand Up @@ -5700,14 +5700,14 @@ fn genFoos(allocator: Allocator, num: usize) ![]Foo {
// Used to track how many foos have been initialized
// (including their data being allocated)
var num_allocated: usize = 0;
errdefer for(foos[0..num_allocated]) |foo| {
errdefer for (foos[0..num_allocated]) |foo| {
allocator.destroy(foo.data);
};
for(foos) |*foo, i| {
for (foos, 0..) |*foo, i| {
foo.data = try allocator.create(u32);
num_allocated += 1;

if(i >= 3) return error.TooManyFoos;
if (i >= 3) return error.TooManyFoos;

foo.data.* = try getData();
}
Expand Down Expand Up @@ -7265,7 +7265,7 @@ const Writer = struct {
comptime var state = State.start;
comptime var next_arg: usize = 0;

inline for (format) |c, i| {
inline for (format, 0..) |c, i| {
switch (state) {
State.start => switch (c) {
'{' => {
Expand Down Expand Up @@ -8629,7 +8629,7 @@ test "integer cast panic" {
This function is a low level intrinsic with no safety mechanisms. Most code
should not use this function, instead using something like this:
</p>
<pre>{#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre>
<pre>{#syntax#}for (dest, source[0..byte_count]) |*d, s| d.* = s;{#endsyntax#}</pre>
<p>
The optimizer is intelligent enough to turn the above snippet into a memcpy.
</p>
Expand Down Expand Up @@ -11116,7 +11116,7 @@ pub fn main() !void {
const args = try std.process.argsAlloc(gpa);
defer std.process.argsFree(gpa, args);

for (args) |arg, i| {
for (args, 0..) |arg, i| {
std.debug.print("{}: {s}\n", .{ i, arg });
}
}
Expand All @@ -11142,7 +11142,7 @@ pub fn main() !void {

const preopens = try fs.wasi.preopensAlloc(arena);

for (preopens.names) |preopen, i| {
for (preopens.names, 0..) |preopen, i| {
std.debug.print("{}: {s}\n", .{ i, preopen });
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler_rt/atomics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ fn __atomic_compare_exchange(
_ = failure;
var sl = spinlocks.get(@ptrToInt(ptr));
defer sl.release();
for (ptr[0..size]) |b, i| {
for (ptr[0..size], 0..) |b, i| {
if (expected[i] != b) break;
} else {
// The two objects, ptr and expected, are equal
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler_rt/comparedf2_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ fn generateVector(comptime a: f64, comptime b: f64) TestVector {
const test_vectors = init: {
@setEvalBranchQuota(10000);
var vectors: [arguments.len * arguments.len]TestVector = undefined;
for (arguments[0..]) |arg_i, i| {
for (arguments[0..]) |arg_j, j| {
for (arguments[0..], 0..) |arg_i, i| {
for (arguments[0..], 0..) |arg_j, j| {
vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j);
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler_rt/comparesf2_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ fn generateVector(comptime a: f32, comptime b: f32) TestVector {
const test_vectors = init: {
@setEvalBranchQuota(10000);
var vectors: [arguments.len * arguments.len]TestVector = undefined;
for (arguments[0..]) |arg_i, i| {
for (arguments[0..]) |arg_j, j| {
for (arguments[0..], 0..) |arg_i, i| {
for (arguments[0..], 0..) |arg_j, j| {
vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j);
}
}
Expand Down
8 changes: 4 additions & 4 deletions lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ pub fn dupe(self: *Build, bytes: []const u8) []u8 {
/// Duplicates an array of strings without the need to handle out of memory.
pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 {
const array = self.allocator.alloc([]u8, strings.len) catch @panic("OOM");
for (strings) |s, i| {
for (strings, 0..) |s, i| {
array[i] = self.dupe(s);
}
return array;
Expand Down Expand Up @@ -1051,15 +1051,15 @@ pub fn standardTargetOptions(self: *Build, args: StandardTargetOptionsArgs) Cros
const all_features = whitelist_cpu.arch.allFeaturesList();
var populated_cpu_features = whitelist_cpu.model.features;
populated_cpu_features.populateDependencies(all_features);
for (all_features) |feature, i_usize| {
for (all_features, 0..) |feature, i_usize| {
const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
const in_cpu_set = populated_cpu_features.isEnabled(i);
if (in_cpu_set) {
log.err("{s} ", .{feature.name});
}
}
log.err(" Remove: ", .{});
for (all_features) |feature, i_usize| {
for (all_features, 0..) |feature, i_usize| {
const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
const in_cpu_set = populated_cpu_features.isEnabled(i);
const in_actual_set = selected_cpu.features.isEnabled(i);
Expand Down Expand Up @@ -1748,7 +1748,7 @@ pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 {
var mcpu_buffer = ArrayList(u8).init(allocator);
try mcpu_buffer.appendSlice(cpu.model.name);

for (all_features) |feature, i_usize| {
for (all_features, 0..) |feature, i_usize| {
const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
const in_cpu_set = populated_cpu_features.isEnabled(i);
const in_actual_set = cpu.features.isEnabled(i);
Expand Down
8 changes: 4 additions & 4 deletions lib/std/Build/CompileStep.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1016,7 +1016,7 @@ pub fn addVcpkgPaths(self: *CompileStep, linkage: CompileStep.Linkage) !void {
pub fn setExecCmd(self: *CompileStep, args: []const ?[]const u8) void {
assert(self.kind == .@"test");
const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch @panic("OOM");
for (args) |arg, i| {
for (args, 0..) |arg, i| {
duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;
}
self.exec_cmd_args = duped_args;
Expand All @@ -1040,7 +1040,7 @@ fn appendModuleArgs(

{
const keys = module.dependencies.keys();
for (module.dependencies.values()) |sub_module, i| {
for (module.dependencies.values(), 0..) |sub_module, i| {
const sub_name = keys[i];
try cs.appendModuleArgs(zig_args, sub_name, sub_module);
}
Expand Down Expand Up @@ -1575,7 +1575,7 @@ fn make(step: *Step) !void {

{
const keys = self.modules.keys();
for (self.modules.values()) |module, i| {
for (self.modules.values(), 0..) |module, i| {
const name = keys[i];
try self.appendModuleArgs(&zig_args, name, module);
}
Expand Down Expand Up @@ -1750,7 +1750,7 @@ fn make(step: *Step) !void {
const args_to_escape = zig_args.items[2..];
var escaped_args = try ArrayList([]const u8).initCapacity(builder.allocator, args_to_escape.len);
arg_blk: for (args_to_escape) |arg| {
for (arg) |c, arg_idx| {
for (arg, 0..) |c, arg_idx| {
if (c == '\\' or c == '"') {
// Slow path for arguments that need to be escaped. We'll need to allocate and copy
var escaped = try ArrayList(u8).initCapacity(builder.allocator, arg.len + 1);
Expand Down
4 changes: 2 additions & 2 deletions lib/std/Build/ConfigHeaderStep.zig
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ fn render_blank(
try output.appendSlice("\n");

const values = defines.values();
for (defines.keys()) |name, i| {
for (defines.keys(), 0..) |name, i| {
try renderValueC(output, name, values[i]);
}

Expand All @@ -361,7 +361,7 @@ fn render_blank(

fn render_nasm(output: *std.ArrayList(u8), defines: std.StringArrayHashMap(Value)) !void {
const values = defines.values();
for (defines.keys()) |name, i| {
for (defines.keys(), 0..) |name, i| {
try renderValueNasm(output, name, values[i]);
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/FmtStep.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep {

self.argv[0] = builder.zig_exe;
self.argv[1] = "fmt";
for (paths) |path, i| {
for (paths, 0..) |path, i| {
self.argv[2 + i] = builder.pathFromRoot(path);
}
return self;
Expand Down
12 changes: 6 additions & 6 deletions lib/std/Thread/Condition.zig
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ test "Condition - wait and signal" {
};

var multi_wait = MultiWait{};
for (multi_wait.threads) |*t| {
for (&multi_wait.threads) |*t| {
t.* = try std.Thread.spawn(.{}, MultiWait.run, .{&multi_wait});
}

Expand Down Expand Up @@ -389,7 +389,7 @@ test "Condition - signal" {
};

var signal_test = SignalTest{};
for (signal_test.threads) |*t| {
for (&signal_test.threads) |*t| {
t.* = try std.Thread.spawn(.{}, SignalTest.run, .{&signal_test});
}

Expand Down Expand Up @@ -457,7 +457,7 @@ test "Condition - multi signal" {
var threads = [_]std.Thread{undefined} ** num_threads;

// Create a circle of paddles which hit each other
for (threads) |*t, i| {
for (&threads, 0..) |*t, i| {
const paddle = &paddles[i];
const hit_to = &paddles[(i + 1) % paddles.len];
t.* = try std.Thread.spawn(.{}, Paddle.run, .{ paddle, hit_to });
Expand All @@ -468,7 +468,7 @@ test "Condition - multi signal" {
for (threads) |t| t.join();

// The first paddle will be hit one last time by the last paddle.
for (paddles) |p, i| {
for (paddles, 0..) |p, i| {
const expected = @as(u32, num_iterations) + @boolToInt(i == 0);
try testing.expectEqual(p.value, expected);
}
Expand Down Expand Up @@ -513,7 +513,7 @@ test "Condition - broadcasting" {
};

var broadcast_test = BroadcastTest{};
for (broadcast_test.threads) |*t| {
for (&broadcast_test.threads) |*t| {
t.* = try std.Thread.spawn(.{}, BroadcastTest.run, .{&broadcast_test});
}

Expand Down Expand Up @@ -584,7 +584,7 @@ test "Condition - broadcasting - wake all threads" {

var broadcast_test = BroadcastTest{};
var thread_id: usize = 1;
for (broadcast_test.threads) |*t| {
for (&broadcast_test.threads) |*t| {
t.* = try std.Thread.spawn(.{}, BroadcastTest.run, .{ &broadcast_test, thread_id });
thread_id += 1;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/std/Thread/Futex.zig
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ test "Futex - signaling" {
var threads = [_]std.Thread{undefined} ** num_threads;

// Create a circle of paddles which hit each other
for (threads) |*t, i| {
for (&threads, 0..) |*t, i| {
const paddle = &paddles[i];
const hit_to = &paddles[(i + 1) % paddles.len];
t.* = try std.Thread.spawn(.{}, Paddle.run, .{ paddle, hit_to });
Expand Down Expand Up @@ -950,14 +950,14 @@ test "Futex - broadcasting" {
threads: [num_threads]std.Thread = undefined,

fn run(self: *@This()) !void {
for (self.barriers) |*barrier| {
for (&self.barriers) |*barrier| {
try barrier.wait();
}
}
};

var broadcast = Broadcast{};
for (broadcast.threads) |*t| t.* = try std.Thread.spawn(.{}, Broadcast.run, .{&broadcast});
for (&broadcast.threads) |*t| t.* = try std.Thread.spawn(.{}, Broadcast.run, .{&broadcast});
for (broadcast.threads) |t| t.join();
}

Expand Down
6 changes: 3 additions & 3 deletions lib/std/Thread/Mutex.zig
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ const NonAtomicCounter = struct {
}

fn inc(self: *NonAtomicCounter) void {
for (@bitCast([2]u64, self.get() + 1)) |v, i| {
for (@bitCast([2]u64, self.get() + 1), 0..) |v, i| {
@ptrCast(*volatile u64, &self.value[i]).* = v;
}
}
Expand Down Expand Up @@ -277,7 +277,7 @@ test "Mutex - many uncontended" {
};

var runners = [_]Runner{.{}} ** num_threads;
for (runners) |*r| r.thread = try Thread.spawn(.{}, Runner.run, .{r});
for (&runners) |*r| r.thread = try Thread.spawn(.{}, Runner.run, .{r});
for (runners) |r| r.thread.join();
for (runners) |r| try testing.expectEqual(r.counter.get(), num_increments);
}
Expand Down Expand Up @@ -312,7 +312,7 @@ test "Mutex - many contended" {
var runner = Runner{};

var threads: [num_threads]Thread = undefined;
for (threads) |*t| t.* = try Thread.spawn(.{}, Runner.run, .{&runner});
for (&threads) |*t| t.* = try Thread.spawn(.{}, Runner.run, .{&runner});
for (threads) |t| t.join();

try testing.expectEqual(runner.counter.get(), num_increments * num_threads);
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Thread/ResetEvent.zig
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ test "ResetEvent - broadcast" {
var ctx = Context{};
var threads: [num_threads - 1]std.Thread = undefined;

for (threads) |*t| t.* = try std.Thread.spawn(.{}, Context.run, .{&ctx});
for (&threads) |*t| t.* = try std.Thread.spawn(.{}, Context.run, .{&ctx});
defer for (threads) |t| t.join();

ctx.run();
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Thread/RwLock.zig
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ test "RwLock - concurrent access" {
var runner = Runner{};
var threads: [num_writers + num_readers]std.Thread = undefined;

for (threads[0..num_writers]) |*t, i| t.* = try std.Thread.spawn(.{}, Runner.writer, .{ &runner, i });
for (threads[0..num_writers], 0..) |*t, i| t.* = try std.Thread.spawn(.{}, Runner.writer, .{ &runner, i });
for (threads[num_writers..]) |*t| t.* = try std.Thread.spawn(.{}, Runner.reader, .{&runner});

for (threads) |t| t.join();
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Thread/Semaphore.zig
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test "Thread.Semaphore" {
var n: i32 = 0;
var ctx = TestContext{ .sem = &sem, .n = &n };

for (threads) |*t| t.* = try std.Thread.spawn(.{}, TestContext.worker, .{&ctx});
for (&threads) |*t| t.* = try std.Thread.spawn(.{}, TestContext.worker, .{&ctx});
for (threads) |t| t.join();
sem.wait();
try testing.expect(n == num_threads);
Expand Down
Loading

0 comments on commit 0bb178b

Please sign in to comment.