Initial commit

This commit is contained in:
Luuk Machielse 2025-10-09 16:51:39 +02:00
commit 00426dfef6
37 changed files with 4794 additions and 0 deletions

25
src/main.zig Normal file
View file

@ -0,0 +1,25 @@
const std = @import("std");
const iter = @import("iterating").iter;
pub fn main() !void {
const arith = struct {
fn square(x: i32) i32 {
return x * x;
}
fn is_square(x: i32) bool {
const sqrt = @sqrt(@as(f32, @floatFromInt(x)));
return sqrt == @floor(sqrt);
}
fn try_sqrt(x: i32) ?i32 {
const sqrt = @sqrt(@as(f32, @floatFromInt(x)));
return if (sqrt == @floor(sqrt)) @intFromFloat(sqrt) else null;
}
};
const items = try iter(i32).once(-100).chain(iter(i32).rangeInclusive(1, 100).filter(arith.is_square).chain(iter(i32).range(0, 10))).toOwnedSlice(std.heap.page_allocator);
defer std.heap.page_allocator.free(items);
std.debug.print("{any}\n", .{items});
}

329
src/root.zig Normal file
View file

@ -0,0 +1,329 @@
const std = @import("std");
pub fn iter(comptime T: type) type {
return struct {
pub fn fromSlice(slice: anytype) Iterator(
if (@typeInfo(@TypeOf(slice)).pointer.is_const) SliceIterConst(T) else SliceIter(T),
) {
return .{ .inner = .{ .slice = slice } };
}
pub fn range(start: T, end: T) Iterator(Range(T)) {
return .{ .inner = .{ .current = start, .end = end } };
}
pub fn rangeInclusive(start: T, end: T) Iterator(RangeInclusive(T)) {
return .{ .inner = .{ .current = start, .end = end } };
}
pub fn once(value: T) Iterator(Once(T)) {
return .{ .inner = .{ .value = value } };
}
};
}
pub fn Iterator(comptime Inner: type) type {
return struct {
inner: Inner,
pub const Item = Inner.Item;
const _Inner = Inner;
const Self = @This();
pub fn next(self: *Self) ?Item {
return self.inner.next();
}
pub fn map(
self: Self,
comptime T: type,
f: fn (Item) T,
) Iterator(adapters.Map(Inner, T, f)) {
return .{ .inner = .{ .inner = self.inner } };
}
pub fn filter(self: Self, predicate: fn (Item) bool) Iterator(adapters.Filter(
Inner,
predicate,
)) {
return .{ .inner = .{ .inner = self.inner } };
}
pub fn filterMap(
self: Self,
comptime T: type,
f: anytype,
) Iterator(adapters.FilterMap(Inner, T, f)) {
return .{ .inner = .{ .inner = self.inner } };
}
pub fn take(
self: Self,
n: usize,
) Iterator(adapters.Take(Inner)) {
return .{ .inner = .{ .inner = self.inner, .n = n } };
}
pub fn enumerate(self: Self) Iterator(adapters.Enumerate(Inner)) {
return .{ .inner = .{ .inner = self.inner } };
}
pub fn fold(self: Self, init: anytype, f: anytype) @typeInfo(@TypeOf(f)).@"fn".return_type.? {
var mutSelf = self;
var acc = init;
while (mutSelf.next()) |x| {
acc = f(acc, x);
}
return acc;
}
pub fn count(self: Self) usize {
return self.fold(@as(usize, 0), struct {
fn inc(i: usize, _: Item) usize {
return i + 1;
}
}.inc);
}
pub fn last(self: Self) ?Item {
return self.fold(@as(?Item, null), struct {
inline fn some(_: ?Item, x: Item) ?Item {
return x;
}
}.some);
}
pub fn chain(self: Self, other: anytype) Iterator(adapters.Chain(Inner, Clean(@TypeOf(other)))) {
return .{ .inner = .{ .first = self.inner, .second = other.inner } };
}
pub fn toOwnedSlice(self: Self, gpa: std.mem.Allocator) ![]const Item {
var list: std.ArrayList(Item) = .empty;
errdefer list.deinit(gpa);
try self.collectInto(&list, gpa);
return try list.toOwnedSlice(gpa);
}
pub fn collectInto(self: Self, list: *std.ArrayList(Item), gpa: std.mem.Allocator) !void {
var mutSelf = self;
while (mutSelf.next()) |val| {
try list.append(gpa, val);
}
}
};
}
fn Clean(comptime Iter: type) type {
if (@hasDecl(Iter, "_Inner")) {
if (Iterator(Iter._Inner) == Iter) return Iter._Inner;
}
return Iter;
}
pub const adapters = struct {
pub fn Map(
comptime Inner: type,
comptime T: type,
comptime f: fn (Inner.Item) T,
) type {
return struct {
inner: Inner,
pub const Item = T;
const Self = @This();
pub fn next(self: *Self) ?Item {
return if (self.inner.next()) |val| f(val) else null;
}
};
}
pub fn Filter(comptime Inner: type, comptime predicate: fn (Inner.Item) bool) type {
return struct {
inner: Inner,
pub const Item = Inner.Item;
const Self = @This();
pub fn next(self: *Self) ?Item {
while (self.inner.next()) |val| {
if (predicate(val)) return val;
}
return null;
}
};
}
pub fn FilterMap(comptime Inner: type, comptime T: type, comptime f: fn (Inner.Item) ?T) type {
return struct {
inner: Inner,
pub const Item = T;
const Self = @This();
pub fn next(self: *Self) ?Item {
while (self.inner.next()) |val| {
if (f(val)) |mapped| return mapped;
}
return null;
}
};
}
pub fn Take(comptime Inner: type) type {
return struct {
i: usize = 0,
n: usize,
inner: Inner,
pub const Item = Inner.Item;
const Self = @This();
pub fn next(self: *Self) ?Item {
if (self.i >= self.n) return null;
defer self.i += 1;
return self.inner.next();
}
};
}
pub fn Enumerate(comptime Inner: type) type {
return struct {
inner: Inner,
i: usize = 0,
pub const Item = struct { usize, Inner.Item };
const Self = @This();
pub fn next(self: *Self) ?Item {
if (self.inner.next()) |val| {
defer self.i += 1;
return .{ self.i, val };
}
return null;
}
};
}
pub fn Chain(comptime First: type, comptime Second: type) type {
comptime std.debug.assert(First.Item == Second.Item);
return struct {
first: First,
second: Second,
pub const Item = First.Item;
const Self = @This();
pub fn next(self: *Self) ?Item {
return if (self.first.next()) |x| x else self.second.next();
}
};
}
};
pub fn Range(comptime T: type) type {
return struct {
current: T,
end: T,
pub const Item = T;
const Self = @This();
pub fn next(self: *Self) ?Item {
if (self.current >= self.end) return null;
defer self.current += 1;
return self.current;
}
};
}
pub fn RangeInclusive(comptime T: type) type {
return struct {
current: T,
end: T,
pub const Item = T;
const Self = @This();
pub fn next(self: *Self) ?Item {
if (self.current > self.end) return null;
defer self.current += 1;
return self.current;
}
};
}
pub fn Once(comptime T: type) type {
return struct {
value: ?T,
pub const Item = T;
const Self = @This();
pub fn next(self: *Self) ?Item {
defer self.value = null;
return self.value;
}
};
}
pub fn SliceIter(comptime T: type) type {
return struct {
slice: []T,
index: usize = 0,
pub const Item = *T;
const Self = @This();
pub fn next(self: *Self) ?Item {
if (self.index >= self.slice.len) return null;
defer self.index += 1;
return &self.slice[self.index];
}
};
}
pub fn SliceIterConst(comptime T: type) type {
return struct {
slice: []const T,
index: usize = 0,
pub const Item = *const T;
const Self = @This();
pub fn next(self: *Self) ?Item {
if (self.index >= self.slice.len) return null;
defer self.index += 1;
return &self.slice[self.index];
}
};
}
test "slices" {
const slice: []const i32 = &[_]i32{ -2, -1, 0, 1, 2 };
var it = iter(i32).slice(slice).enumerate();
while (it.next()) |pair| {
const i, const val = pair;
try std.testing.expectEqual(slice[i], val.*);
}
}