Skip to content

Commit c14076e

Browse files
authored
Rollup merge of rust-lang#143477 - folkertdev:use-is-multiple-of, r=joshtriplett
use `is_multiple_of` and `div_ceil` In tricky logic, these functions are much more informative than the manual implementations. They also catch subtle bugs: - the manual `is_multiple_of` often does not handle division by zero - manual `div_ceil` often does not consider overflow The transformation is free for `is_multiple_of` if the divisor is compile-time known to be non-zero. For `div_ceil` there is a small cost to considering overflow. Here is some assembly https://godbolt.org/z/5zP8KaE1d.
2 parents f033a22 + 4cf3d66 commit c14076e

File tree

7 files changed

+13
-13
lines changed

7 files changed

+13
-13
lines changed

core/src/slice/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,7 +1316,7 @@ impl<T> [T] {
13161316
assert_unsafe_precondition!(
13171317
check_language_ub,
13181318
"slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
1319-
(n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0,
1319+
(n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n),
13201320
);
13211321
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
13221322
let new_len = unsafe { exact_div(self.len(), N) };
@@ -1512,7 +1512,7 @@ impl<T> [T] {
15121512
assert_unsafe_precondition!(
15131513
check_language_ub,
15141514
"slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
1515-
(n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0
1515+
(n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n)
15161516
);
15171517
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
15181518
let new_len = unsafe { exact_div(self.len(), N) };
@@ -4866,7 +4866,7 @@ impl<T> [T] {
48664866

48674867
let byte_offset = elem_start.wrapping_sub(self_start);
48684868

4869-
if byte_offset % size_of::<T>() != 0 {
4869+
if !byte_offset.is_multiple_of(size_of::<T>()) {
48704870
return None;
48714871
}
48724872

@@ -4920,7 +4920,7 @@ impl<T> [T] {
49204920

49214921
let byte_start = subslice_start.wrapping_sub(self_start);
49224922

4923-
if byte_start % size_of::<T>() != 0 {
4923+
if !byte_start.is_multiple_of(size_of::<T>()) {
49244924
return None;
49254925
}
49264926

core/src/slice/sort/shared/smallsort.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
823823
let right_end = right_rev.wrapping_add(1);
824824

825825
// Odd length, so one element is left unconsumed in the input.
826-
if len % 2 != 0 {
826+
if !len.is_multiple_of(2) {
827827
let left_nonempty = left < left_end;
828828
let last_src = if left_nonempty { left } else { right };
829829
ptr::copy_nonoverlapping(last_src, dst, 1);

core/src/slice/sort/stable/drift.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ fn merge_tree_scale_factor(n: usize) -> u64 {
158158
panic!("Platform not supported");
159159
}
160160

161-
((1 << 62) + n as u64 - 1) / n as u64
161+
(1u64 << 62).div_ceil(n as u64)
162162
}
163163

164164
// Note: merge_tree_depth output is < 64 when left < right as f*x and f*y must
@@ -182,7 +182,7 @@ fn sqrt_approx(n: usize) -> usize {
182182
// Finally we note that the exponentiation / division can be done directly
183183
// with shifts. We OR with 1 to avoid zero-checks in the integer log.
184184
let ilog = (n | 1).ilog2();
185-
let shift = (1 + ilog) / 2;
185+
let shift = ilog.div_ceil(2);
186186
((1 << shift) + (n >> shift)) / 2
187187
}
188188

core/src/str/count.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn do_count_chars(s: &str) -> usize {
5252
// Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required
5353
// for correctness.
5454
const _: () = assert!(CHUNK_SIZE < 256);
55-
const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0);
55+
const _: () = assert!(CHUNK_SIZE.is_multiple_of(UNROLL_INNER));
5656

5757
// SAFETY: transmuting `[u8]` to `[usize]` is safe except for size
5858
// differences which are handled by `align_to`.

core/src/str/iter.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl<'a> Iterator for Chars<'a> {
102102
// `(len + 3)` can't overflow, because we know that the `slice::Iter`
103103
// belongs to a slice in memory which has a maximum length of
104104
// `isize::MAX` (that's well below `usize::MAX`).
105-
((len + 3) / 4, Some(len))
105+
(len.div_ceil(4), Some(len))
106106
}
107107

108108
#[inline]
@@ -1532,11 +1532,11 @@ impl<'a> Iterator for EncodeUtf16<'a> {
15321532
// belongs to a slice in memory which has a maximum length of
15331533
// `isize::MAX` (that's well below `usize::MAX`)
15341534
if self.extra == 0 {
1535-
((len + 2) / 3, Some(len))
1535+
(len.div_ceil(3), Some(len))
15361536
} else {
15371537
// We're in the middle of a surrogate pair, so add the remaining
15381538
// surrogate to the bounds.
1539-
((len + 2) / 3 + 1, Some(len + 1))
1539+
(len.div_ceil(3) + 1, Some(len + 1))
15401540
}
15411541
}
15421542
}

core/src/str/validations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
219219
// Ascii case, try to skip forward quickly.
220220
// When the pointer is aligned, read 2 words of data per iteration
221221
// until we find a word containing a non-ascii byte.
222-
if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 {
222+
if align != usize::MAX && align.wrapping_sub(index).is_multiple_of(USIZE_BYTES) {
223223
let ptr = v.as_ptr();
224224
while index < blocks_end {
225225
// SAFETY: since `align - index` and `ascii_block_size` are

portable-simd/crates/core_simd/src/lane_count.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub struct LaneCount<const N: usize>;
88

99
impl<const N: usize> LaneCount<N> {
1010
/// The number of bytes in a bitmask with this many lanes.
11-
pub const BITMASK_LEN: usize = (N + 7) / 8;
11+
pub const BITMASK_LEN: usize = N.div_ceil(8);
1212
}
1313

1414
/// Statically guarantees that a lane count is marked as supported.

0 commit comments

Comments
 (0)