-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
NonMaxUsize for SparseArrays #11843
Closed
Closed
NonMaxUsize for SparseArrays #11843
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
macro_rules! impl_non_max_fmt { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a |
||
(($($trait:ident),+) for $ty:ident) => { | ||
$( | ||
impl std::fmt::$trait for $ty { | ||
#[inline] | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
self.get().fmt(f) | ||
} | ||
} | ||
)+ | ||
} | ||
} | ||
|
||
macro_rules! impl_non_max { | ||
($nonmax:ident, $nonzero:ty, $repr:ty, $test:ident) => { | ||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] | ||
#[repr(transparent)] | ||
pub struct $nonmax($nonzero); | ||
|
||
impl $nonmax { | ||
/// Creates a non-max if `n` is not the maximum value. | ||
#[inline] | ||
#[allow(clippy::manual_map)] | ||
pub const fn new(n: $repr) -> Option<Self> { | ||
if let Some(n) = <$nonzero>::new(!n) { | ||
Some(Self(n)) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
/// Creates a non-max without checking the value. | ||
/// | ||
/// # Safety | ||
/// `n` must not be equal to T::MAX. | ||
#[inline] | ||
pub const unsafe fn new_unchecked(n: $repr) -> Self { | ||
Self(<$nonzero>::new_unchecked(!n)) | ||
} | ||
|
||
/// Returns the value as a primitive type. | ||
/// | ||
/// # Note | ||
/// This function is not free. Consider storing the result | ||
/// into a variable instead of calling `get()` multiple times. | ||
#[inline] | ||
pub const fn get(self) -> $repr { | ||
!self.0.get() | ||
} | ||
} | ||
|
||
impl_non_max_fmt! { | ||
(Debug, Display, Binary, Octal, LowerHex, UpperHex) for $nonmax | ||
} | ||
|
||
#[cfg(test)] | ||
mod $test { | ||
use super::*; | ||
|
||
#[test] | ||
fn test() { | ||
assert!($nonmax::new(<$repr>::MAX).is_none()); | ||
assert_eq!($nonmax::new(0).unwrap().get(), 0); | ||
assert_eq!($nonmax::new(1).unwrap().get(), 1); | ||
|
||
// SAFE: `0` != <$repr>::MAX | ||
unsafe { | ||
assert_eq!($nonmax::new_unchecked(0).get(), 0); | ||
} | ||
|
||
assert_eq!( | ||
std::mem::size_of::<$nonmax>(), | ||
std::mem::size_of::<Option<$nonmax>>() | ||
); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
impl_non_max!( | ||
NonMaxUsize, | ||
std::num::NonZeroUsize, | ||
usize, | ||
non_max_usize_test | ||
); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This isn't an uncommon branch to take, and this introduces a potential panic, even if we never panic normally, this will have a negative impact on performance, and it's not something we can use
debug_checked_unwrap
on either since we know for a fact that it's something that we can hit.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.
Does that mean you want me to revert that line?
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.
I honestly am not sure how to deal with this. This branch is unavoidable if we want to avoid unsoundness. If we can find a way to address this without impacting performance, this seems feasible, but otherwise, this is potentially on the hotpath for a lot of operations within the engine, so any tangible performance regression is probably unacceptable. Definitely need to benchmark this in some way to validate.
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.
What is the potential performance issue here? Is it
xor
operation orunwrap()
?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 best way to deal with this is to improve Rust language (there're a lot of discussions like this). But I'm afraid we're not getting it in the next ten years. :(
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 unwrap, the XOR has persistently shown to be easily pipelinable in any current CPUs without adding too much here, but the extra branch and codegen from panicking has shown to have a signficant impact when working with code that is this hot.