n = Saturating(Int32).new(Int32::MAX - 2)
n += 20 # => 2147483647 (Int32::MAX)
m = Saturating(Int32).new(Int32::MIN + 3)
m -= 30 # => -2147483648 (Int32::MIN)
At first I was confused that you’d pass the (arbitrary) maximum value you want to allow to .new :D
API wise for a shard like this I wouldn’t mind adding itself to Int, so providing something like 0.to_si32 etc.
I’m not sure why you’d want to keep multiple implementation around, the intrinsics version should beat them all :) Meanwhile an implementation using wrapping operators (&+ etc) and checking whether the value wrapped around (by keeping value from before the operation around and comparing) should be slightly more performant as it avoids the stack unwinding :)
This is a good point. I’ll update the README. In particular, my number choice seems to have caused confusion already…
I don’t like throwing stuff away… However, if I’m able to keep an API that’s easy to use (like, I’d argue, the current one), I’m fine only using the LLVM-based implementation.
Yeah, that’s on my to-do list. I saw your code snippet, and I was planning on using something like that. However, I think wrapping it in a type will probably still be a friendlier API.
I had worked on saturating arithmetic a little before, but a large part of the reason I made this shard was so that you could use it. I’m not asking for overflowing gratitude, but it would be nice if you weren’t rude about this thing that was made for you.
This is a product of my bad example in the README (see @jhass’s post above). In a call Saturating(T).new(x), the T is obviously the type, and the x is the value you want the variable to have (not the max). I’ll be changing the README to make that more clear.
I don’t think this is possible, but I’ll look into it.
People have discussed this with you, and I’m not going to rehash this argument. This thread is not a place to argue that this shard shouldn’t exist because you think the language should already work like this.
The documentation is still pretty lacking, but the big thing is that Saturating is much faster in almost every case due to a new LLVM-backed implementation. It’s pretty complicated under the hood, and it’s currently only properly implemented for Int* and UInt* types, but my benchmarks show most operations taking less than 1.2x as long as those operations normally take for primitives. The worst slowdowns, for multiplication (there’s no LLVM backing for saturating multiplication), still take less than 10x as long as the non-saturating operations on primitives.
If anyone is using Saline or uses it in the future, please let me know. I’m probably not going to put much more work into in unless/until I know that people need feature or documentation improvements for it.