-
Notifications
You must be signed in to change notification settings - Fork 20
ACP: add least_significant_one
and most_significant_one
to integer types and NonZero
types
#467
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
Comments
NonZero
typesleast_significant_one
and most_significant_one
to integer types and NonZero
types
We discussed this in the libs-api meeting. We're happy to accept this, but prefer the names |
in that case would |
we considered that but it could just refer to the MSB in an int and mask that. That would be a rather useless method, but still, we're not looking for any bit but for a bit set to one. |
I think We already use the terminology "high-order" bits in the docs, so I don't think
instead? Regardless, I'm happy to see it accepted. |
We have precedents for "leading" and "trailing" methods too -- though maybe that doesn't help because MSB would mean "skip leading zeros and return the one", which isn't really a "leading" one. |
Implement feature `isolate_most_least_significant_one` for integer types Accepted ACP - rust-lang/libs-team#467 Tracking issue - rust-lang#136909 Implement ACP for functions that isolate the most significant set bit and least significant set bit on unsigned, signed, and `NonZero` integers. Add function `isolate_most_significant_one` Add function `isolate_least_significant_one` --- This PR adds the following impls ```rust impl {u8, u16, u32, u64, u128, usize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl {i8, i16, i32, i64, i128, isize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl NonZeroT { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } ``` Example behavior ```rust assert_eq!(u8::isolate_most_significant_one(0b01100100), 0b01000000); assert_eq!(u8::isolate_least_significant_one(0b01100100), 0b00000100); ```
Implement feature `isolate_most_least_significant_one` for integer types Accepted ACP - rust-lang/libs-team#467 Tracking issue - rust-lang#136909 Implement ACP for functions that isolate the most significant set bit and least significant set bit on unsigned, signed, and `NonZero` integers. Add function `isolate_most_significant_one` Add function `isolate_least_significant_one` --- This PR adds the following impls ```rust impl {u8, u16, u32, u64, u128, usize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl {i8, i16, i32, i64, i128, isize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl NonZeroT { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } ``` Example behavior ```rust assert_eq!(u8::isolate_most_significant_one(0b01100100), 0b01000000); assert_eq!(u8::isolate_least_significant_one(0b01100100), 0b00000100); ```
Rollup merge of rust-lang#136910 - okaneco:sig_ones, r=thomcc Implement feature `isolate_most_least_significant_one` for integer types Accepted ACP - rust-lang/libs-team#467 Tracking issue - rust-lang#136909 Implement ACP for functions that isolate the most significant set bit and least significant set bit on unsigned, signed, and `NonZero` integers. Add function `isolate_most_significant_one` Add function `isolate_least_significant_one` --- This PR adds the following impls ```rust impl {u8, u16, u32, u64, u128, usize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl {i8, i16, i32, i64, i128, isize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl NonZeroT { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } ``` Example behavior ```rust assert_eq!(u8::isolate_most_significant_one(0b01100100), 0b01000000); assert_eq!(u8::isolate_least_significant_one(0b01100100), 0b00000100); ```
Implement feature `isolate_most_least_significant_one` for integer types Accepted ACP - rust-lang/libs-team#467 Tracking issue - rust-lang#136909 Implement ACP for functions that isolate the most significant set bit and least significant set bit on unsigned, signed, and `NonZero` integers. Add function `isolate_most_significant_one` Add function `isolate_least_significant_one` --- This PR adds the following impls ```rust impl {u8, u16, u32, u64, u128, usize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl {i8, i16, i32, i64, i128, isize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl NonZeroT { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } ``` Example behavior ```rust assert_eq!(u8::isolate_most_significant_one(0b01100100), 0b01000000); assert_eq!(u8::isolate_least_significant_one(0b01100100), 0b00000100); ```
Implement feature `isolate_most_least_significant_one` for integer types Accepted ACP - rust-lang/libs-team#467 Tracking issue - rust-lang#136909 Implement ACP for functions that isolate the most significant set bit and least significant set bit on unsigned, signed, and `NonZero` integers. Add function `isolate_most_significant_one` Add function `isolate_least_significant_one` --- This PR adds the following impls ```rust impl {u8, u16, u32, u64, u128, usize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl {i8, i16, i32, i64, i128, isize} { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } impl NonZeroT { const fn isolate_most_significant_one(self) -> Self; const fn isolate_least_significant_one(self) -> Self; } ``` Example behavior ```rust assert_eq!(u8::isolate_most_significant_one(0b01100100), 0b01000000); assert_eq!(u8::isolate_least_significant_one(0b01100100), 0b00000100); ```
Proposal
Problem statement
It is common in bit-twiddling code to want to isolate the most significant set bit or the least significant set bit on an integer, for a very wide variety of purposes. Currently in Rust it is quite error prone to do this, for the least significant bit you must remember the following incantation:
and for the most significant bit the following:
These are just the most efficient implementations I've come up with, on x86-64 they compile to 1 and 4 branchless instructions respectively:
Most people will likely find or come up with worse implementations, or worse, buggy ones. Off-by-one errors in shift amounts, or accidental wrapping of shift amounts are common.
Motivating examples or use cases
As mentioned, these functions are widely used in all kinds of bit twiddling. Here are two concrete usage examples but these don't even begin to scratch the surface of the ways in which they could be used.
Summing elements from an array masked by a bitset:
Doing a bitwise binary search on an array:
Solution sketch
I propose we add the following two functions to all integer types, and all
NonZeroT
types:While one could potentially argue that for the normal integer types they should return
Option<Self>
, this is undesirable. There are efficient implementations available that do not check for the zero input, and checking for zero adds extra branches that the caller almost surely does not want. It is always trivial to add a zero check yourself if the behavior at zero is not what you want, but in my experience zero-in zero-out is always what you want for these functions.The
NonZero
variants never have this concern and can always returnSelf
in any design, as there is guaranteed to be a bit set.Alternatives
For
most_significant_one
there isuN::next_power_of_two
defined on unsigned integers which almost-but-not-quite does what you want, and a proposal forprev_power_of_two
which does what you want but not for the zero input. However these methods:next
), andThe
least_significant_one
andmost_significant_one
are well-defined for both signed and unsigned integers on all inputs except zero, and can trivially be extended to zero without conflicting with the "must return a power of two" requirement.Alternative names
To get some bikeshedding out of the way, here are some alternative names:
least_sig_one
/most_sig_one
lowest_one
/highest_one
lowest_bit_set
/highest_bit_set
Links and related work
prev_power_of_two
andbit_width
methods for unsigned integers andNonZero<uN>
#397The text was updated successfully, but these errors were encountered: