Reading Can i have a range as function parameter? I had an idea how you could use (abuse) slice syntax to create a kind-of range object:
const Example = struct {
many: [20]f32,
pub const zeroes: Example = .{ .many = @splat(0) };
pub fn subslice(self: *Example, item_range: anytype) []f32 {
return range.apply(&self.many, item_range);
}
};
pub fn main() !void {
var example: Example = .zeroes;
example.subslice(range.over[0..1])[0] = 99.0;
const subslice = example.subslice(range.over[5..]);
subslice[0] = 123.0;
subslice[1] = 0.5;
subslice[2] = 3.9;
std.debug.print("{}\n", .{example});
}
pub const range = struct {
const RangeElement = struct { do_not_access_or_deref: u8 };
pub const Closed = []allowzero const RangeElement;
pub const OpenEnded = [*]allowzero const RangeElement;
pub const over: OpenEnded = @ptrFromInt(0);
pub fn hasLength(comptime Sliceable: type) bool {
return comptime info: switch (@typeInfo(Sliceable)) {
.array => true,
.pointer => |p| switch (p.size) {
.c, .many => false,
.slice => true,
.one => continue :info @typeInfo(p.child),
},
else => false,
};
}
pub fn Result(Sliceable: type, Range: type) type {
return if (hasLength(Sliceable) or hasLength(Range))
[]std.meta.Elem(Sliceable)
else
[*]std.meta.Elem(Sliceable);
}
pub fn applyClosed(sliceable: anytype, range_: Closed) []std.meta.Elem(@TypeOf(sliceable)) {
return sliceable[@intFromPtr(range_.ptr)..][0..range_.len];
}
pub fn applyOpenEnded(sliceable: anytype, range_: OpenEnded) Result(@TypeOf(sliceable), @TypeOf(range_)) {
return sliceable[@intFromPtr(range_)..];
}
pub fn apply(
sliceable: anytype,
/// Needs to be of type `Closed` or `OpenEnded`
range_: anytype,
) Result(@TypeOf(sliceable), @TypeOf(range_)) {
const Sliceable = @TypeOf(sliceable);
const Range = @TypeOf(range_);
return if (hasLength(Sliceable) or hasLength(Range))
applyClosed(sliceable, if (comptime hasLength(Range)) range_ else range_[0 .. sliceable.len - @intFromPtr(range_)])
else
applyOpenEnded(sliceable, range_);
}
};
const std = @import("std");
I am not quite sure whether I like it or not.
What do you think?