Range: a simple little numeric range iterator

With one additional line of code, you get:

  1. Control the type of iterated numeric values.
var r = Range(i8){ .from = -2, .to = 2 };
while (r.next()) |i| { ...
  1. Ascending or descending iteration.
var r = Range(i8){ .from = 2, .to = -2 };
while (r.next()) |i| { ...
  1. Control the iteration step.
var r = Range(i8){ .from = -2, .to = 2, .step = 2 };
while (r.next()) |i| { ...
  1. Range over the values of a type.
var r = Range(u4){ .inclusive = true };
while (r.next()) |i| { ...

This looks great @dude_the_builder . I am trying to look at the source, but codeberg.org is excruciatingly slow for me, for some reason.

1 Like

Yeah, sometimes it’s fast, sometimes it’s really slow, sometimes it’s plain unavailable. I guess it’s the price to pay for not hosting on a tech giant’s infrastructure.

Cool little utility!

I have a suggestion: “unbounded” ranges don’t exist, and the way you use null and saturating add (if I’m reading the code correctly) would produce an infinite loop of the maximum value that the numeric type can represent.

You could use the type-maximum for .to when it’s not specified, and return null when .i.? is == to .to. Since .i starts as null, this should make e.g. 0..255 all representable for a u8, since you return the incremented value, therefore the final returned value of .i.? would be 255, then it would be checked, found to be equal, and the iterator would return null.

This also wouldn’t need to use saturating arithmetic.

Commenting on code one hasn’t run is a bad habit, so if I missed something about the implementation and all of this is wrong, sorry about that! I also want to note that this is an incomplete observation, which only applies to ranges which increment.


The upper bound is infinity. lol But seriously, I’m kind of on the fence with the unbounded option. The repeating maximum value for the type is exactly the behavior that occurs and I’m hard-pressed to think of a useful use-case for that.

I think I need it because of .step, which can cause the last increment / decrement to go past the max / min for the type, right?

Either way, those are some great observations, thanks for taking the time!

1 Like

Ok, so thanks to @mnemnion’s observations, I replaced the unbounded option with type min / max default values for from and to. Also added an inclusive field to be able to easily iterate over a type’s range of values:

var r = Range(u8){ .inclusive = true };
while (r.next()) |i| { // 0-255

Very neat, I like how simple + readable the implementation is for it too, also no idea Zig had saturating arithmetic operators until now, this seems like a really great use for them!


Okay, now that’s really cool. I like that you can span the entire value set for smaller integer types.

1 Like

If you wanted to go full Dijkstra on this, you could support inclusive / exclusive on both ends, with four total combinations. But I am not aware exclusive on the starting value would ever be useful… Great job!

1 Like