Skip to content
v1.0.0-zig0.15.2

Iterators API Reference

Complete reference for Blitz’s Rayon-style parallel iterators.

Blitz provides three iterator types:

TypeCreationPurpose
ParIter(T)blitz.iter(T, slice)Read-only parallel iteration
ParIterMut(T)blitz.iterMut(T, slice)Mutable parallel iteration
RangeIterblitz.range(start, end)Index range iteration

Create an immutable parallel iterator over a slice.

const data = [_]i64{ 1, 2, 3, 4, 5 };
const it = blitz.iter(i64, &data);
// All operations are parallel and thread-safe
const sum = it.sum(); // 15

Thread Safety: Read-only access, fully thread-safe.


Create a mutable parallel iterator over a slice.

var data = [_]i64{ 1, 2, 3, 4, 5 };
var it = blitz.iterMut(i64, &data);
it.mapInPlace(double); // data is now [2, 4, 6, 8, 10]
fn double(x: i64) i64 { return x * 2; }

Thread Safety: Each element written by exactly one thread (disjoint access).


Create an iterator over the index range [start, end).

const it = blitz.range(0, 1000);
it.forEach(processIndex);
fn processIndex(i: usize) void {
// Process index i
}

Compute the sum of all elements using parallel reduction.

const data = [_]i64{ 1, 2, 3, 4, 5 };
const sum = blitz.iter(i64, &data).sum(); // 15

Returns: Sum of all elements (0 for empty slice)


Find the minimum element using parallel reduction.

const min = blitz.iter(i64, &data).min(); // ?i64
if (min) |m| {
std.debug.print("Min: {}\n", .{m});
}

Returns: ?T - The minimum, or null for empty slice


Find the maximum element using parallel reduction.

const max = blitz.iter(i64, &data).max(); // ?i64

Returns: ?T - The maximum, or null for empty slice


Count the number of elements.

const n = blitz.iter(i64, &data).count(); // 5

General parallel reduction with a custom binary operation.

const product = blitz.iter(i64, &data).reduce(1, multiply);
fn multiply(a: i64, b: i64) i64 { return a * b; }

Parameters:

  • identity: T - Identity value for the operation (e.g., 0 for sum, 1 for product)
  • reducer: fn(T, T) T - Associative binary operation

Requirements: The reducer must be associative: f(f(a,b), c) == f(a, f(b,c))


Find any element matching the predicate. Non-deterministic order, fastest search.

const found = blitz.iter(i64, &data).findAny(isNegative);
fn isNegative(x: i64) bool { return x < 0; }

Performance: Supports early exit - stops when any thread finds a match.


Find the first element matching the predicate (deterministic order).

const result = blitz.iter(i64, &data).findFirst(isNegative);
if (result) |r| {
std.debug.print("First negative at index {}: {}\n", .{ r.index, r.value });
}

Returns: ?struct { index: usize, value: T } - First match with index


Find the last element matching the predicate (deterministic order).


Find the index of the first matching element.

const pos = blitz.iter(i64, &data).position(isNegative);

Find the index of the last matching element.


Check if any element matches. Short-circuits on first match.

const hasNegative = blitz.iter(i64, &data).any(isNegative);

Performance: Early exit when match found - can be 100-1000x faster than full scan.


Check if all elements match. Short-circuits on first non-match.

const allPositive = blitz.iter(i64, &data).all(isPositive);
fn isPositive(x: i64) bool { return x > 0; }

Find minimum using a custom comparator.

const Person = struct { name: []const u8, age: u32 };
const youngest = blitz.iter(Person, &people).minBy(compareByAge);
fn compareByAge(a: Person, b: Person) std.math.Order {
return std.math.order(a.age, b.age);
}

Find maximum using a custom comparator.


Find minimum by extracting a comparable key.

const youngest = blitz.iter(Person, &people).minByKey(u32, getAge);
fn getAge(p: Person) u32 { return p.age; }

Find maximum by extracting a comparable key.


Create a new iterator with transformed values (lazy).

const squared = blitz.iter(i64, &data).map(square);
const sumOfSquares = squared.sum();
fn square(x: i64) i64 { return x * x; }

Note: Lazy evaluation - transformation applied when consumed.


Execute a function for each element in parallel.

blitz.iter(i64, &data).forEach(process);
fn process(x: i64) void {
std.debug.print("Value: {}\n", .{x});
}

Note: No ordering guarantee - elements processed in parallel.


Collect elements into a new allocated array.

const copy = try blitz.iter(i64, &data).collect(allocator);
defer allocator.free(copy);

Create an iterator over fixed-size chunks.

const chunks = blitz.iter(f64, &data).chunks_iter(1000);
const numChunks = chunks.count(); // ceil(data.len / 1000)

Create an iterator with indices starting at 0.

const enum_it = blitz.iter(i64, &data).enumerate_iter();
enum_it.forEach(processWithIndex);
fn processWithIndex(index: usize, value: i64) void {
// ...
}

Includes all ParIter methods plus:

Transform each element in place.

var it = blitz.iterMut(i64, &data);
it.mapInPlace(double);
fn double(x: i64) i64 { return x * 2; }

Thread Safety: Each element written by exactly one thread.


Set all elements to a value (parallel memset).

var it = blitz.iterMut(i64, &data);
it.fill(0); // Zero all elements

Sum values generated from indices.

const total = blitz.range(0, 1000).sum(i64, identity);
fn identity(i: usize) i64 { return @intCast(i); }

Process each index in parallel.

blitz.range(0, 1000).forEach(processIndex);
fn processIndex(i: usize) void {
// Process index i
}

OperationSequentialParallel (10 cores)Speedup
sum (100M i64)31 ms3.1 ms10x
min (100M i64)45 ms8 ms5.6x
any (10M, early exit)35 ms0.07 ms500x
findAny (10M)35 ms0.1 ms350x
mapInPlace (10M)25 ms3 ms8x

  1. Use findAny over findFirst when order doesn’t matter - it’s faster
  2. Use any/all for boolean checks - early exit is very fast
  3. Use built-in aggregations (sum, min, max) - optimized parallel reduction
  4. Use minByKey/maxByKey when you have a natural key - cleaner than minBy
  5. Use chunks_iter for complex per-chunk processing with custom reduction
  6. Don’t parallelize tiny data - overhead exceeds benefit below ~1000 elements