about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-08-30 08:06:42 +0000
committerbors <bors@rust-lang.org>2017-08-30 08:06:42 +0000
commitc66e7fa8dee0b6b2b5439e2bd527ab66c9fbde13 (patch)
tree3aa5b315b66f38c18890c727d66e48b9f1e7ef7b /src/libcore
parentb58e31ac03d3f338385593496426534ad5a150a7 (diff)
parentbe96ad2c85b680be68d38ab7aa115f0b9c32b3d5 (diff)
downloadrust-c66e7fa8dee0b6b2b5439e2bd527ab66c9fbde13.tar.gz
rust-c66e7fa8dee0b6b2b5439e2bd527ab66c9fbde13.zip
Auto merge of #43903 - oli-obk:alignto, r=aturon
Add align_offset intrinsic

see https://github.com/rust-lang/rfcs/pull/2043 for details and the plan towards stabilization (reexport in `core::mem` via various convenience functions)

as per @scottmcm 's [comment](https://github.com/rust-lang/rfcs/pull/2043#issuecomment-316818169), this is just the intrinsic (which is obviously unstable).
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/intrinsics.rs77
-rw-r--r--src/libcore/str/mod.rs6
2 files changed, 82 insertions, 1 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index ad776c8605a..607f6f37017 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1343,4 +1343,81 @@ extern "rust-intrinsic" {
     /// on MSVC it's `*mut [usize; 2]`. For more information see the compiler's
     /// source as well as std's catch implementation.
     pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;
+
+    /// 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::<u16>());
+    /// 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
+    /// }
+    /// # } }
+    /// ```
+    #[cfg(not(stage0))]
+    pub fn align_offset(ptr: *const (), align: usize) -> usize;
+}
+
+#[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::<u16>());
+/// 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
+/// }
+/// # } }
+/// ```
+pub unsafe fn align_offset(ptr: *const (), align: usize) -> usize {
+    let offset = ptr as usize % align;
+    if offset == 0 {
+        0
+    } else {
+        align - offset
+    }
 }
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index a5f6e49a53b..62e84c9ebd0 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -23,6 +23,7 @@ use fmt;
 use iter::{Map, Cloned, FusedIterator};
 use slice::{self, SliceIndex};
 use mem;
+use intrinsics::align_offset;
 
 pub mod pattern;
 
@@ -1468,7 +1469,10 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
             // When the pointer is aligned, read 2 words of data per iteration
             // until we find a word containing a non-ascii byte.
             let ptr = v.as_ptr();
-            let align = (ptr as usize + index) & (usize_bytes - 1);
+            let align = unsafe {
+                // the offset is safe, because `index` is guaranteed inbounds
+                align_offset(ptr.offset(index as isize) as *const (), usize_bytes)
+            };
             if align == 0 {
                 while index < blocks_end {
                     unsafe {