@@ 182,65 182,75 @@ pub fn SliceIter(comptime T: type) type
};
}
-pub fn Product(comptime T: type) type {
+/// Get the cartesian product of iterators. All iterators' next
+/// methods must return the same type, passed in as T. The number of
+/// iterators to process is passed as num.
+///
+/// Sample usage:
+/// var a = try Range(u32, 1).init(0, 2);
+/// var b = try Range(u32, 2).init(4, 8);
+/// var iterators = [_]*Iterator(u32){ &a.iterator, &b.iterator };
+/// var product = Product(u32, 2).init(iterators);
+/// var iter = &product.iterator;
+/// while (iter.next()) |vals| {
+/// // vals will have these values: {0, 4}, {1, 4}, {0, 6}, {1, 6}
+/// }
+pub fn Product(comptime T: type, comptime num: usize) type {
return struct {
const Self = @This();
// This would be better as a tuple. Note for when we get tuple
- // types.
- const Result = struct { a: T, b: T };
+ // types. Then the iterators being multiplied don't need to
+ // all return the same type.
+ const Result = [num]T;
iterator: Iterator(Result),
- a: *Iterator(T),
- b: *Iterator(T),
- next_a: T,
- next_b: T,
+ children: [num]*Iterator(T),
+ next: [num]T,
done: bool = false,
pub fn next(iterator: *Iterator(Result)) ?Result {
const self = @fieldParentPtr(Self, "iterator", iterator);
if (self.done)
return null;
- const prev_a = self.next_a;
- const prev_b = self.next_b;
- if (self.a.next()) |aa| {
- self.next_a = aa;
- } else {
- self.a.reset();
- if (self.a.next()) |aa| {
- self.next_a = aa;
+ const prev: Result = self.next;
+ for (self.children) |child, idx| {
+ if (child.next()) |val| {
+ self.next[idx] = val;
+ self.done = false;
+ break;
} else {
- // a iterator is empty.
- return null;
+ child.reset();
+ self.next[idx] = child.next().?;
}
- if (self.b.next()) |bb| {
- self.next_b = bb;
- } else {
- // b iterator has been exhausted; all done
- self.done = true;
- }
+ } else {
+ self.done = true;
}
- return Result{ .a = prev_a, .b = prev_b };
+ return prev;
}
pub fn reset(iterator: *Iterator(Result)) void {
const self = @fieldParentPtr(Self, "iterator", iterator);
- self.a.reset();
- self.b.reset();
+ for (self.children) |child| {
+ child.reset();
+ }
}
- pub fn init(a: *Iterator(T), b: *Iterator(T)) Self {
- const prev_a = a.next().?;
- const prev_b = b.next().?;
- return Self{
- .a = a,
- .b = b,
- .next_a = prev_a,
- .next_b = prev_b,
+ /// Invokes safety-checked illegal behavior if any iterators
+ /// are empty.
+ pub fn init(args: [num]*Iterator(T)) Self {
+ var rv = Self{
.iterator = Iterator(Result){
.nextFn = next,
.resetFn = reset,
},
+ .children = args,
+ .next = undefined,
};
+
+ for (args) |iter, idx| {
+ rv.next[idx] = iter.next().?;
+ }
+ return rv;
}
};
}
@@ 311,21 321,23 @@ test "reverse" {
test "product" {
const R = Range(u32, 1);
var a = try R.init(0, 10);
- var b = try R.init(10, 20);
- var product = Product(u32).init(&a.iterator, &b.iterator);
+ var b = try R.init(10, 25);
+ var iterators = [_]*Iterator(u32){ &a.iterator, &b.iterator };
+ var product = Product(u32, 2).init(iterators);
+
var pi = &product.iterator;
var correct_a: u32 = 0;
var correct_b: u32 = 10;
while (pi.next()) |ab| {
- testing.expectEqual(ab.a, correct_a);
- testing.expectEqual(ab.b, correct_b);
+ testing.expectEqual(ab[0], correct_a);
+ testing.expectEqual(ab[1], correct_b);
correct_a += 1;
if (correct_a == 10) {
correct_a = 0;
correct_b += 1;
}
}
- testing.expectEqual(correct_b, 20);
+ testing.expectEqual(correct_b, 25);
testing.expectEqual(pi.next(), null);
}