-
Notifications
You must be signed in to change notification settings - Fork 220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use non-zero optimization for Generation #447
Conversation
Hi! Unfortunately, this is a nightly-only feature, we cannot use this optimization. |
NonZeroU32 was stabilized a couple days ago with rust 1.28.0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, now you removed the feature requirement. I think this makes sense, but I don't want it to be merged yet because 1.28 is the latest version. Can we come back to this in a few weeks?
@torkleyy @andrewhickman 1.29 is released now, might be worth looking at rebasing/merging this (unless we want a larger buffer size). |
Should probably be released in 0.13, I'm doing a 0.12.3 right now |
src/world/entity.rs
Outdated
@@ -383,20 +406,38 @@ impl Generation { | |||
/// Panics in debug mode if it's not alive. | |||
fn die(&mut self) { | |||
debug_assert!(self.is_alive()); | |||
self.0 = -self.0; | |||
self.0 = NonZeroU32::new(-self.id() as u32).map(Generation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this underflow and therefore panic in debug builds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure can, so yeah that should be corrected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which operation can overflow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewhickman The negation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewhickman Or alternately, the cast. I'm not sure where the problem would actually occur.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assert should ensure that id()
is positive and the only overflow case is where id()
is i32::MIN so I think this one is correct. AFAIK signed-ness casts are always no-ops in rust so that should be OK as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok; I can accept the assert!
making the negation safe, but I'd like to see where casts from signed to unsigned are supposed to be defined as bitcasts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind; found it: https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
id()
can only ever be a positive number by virtue of the fact that it is built from a NonZeroU32
. Won't this always panic?
scratch that, I was missing context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm ok but it can only ever be positive or 0. I think we still have a problem.
src/world/entity.rs
Outdated
/// Panics if it is alive. | ||
fn raised(&self) -> Generation { | ||
assert!(!self.is_alive()); | ||
Generation(unsafe { NonZeroU32::new_unchecked((1 - self.id()) as u32) }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another very similar possible underflow here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that wrapping will give the wrong behaviour here, sending id from i32::MIN + 1
to i32::MIN
and vice versa. I think it would be better to just unconditionally panic here. Potentially we could start wrapping the generations back around to 1 but that sounds risky to me.
The test failure seems to be caused by ab43ce1 |
I removed |
Alright, after having read all the overflow/underflow bits and pieced this together I understand now why what I did broke the PR. I'm not super sure though that the loss in readability is worth the minute performance gains to be had from this. |
@andrewhickman would you rather I put the PR back together or would you prefer to? |
I don't know, I'm not even sure it's worth the effort to be honest. Specs is hard enough to read as is, and while this is technologically an improvement relying on overflow behavior to implement negatives makes it so much harder to maintain that I question the value of this. |
Ok, so I've been thinking about this a bit more and I actually see a way we can make this work. You've already made sure that the only entry and exit points from the |
@Xaeroxe not sure from your comments if you worked this out but the only reason I used |
Yeah I learned that from the original issue... probably should have read that first :P Sorry for all the trouble, and thanks for fixing my mistakes |
If we wanted to go a little overboard, we could implement a |
Maybe we ought to make a crate ;) |
@pthariensflame K you're gonna laugh but... I did it! https://crates.io/crates/nonzero_signed |
@Xaeroxe ooh nice! Shall we use it here? |
Might as well :)
|
Thank you! |
As promised in issue #436, this PR uses
NonZeroU32
inGeneration
. Note this bumps the minimum supported rust version to 1.28 - is this a concern? If so I could put this under a feature flag.This change is