From 2787a285bd211ecbf75fd95d990226242005d848 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 13 Sep 2017 12:20:39 +0200 Subject: [PATCH] Add `<*const T>::align_offset` and use it in `memchr` --- src/libcore/intrinsics.rs | 33 +-------------- src/libcore/ptr.rs | 75 ++++++++++++++++++++++++++++++++- src/libcore/str/mod.rs | 3 +- src/libstd/lib.rs | 1 + src/libstd/sys_common/memchr.rs | 9 ++-- 5 files changed, 80 insertions(+), 41 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index f7f1dd12d28b1..bc82f0230e5b4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1381,38 +1381,7 @@ extern "rust-intrinsic" { } #[cfg(stage0)] -/// Computes the byte offset that needs to be applied to `ptr` in order to -/// make it aligned to `align`. -/// If it is not possible to align `ptr`, the implementation returns -/// `usize::max_value()`. -/// -/// There are no guarantees whatsover that offsetting the pointer will not -/// overflow or go beyond the allocation that `ptr` points into. -/// It is up to the caller to ensure that the returned offset is correct -/// in all terms other than alignment. -/// -/// # Examples -/// -/// Accessing adjacent `u8` as `u16` -/// -/// ``` -/// # #![feature(core_intrinsics)] -/// # fn foo(n: usize) { -/// # use std::intrinsics::align_offset; -/// # use std::mem::align_of; -/// # unsafe { -/// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; -/// let ptr = &x[n] as *const u8; -/// let offset = align_offset(ptr as *const (), align_of::()); -/// if offset < x.len() - n - 1 { -/// let u16_ptr = ptr.offset(offset as isize) as *const u16; -/// assert_ne!(*u16_ptr, 500); -/// } else { -/// // while the pointer can be aligned via `offset`, it would point -/// // outside the allocation -/// } -/// # } } -/// ``` +/// remove me after the next release pub unsafe fn align_offset(ptr: *const (), align: usize) -> usize { let offset = ptr as usize % align; if offset == 0 { diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index dd01534ec02d9..4041a3760e5ca 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1064,7 +1064,43 @@ impl *const T { copy_nonoverlapping(self, dest, count) } - + /// Computes the byte offset that needs to be applied in order to + /// make the pointer aligned to `align`. + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. + /// + /// There are no guarantees whatsover that offsetting the pointer will not + /// overflow or go beyond the allocation that the pointer points into. + /// It is up to the caller to ensure that the returned offset is correct + /// in all terms other than alignment. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # #![feature(align_offset)] + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.offset(offset as isize) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[unstable(feature = "align_offset", issue = "44488")] + pub fn align_offset(self, align: usize) -> usize { + unsafe { + intrinsics::align_offset(self as *const _, align) + } + } } #[lang = "mut_ptr"] @@ -1284,6 +1320,43 @@ impl *mut T { } } + /// Computes the byte offset that needs to be applied in order to + /// make the pointer aligned to `align`. + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. + /// + /// There are no guarantees whatsover that offsetting the pointer will not + /// overflow or go beyond the allocation that the pointer points into. + /// It is up to the caller to ensure that the returned offset is correct + /// in all terms other than alignment. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # #![feature(align_offset)] + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.offset(offset as isize) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[unstable(feature = "align_offset", issue = "44488")] + pub fn align_offset(self, align: usize) -> usize { + unsafe { + intrinsics::align_offset(self as *const _, align) + } + } /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d4fef45ae4e8f..0d907d11cfba1 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -23,7 +23,6 @@ use fmt; use iter::{Map, Cloned, FusedIterator}; use slice::{self, SliceIndex}; use mem; -use intrinsics::align_offset; pub mod pattern; @@ -1515,7 +1514,7 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let ptr = v.as_ptr(); let align = unsafe { // the offset is safe, because `index` is guaranteed inbounds - align_offset(ptr.offset(index as isize) as *const (), usize_bytes) + ptr.offset(index as isize).align_offset(usize_bytes) }; if align == 0 { while index < blocks_end { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 1a0f8b8d2177e..a3eecd46e9051 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -242,6 +242,7 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] +#![feature(align_offset)] #![feature(asm)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] diff --git a/src/libstd/sys_common/memchr.rs b/src/libstd/sys_common/memchr.rs index 3824a5fb5284c..50f998eb4867d 100644 --- a/src/libstd/sys_common/memchr.rs +++ b/src/libstd/sys_common/memchr.rs @@ -65,15 +65,12 @@ pub mod fallback { let usize_bytes = mem::size_of::(); // search up to an aligned boundary - let align = (ptr as usize) & (usize_bytes- 1); - let mut offset; - if align > 0 { - offset = cmp::min(usize_bytes - align, len); + let mut offset = ptr.align_offset(usize_bytes); + if offset > 0 { + offset = cmp::min(offset, len); if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { return Some(index); } - } else { - offset = 0; } // search the body of the text