talc/
ptr_utils.rs

1//! Generic utilities for pointer handling and sizing.
2
3pub const WORD_SIZE: usize = core::mem::size_of::<usize>();
4pub const WORD_BITS: usize = usize::BITS as usize;
5pub const ALIGN: usize = core::mem::align_of::<usize>();
6
7/// Aligns `ptr` up to the next `align_mask + 1`.
8///
9/// `align_mask` must be a power of two minus one.
10#[inline]
11pub fn align_up_by(ptr: *mut u8, align_mask: usize) -> *mut u8 {
12    debug_assert!((align_mask + 1).is_power_of_two());
13
14    // this incantation maintains provenance of ptr
15    // while allowing the compiler to see through the wrapping_add and optimize it
16    ptr.wrapping_add(((ptr as usize + align_mask) & !align_mask) - ptr as usize)
17    // equivalent to the following:
18    // ((ptr as usize + align_mask) & !align_mask) as *mut u8
19    // i.e. just align up to the next align_mask + 1
20}
21
22pub fn align_down(ptr: *mut u8) -> *mut u8 {
23    ptr.wrapping_sub(ptr as usize % ALIGN)
24}
25pub fn align_up_overflows(ptr: *mut u8) -> bool {
26    ALIGN - 1 > usize::MAX - ptr as usize
27}
28pub fn align_up(ptr: *mut u8) -> *mut u8 {
29    debug_assert!(!align_up_overflows(ptr));
30
31    let offset_ptr = ptr.wrapping_add(ALIGN - 1);
32    offset_ptr.wrapping_sub(offset_ptr as usize % ALIGN)
33}
34
35#[cfg(test)]
36mod tests {
37    use core::ptr::null_mut;
38
39    use super::*;
40
41    #[test]
42    fn align_ptr_test() {
43        assert!(!align_up_overflows(null_mut()));
44        assert!(!align_up_overflows(null_mut::<u8>().wrapping_sub(ALIGN)));
45        assert!(align_up_overflows(null_mut::<u8>().wrapping_sub(ALIGN - 1)));
46        assert!(align_up_overflows(null_mut::<u8>().wrapping_sub(ALIGN - 2)));
47        assert!(align_up_overflows(null_mut::<u8>().wrapping_sub(ALIGN - 3)));
48
49        assert!(align_up(null_mut()) == null_mut());
50        assert!(align_down(null_mut()) == null_mut());
51
52        assert!(align_up(null_mut::<u8>().wrapping_add(1)) == null_mut::<u8>().wrapping_add(ALIGN));
53        assert!(align_up(null_mut::<u8>().wrapping_add(2)) == null_mut::<u8>().wrapping_add(ALIGN));
54        assert!(align_up(null_mut::<u8>().wrapping_add(3)) == null_mut::<u8>().wrapping_add(ALIGN));
55        assert!(
56            align_up(null_mut::<u8>().wrapping_add(ALIGN)) == null_mut::<u8>().wrapping_add(ALIGN)
57        );
58
59        assert!(align_down(null_mut::<u8>().wrapping_add(1)) == null_mut::<u8>());
60        assert!(align_down(null_mut::<u8>().wrapping_add(2)) == null_mut::<u8>());
61        assert!(align_down(null_mut::<u8>().wrapping_add(3)) == null_mut::<u8>());
62        assert!(
63            align_down(null_mut::<u8>().wrapping_add(ALIGN))
64                == null_mut::<u8>().wrapping_add(ALIGN)
65        );
66    }
67}