Skip to content

Commit 731af70

Browse files
authored
Rollup merge of #92956 - scottmcm:nonzero-log2, r=dtolnay
Add `log2` and `log10` to `NonZeroU*` This version is nice in that it doesn't need to worry about zeros, and thus doesn't have any error cases. cc `int_log` tracking issue #70887 (I didn't add them to `NonZeroI*` despite it being on `i*` since allowing negatives bring back the error cases again.)
2 parents 25f73b7 + 3dfcc66 commit 731af70

File tree

5 files changed

+197
-141
lines changed

5 files changed

+197
-141
lines changed

library/core/src/num/int_log10.rs

+123-124
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,140 @@
1-
mod unchecked {
2-
// 0 < val <= u8::MAX
3-
#[inline]
4-
pub const fn u8(val: u8) -> u32 {
5-
let val = val as u32;
6-
7-
// For better performance, avoid branches by assembling the solution
8-
// in the bits above the low 8 bits.
9-
10-
// Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
11-
const C1: u32 = 0b11_00000000 - 10; // 758
12-
// Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
13-
const C2: u32 = 0b10_00000000 - 100; // 412
14-
15-
// Value of top bits:
16-
// +c1 +c2 1&2
17-
// 0..=9 10 01 00 = 0
18-
// 10..=99 11 01 01 = 1
19-
// 100..=255 11 10 10 = 2
20-
((val + C1) & (val + C2)) >> 8
21-
}
1+
/// These functions compute the integer logarithm of their type, assuming
2+
/// that someone has already checked that the the value is strictly positive.
3+
4+
// 0 < val <= u8::MAX
5+
#[inline]
6+
pub const fn u8(val: u8) -> u32 {
7+
let val = val as u32;
8+
9+
// For better performance, avoid branches by assembling the solution
10+
// in the bits above the low 8 bits.
11+
12+
// Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
13+
const C1: u32 = 0b11_00000000 - 10; // 758
14+
// Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
15+
const C2: u32 = 0b10_00000000 - 100; // 412
16+
17+
// Value of top bits:
18+
// +c1 +c2 1&2
19+
// 0..=9 10 01 00 = 0
20+
// 10..=99 11 01 01 = 1
21+
// 100..=255 11 10 10 = 2
22+
((val + C1) & (val + C2)) >> 8
23+
}
2224

23-
// 0 < val < 100_000
24-
#[inline]
25-
const fn less_than_5(val: u32) -> u32 {
26-
// Similar to u8, when adding one of these constants to val,
27-
// we get two possible bit patterns above the low 17 bits,
28-
// depending on whether val is below or above the threshold.
29-
const C1: u32 = 0b011_00000000000000000 - 10; // 393206
30-
const C2: u32 = 0b100_00000000000000000 - 100; // 524188
31-
const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
32-
const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
33-
34-
// Value of top bits:
35-
// +c1 +c2 1&2 +c3 +c4 3&4 ^
36-
// 0..=9 010 011 010 110 011 010 000 = 0
37-
// 10..=99 011 011 011 110 011 010 001 = 1
38-
// 100..=999 011 100 000 110 011 010 010 = 2
39-
// 1000..=9999 011 100 000 111 011 011 011 = 3
40-
// 10000..=99999 011 100 000 111 100 100 100 = 4
41-
(((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
42-
}
25+
// 0 < val < 100_000
26+
#[inline]
27+
const fn less_than_5(val: u32) -> u32 {
28+
// Similar to u8, when adding one of these constants to val,
29+
// we get two possible bit patterns above the low 17 bits,
30+
// depending on whether val is below or above the threshold.
31+
const C1: u32 = 0b011_00000000000000000 - 10; // 393206
32+
const C2: u32 = 0b100_00000000000000000 - 100; // 524188
33+
const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
34+
const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
35+
36+
// Value of top bits:
37+
// +c1 +c2 1&2 +c3 +c4 3&4 ^
38+
// 0..=9 010 011 010 110 011 010 000 = 0
39+
// 10..=99 011 011 011 110 011 010 001 = 1
40+
// 100..=999 011 100 000 110 011 010 010 = 2
41+
// 1000..=9999 011 100 000 111 011 011 011 = 3
42+
// 10000..=99999 011 100 000 111 100 100 100 = 4
43+
(((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
44+
}
4345

44-
// 0 < val <= u16::MAX
45-
#[inline]
46-
pub const fn u16(val: u16) -> u32 {
47-
less_than_5(val as u32)
48-
}
46+
// 0 < val <= u16::MAX
47+
#[inline]
48+
pub const fn u16(val: u16) -> u32 {
49+
less_than_5(val as u32)
50+
}
4951

50-
// 0 < val <= u32::MAX
51-
#[inline]
52-
pub const fn u32(mut val: u32) -> u32 {
53-
let mut log = 0;
54-
if val >= 100_000 {
55-
val /= 100_000;
56-
log += 5;
57-
}
58-
log + less_than_5(val)
52+
// 0 < val <= u32::MAX
53+
#[inline]
54+
pub const fn u32(mut val: u32) -> u32 {
55+
let mut log = 0;
56+
if val >= 100_000 {
57+
val /= 100_000;
58+
log += 5;
5959
}
60+
log + less_than_5(val)
61+
}
6062

61-
// 0 < val <= u64::MAX
62-
#[inline]
63-
pub const fn u64(mut val: u64) -> u32 {
64-
let mut log = 0;
65-
if val >= 10_000_000_000 {
66-
val /= 10_000_000_000;
67-
log += 10;
68-
}
69-
if val >= 100_000 {
70-
val /= 100_000;
71-
log += 5;
72-
}
73-
log + less_than_5(val as u32)
63+
// 0 < val <= u64::MAX
64+
#[inline]
65+
pub const fn u64(mut val: u64) -> u32 {
66+
let mut log = 0;
67+
if val >= 10_000_000_000 {
68+
val /= 10_000_000_000;
69+
log += 10;
7470
}
75-
76-
// 0 < val <= u128::MAX
77-
#[inline]
78-
pub const fn u128(mut val: u128) -> u32 {
79-
let mut log = 0;
80-
if val >= 100_000_000_000_000_000_000_000_000_000_000 {
81-
val /= 100_000_000_000_000_000_000_000_000_000_000;
82-
log += 32;
83-
return log + u32(val as u32);
84-
}
85-
if val >= 10_000_000_000_000_000 {
86-
val /= 10_000_000_000_000_000;
87-
log += 16;
88-
}
89-
log + u64(val as u64)
71+
if val >= 100_000 {
72+
val /= 100_000;
73+
log += 5;
9074
}
75+
log + less_than_5(val as u32)
76+
}
9177

92-
// 0 < val <= i8::MAX
93-
#[inline]
94-
pub const fn i8(val: i8) -> u32 {
95-
u8(val as u8)
78+
// 0 < val <= u128::MAX
79+
#[inline]
80+
pub const fn u128(mut val: u128) -> u32 {
81+
let mut log = 0;
82+
if val >= 100_000_000_000_000_000_000_000_000_000_000 {
83+
val /= 100_000_000_000_000_000_000_000_000_000_000;
84+
log += 32;
85+
return log + u32(val as u32);
9686
}
97-
98-
// 0 < val <= i16::MAX
99-
#[inline]
100-
pub const fn i16(val: i16) -> u32 {
101-
u16(val as u16)
87+
if val >= 10_000_000_000_000_000 {
88+
val /= 10_000_000_000_000_000;
89+
log += 16;
10290
}
91+
log + u64(val as u64)
92+
}
10393

104-
// 0 < val <= i32::MAX
105-
#[inline]
106-
pub const fn i32(val: i32) -> u32 {
107-
u32(val as u32)
108-
}
94+
#[cfg(target_pointer_width = "16")]
95+
#[inline]
96+
pub const fn usize(val: usize) -> u32 {
97+
u16(val as _)
98+
}
10999

110-
// 0 < val <= i64::MAX
111-
#[inline]
112-
pub const fn i64(val: i64) -> u32 {
113-
u64(val as u64)
114-
}
100+
#[cfg(target_pointer_width = "32")]
101+
#[inline]
102+
pub const fn usize(val: usize) -> u32 {
103+
u32(val as _)
104+
}
115105

116-
// 0 < val <= i128::MAX
117-
#[inline]
118-
pub const fn i128(val: i128) -> u32 {
119-
u128(val as u128)
120-
}
106+
#[cfg(target_pointer_width = "64")]
107+
#[inline]
108+
pub const fn usize(val: usize) -> u32 {
109+
u64(val as _)
110+
}
111+
112+
// 0 < val <= i8::MAX
113+
#[inline]
114+
pub const fn i8(val: i8) -> u32 {
115+
u8(val as u8)
121116
}
122117

123-
macro_rules! impl_checked {
124-
($T:ident) => {
125-
#[inline]
126-
pub const fn $T(val: $T) -> Option<u32> {
127-
if val > 0 { Some(unchecked::$T(val)) } else { None }
128-
}
129-
};
118+
// 0 < val <= i16::MAX
119+
#[inline]
120+
pub const fn i16(val: i16) -> u32 {
121+
u16(val as u16)
130122
}
131123

132-
impl_checked! { u8 }
133-
impl_checked! { u16 }
134-
impl_checked! { u32 }
135-
impl_checked! { u64 }
136-
impl_checked! { u128 }
137-
impl_checked! { i8 }
138-
impl_checked! { i16 }
139-
impl_checked! { i32 }
140-
impl_checked! { i64 }
141-
impl_checked! { i128 }
124+
// 0 < val <= i32::MAX
125+
#[inline]
126+
pub const fn i32(val: i32) -> u32 {
127+
u32(val as u32)
128+
}
129+
130+
// 0 < val <= i64::MAX
131+
#[inline]
132+
pub const fn i64(val: i64) -> u32 {
133+
u64(val as u64)
134+
}
135+
136+
// 0 < val <= i128::MAX
137+
#[inline]
138+
pub const fn i128(val: i128) -> u32 {
139+
u128(val as u128)
140+
}

library/core/src/num/int_macros.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -2362,7 +2362,11 @@ macro_rules! int_impl {
23622362
without modifying the original"]
23632363
#[inline]
23642364
pub const fn checked_log10(self) -> Option<u32> {
2365-
int_log10::$ActualT(self as $ActualT)
2365+
if self > 0 {
2366+
Some(int_log10::$ActualT(self as $ActualT))
2367+
} else {
2368+
None
2369+
}
23662370
}
23672371

23682372
/// Computes the absolute value of `self`.

library/core/src/num/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
264264

265265
#[lang = "u8"]
266266
impl u8 {
267-
uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
267+
uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
268268
"[0x12]", "", "" }
269269
widening_impl! { u8, u16, 8, unsigned }
270270

@@ -813,21 +813,21 @@ impl u8 {
813813

814814
#[lang = "u16"]
815815
impl u16 {
816-
uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
816+
uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
817817
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
818818
widening_impl! { u16, u32, 16, unsigned }
819819
}
820820

821821
#[lang = "u32"]
822822
impl u32 {
823-
uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
823+
uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
824824
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
825825
widening_impl! { u32, u64, 32, unsigned }
826826
}
827827

828828
#[lang = "u64"]
829829
impl u64 {
830-
uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
830+
uint_impl! { u64, u64, i64, NonZeroU64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
831831
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
832832
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
833833
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -837,7 +837,7 @@ impl u64 {
837837

838838
#[lang = "u128"]
839839
impl u128 {
840-
uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16,
840+
uint_impl! { u128, u128, i128, NonZeroU128, 128, 340282366920938463463374607431768211455, 16,
841841
"0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
842842
"0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
843843
"[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -850,15 +850,15 @@ impl u128 {
850850
#[cfg(target_pointer_width = "16")]
851851
#[lang = "usize"]
852852
impl usize {
853-
uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
853+
uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
854854
"[0x34, 0x12]", "[0x12, 0x34]",
855855
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
856856
widening_impl! { usize, u32, 16, unsigned }
857857
}
858858
#[cfg(target_pointer_width = "32")]
859859
#[lang = "usize"]
860860
impl usize {
861-
uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
861+
uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
862862
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
863863
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
864864
widening_impl! { usize, u64, 32, unsigned }
@@ -867,7 +867,7 @@ impl usize {
867867
#[cfg(target_pointer_width = "64")]
868868
#[lang = "usize"]
869869
impl usize {
870-
uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
870+
uint_impl! { usize, u64, isize, NonZeroUsize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
871871
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
872872
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
873873
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",

0 commit comments

Comments
 (0)