Created
August 16, 2018 01:53
-
-
Save abcdabcd987/fb1f93a569bd6e4ddd7ac0b748b71af4 to your computer and use it in GitHub Desktop.
patch https://web.stanford.edu/class/cs140e/os.git @2-Fs @41ef36e for rustc 1.28.0-nightly (cd494c1f0 2018-06-27); https://abcdabcd987.com/cs140e-2-fs/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -ruN orig/kernel/src/allocator/bin.rs new/kernel/src/allocator/bin.rs | |
--- orig/kernel/src/allocator/bin.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/kernel/src/allocator/bin.rs 2018-08-04 11:18:29.000000000 +0800 | |
@@ -1,5 +1,6 @@ | |
use std::fmt; | |
-use alloc::heap::{AllocErr, Layout}; | |
+use core::alloc::{AllocErr, Layout}; | |
+use core::ptr::NonNull; | |
use allocator::util::*; | |
use allocator::linked_list::LinkedList; | |
@@ -16,45 +17,66 @@ | |
unimplemented!("bin allocator") | |
} | |
- /// Allocates memory. Returns a pointer meeting the size and alignment | |
- /// properties of `layout.size()` and `layout.align()`. | |
+ | |
+ /// Returns a pointer meeting the size and alignment guarantees of | |
+ /// `layout`. | |
/// | |
- /// If this method returns an `Ok(addr)`, `addr` will be non-null address | |
- /// pointing to a block of storage suitable for holding an instance of | |
- /// `layout`. In particular, the block will be at least `layout.size()` | |
- /// bytes large and will be aligned to `layout.align()`. The returned block | |
- /// of storage may or may not have its contents initialized or zeroed. | |
+ /// If this method returns an `Ok(addr)`, then the `addr` returned | |
+ /// will be non-null address pointing to a block of storage | |
+ /// suitable for holding an instance of `layout`. | |
+ /// | |
+ /// The returned block of storage may or may not have its contents | |
+ /// initialized. (Extension subtraits might restrict this | |
+ /// behavior, e.g. to ensure initialization to particular sets of | |
+ /// bit patterns.) | |
/// | |
/// # Safety | |
/// | |
- /// The _caller_ must ensure that `layout.size() > 0` and that | |
- /// `layout.align()` is a power of two. Parameters not meeting these | |
- /// conditions may result in undefined behavior. | |
+ /// This function is unsafe because undefined behavior can result | |
+ /// if the caller does not ensure that `layout` has non-zero size. | |
+ /// | |
+ /// (Extension subtraits might provide more specific bounds on | |
+ /// behavior, e.g. guarantee a sentinel address or a null pointer | |
+ /// in response to a zero-size allocation request.) | |
/// | |
/// # Errors | |
/// | |
- /// Returning `Err` indicates that either memory is exhausted | |
- /// (`AllocError::Exhausted`) or `layout` does not meet this allocator's | |
- /// size or alignment constraints (`AllocError::Unsupported`). | |
- pub fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { | |
- unimplemented!("bin allocation") | |
+ /// Returning `Err` indicates that either memory is exhausted or | |
+ /// `layout` does not meet allocator's size or alignment | |
+ /// constraints. | |
+ /// | |
+ /// Implementations are encouraged to return `Err` on memory | |
+ /// exhaustion rather than panicking or aborting, but this is not | |
+ /// a strict requirement. (Specifically: it is *legal* to | |
+ /// implement this trait atop an underlying native allocation | |
+ /// library that aborts on memory exhaustion.) | |
+ /// | |
+ /// Clients wishing to abort computation in response to an | |
+ /// allocation error are encouraged to call the [`handle_alloc_error`] function, | |
+ /// rather than directly invoking `panic!` or similar. | |
+ /// | |
+ /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html | |
+ pub fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> { | |
+ unimplemented!("bump allocation") | |
} | |
- /// Deallocates the memory referenced by `ptr`. | |
+ /// Deallocate the memory referenced by `ptr`. | |
/// | |
/// # Safety | |
/// | |
- /// The _caller_ must ensure the following: | |
+ /// This function is unsafe because undefined behavior can result | |
+ /// if the caller does not ensure all of the following: | |
+ /// | |
+ /// * `ptr` must denote a block of memory currently allocated via | |
+ /// this allocator, | |
+ /// | |
+ /// * `layout` must *fit* that block of memory, | |
/// | |
- /// * `ptr` must denote a block of memory currently allocated via this | |
- /// allocator | |
- /// * `layout` must properly represent the original layout used in the | |
- /// allocation call that returned `ptr` | |
- /// | |
- /// Parameters not meeting these conditions may result in undefined | |
- /// behavior. | |
- pub fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { | |
- unimplemented!("bin deallocation") | |
+ /// * In addition to fitting the block of memory `layout`, the | |
+ /// alignment of the `layout` must match the alignment used | |
+ /// to allocate that block of memory. | |
+ pub fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { | |
+ unimplemented!("bump deallocation") | |
} | |
} | |
// | |
diff -ruN orig/kernel/src/allocator/bump.rs new/kernel/src/allocator/bump.rs | |
--- orig/kernel/src/allocator/bump.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/kernel/src/allocator/bump.rs 2018-08-04 11:17:49.000000000 +0800 | |
@@ -1,4 +1,5 @@ | |
-use alloc::heap::{AllocErr, Layout}; | |
+use core::alloc::{Layout, AllocErr}; | |
+use core::ptr::NonNull; | |
use allocator::util::*; | |
@@ -16,44 +17,64 @@ | |
unimplemented!("bump allocator") | |
} | |
- /// Allocates memory. Returns a pointer meeting the size and alignment | |
- /// properties of `layout.size()` and `layout.align()`. | |
+ /// Returns a pointer meeting the size and alignment guarantees of | |
+ /// `layout`. | |
/// | |
- /// If this method returns an `Ok(addr)`, `addr` will be non-null address | |
- /// pointing to a block of storage suitable for holding an instance of | |
- /// `layout`. In particular, the block will be at least `layout.size()` | |
- /// bytes large and will be aligned to `layout.align()`. The returned block | |
- /// of storage may or may not have its contents initialized or zeroed. | |
+ /// If this method returns an `Ok(addr)`, then the `addr` returned | |
+ /// will be non-null address pointing to a block of storage | |
+ /// suitable for holding an instance of `layout`. | |
+ /// | |
+ /// The returned block of storage may or may not have its contents | |
+ /// initialized. (Extension subtraits might restrict this | |
+ /// behavior, e.g. to ensure initialization to particular sets of | |
+ /// bit patterns.) | |
/// | |
/// # Safety | |
/// | |
- /// The _caller_ must ensure that `layout.size() > 0` and that | |
- /// `layout.align()` is a power of two. Parameters not meeting these | |
- /// conditions may result in undefined behavior. | |
+ /// This function is unsafe because undefined behavior can result | |
+ /// if the caller does not ensure that `layout` has non-zero size. | |
+ /// | |
+ /// (Extension subtraits might provide more specific bounds on | |
+ /// behavior, e.g. guarantee a sentinel address or a null pointer | |
+ /// in response to a zero-size allocation request.) | |
/// | |
/// # Errors | |
/// | |
- /// Returning `Err` indicates that either memory is exhausted | |
- /// (`AllocError::Exhausted`) or `layout` does not meet this allocator's | |
- /// size or alignment constraints (`AllocError::Unsupported`). | |
- pub fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { | |
+ /// Returning `Err` indicates that either memory is exhausted or | |
+ /// `layout` does not meet allocator's size or alignment | |
+ /// constraints. | |
+ /// | |
+ /// Implementations are encouraged to return `Err` on memory | |
+ /// exhaustion rather than panicking or aborting, but this is not | |
+ /// a strict requirement. (Specifically: it is *legal* to | |
+ /// implement this trait atop an underlying native allocation | |
+ /// library that aborts on memory exhaustion.) | |
+ /// | |
+ /// Clients wishing to abort computation in response to an | |
+ /// allocation error are encouraged to call the [`handle_alloc_error`] function, | |
+ /// rather than directly invoking `panic!` or similar. | |
+ /// | |
+ /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html | |
+ pub fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> { | |
unimplemented!("bump allocation") | |
} | |
- /// Deallocates the memory referenced by `ptr`. | |
+ /// Deallocate the memory referenced by `ptr`. | |
/// | |
/// # Safety | |
/// | |
- /// The _caller_ must ensure the following: | |
+ /// This function is unsafe because undefined behavior can result | |
+ /// if the caller does not ensure all of the following: | |
+ /// | |
+ /// * `ptr` must denote a block of memory currently allocated via | |
+ /// this allocator, | |
+ /// | |
+ /// * `layout` must *fit* that block of memory, | |
/// | |
- /// * `ptr` must denote a block of memory currently allocated via this | |
- /// allocator | |
- /// * `layout` must properly represent the original layout used in the | |
- /// allocation call that returned `ptr` | |
- /// | |
- /// Parameters not meeting these conditions may result in undefined | |
- /// behavior. | |
- pub fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) { | |
+ /// * In addition to fitting the block of memory `layout`, the | |
+ /// alignment of the `layout` must match the alignment used | |
+ /// to allocate that block of memory. | |
+ pub fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { | |
unimplemented!("bump deallocation") | |
} | |
} | |
diff -ruN orig/kernel/src/allocator/mod.rs new/kernel/src/allocator/mod.rs | |
--- orig/kernel/src/allocator/mod.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/kernel/src/allocator/mod.rs 2018-08-04 11:09:18.000000000 +0800 | |
@@ -7,8 +7,10 @@ | |
#[cfg(test)] | |
mod tests; | |
+use core::ptr; | |
+use core::ptr::NonNull; | |
use mutex::Mutex; | |
-use alloc::heap::{Alloc, AllocErr, Layout}; | |
+use core::alloc::{GlobalAlloc, Layout}; | |
use std::cmp::max; | |
/// Thread-safe (locking) wrapper around a particular memory allocator. | |
@@ -35,46 +37,61 @@ | |
} | |
} | |
-unsafe impl<'a> Alloc for &'a Allocator { | |
- /// Allocates memory. Returns a pointer meeting the size and alignment | |
- /// properties of `layout.size()` and `layout.align()`. | |
- /// | |
- /// If this method returns an `Ok(addr)`, `addr` will be non-null address | |
- /// pointing to a block of storage suitable for holding an instance of | |
- /// `layout`. In particular, the block will be at least `layout.size()` | |
- /// bytes large and will be aligned to `layout.align()`. The returned block | |
- /// of storage may or may not have its contents initialized or zeroed. | |
+unsafe impl GlobalAlloc for Allocator { | |
+ | |
+ /// Allocate memory as described by the given `layout`. | |
+ /// | |
+ /// Returns a pointer to newly-allocated memory, | |
+ /// or null to indicate allocation failure. | |
/// | |
/// # Safety | |
/// | |
- /// The _caller_ must ensure that `layout.size() > 0` and that | |
- /// `layout.align()` is a power of two. Parameters not meeting these | |
- /// conditions may result in undefined behavior. | |
+ /// This function is unsafe because undefined behavior can result | |
+ /// if the caller does not ensure that `layout` has non-zero size. | |
+ /// | |
+ /// (Extension subtraits might provide more specific bounds on | |
+ /// behavior, e.g. guarantee a sentinel address or a null pointer | |
+ /// in response to a zero-size allocation request.) | |
+ /// | |
+ /// The allocated block of memory may or may not be initialized. | |
/// | |
/// # Errors | |
/// | |
- /// Returning `Err` indicates that either memory is exhausted | |
- /// (`AllocError::Exhausted`) or `layout` does not meet this allocator's | |
- /// size or alignment constraints (`AllocError::Unsupported`). | |
- unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { | |
- self.0.lock().as_mut().expect("allocator uninitialized").alloc(layout) | |
+ /// Returning a null pointer indicates that either memory is exhausted | |
+ /// or `layout` does not meet allocator's size or alignment constraints. | |
+ /// | |
+ /// Implementations are encouraged to return null on memory | |
+ /// exhaustion rather than aborting, but this is not | |
+ /// a strict requirement. (Specifically: it is *legal* to | |
+ /// implement this trait atop an underlying native allocation | |
+ /// library that aborts on memory exhaustion.) | |
+ /// | |
+ /// Clients wishing to abort computation in response to an | |
+ /// allocation error are encouraged to call the [`handle_alloc_error`] function, | |
+ /// rather than directly invoking `panic!` or similar. | |
+ /// | |
+ /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html | |
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | |
+ match self.0.lock().as_mut().expect("allocator uninitialized").alloc(layout) { | |
+ Ok(ptr) => ptr.as_ptr(), | |
+ Err(_) => ptr::null_mut() | |
+ } | |
} | |
- /// Deallocates the memory referenced by `ptr`. | |
+ /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. | |
/// | |
/// # Safety | |
/// | |
- /// The _caller_ must ensure the following: | |
+ /// This function is unsafe because undefined behavior can result | |
+ /// if the caller does not ensure all of the following: | |
+ /// | |
+ /// * `ptr` must denote a block of memory currently allocated via | |
+ /// this allocator, | |
/// | |
- /// * `ptr` must denote a block of memory currently allocated via this | |
- /// allocator | |
- /// * `layout` must properly represent the original layout used in the | |
- /// allocation call that returned `ptr` | |
- /// | |
- /// Parameters not meeting these conditions may result in undefined | |
- /// behavior. | |
- unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { | |
- self.0.lock().as_mut().expect("allocator uninitialized").dealloc(ptr, layout); | |
+ /// * `layout` must be the same layout that was used | |
+ /// to allocated that block of memory, | |
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | |
+ self.0.lock().as_mut().expect("allocator uninitialized").dealloc(NonNull::new(ptr).unwrap(), layout); | |
} | |
} | |
diff -ruN orig/kernel/src/allocator/tests.rs new/kernel/src/allocator/tests.rs | |
--- orig/kernel/src/allocator/tests.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/kernel/src/allocator/tests.rs 2018-08-04 11:20:02.000000000 +0800 | |
@@ -59,7 +59,8 @@ | |
#[allow(dead_code)] mod bump; | |
#[allow(dead_code)] mod bin; | |
- use alloc::allocator::{AllocErr, Layout}; | |
+ use core::ptr::NonNull; | |
+ use core::alloc::{AllocErr, Layout}; | |
use alloc::raw_vec::RawVec; | |
macro test_allocators { | |
@@ -91,7 +92,7 @@ | |
let mut pointers: Vec<(usize, Layout)> = vec![]; | |
for layout in &layouts { | |
- let ptr = a.alloc(layout.clone()).unwrap() as usize; | |
+ let ptr = a.alloc(layout.clone()).unwrap().as_ptr() as usize; | |
pointers.push((ptr, layout.clone())); | |
} | |
@@ -119,7 +120,7 @@ | |
test_allocators!(bin_exhausted, bump_exhausted, 128, |(_, _, mut a)| { | |
let e = a.alloc(layout!(1024, 128)).unwrap_err(); | |
- assert_eq!(e, AllocErr::Exhausted { request: layout!(1024, 128) }) | |
+ assert_eq!(e, AllocErr) | |
}); | |
test_allocators!(bin_alloc, bump_alloc, 8 * (1 << 20), |(start, end, a)| { | |
@@ -171,7 +172,7 @@ | |
let mut pointers: Vec<(usize, Layout)> = vec![]; | |
for layout in &layouts { | |
- let ptr = a.alloc(layout.clone()).unwrap(); | |
+ let ptr = a.alloc(layout.clone()).unwrap().as_ptr(); | |
scribble(ptr, layout.size()); | |
pointers.push((ptr as usize, layout.clone())); | |
} | |
@@ -179,7 +180,7 @@ | |
// Just check that deallocation doesn't panic. | |
for (ptr, layout) in pointers { | |
scribble(ptr as *mut u8, layout.size()); | |
- a.dealloc(ptr as *mut u8, layout); | |
+ a.dealloc(NonNull::new(ptr as *mut u8).unwrap(), layout); | |
} | |
}); | |
@@ -198,7 +199,7 @@ | |
for (i, layout) in layouts.iter().enumerate() { | |
let mut ptrs = vec![]; | |
for _ in 0..(25 + i * 2) { | |
- let ptr = a.alloc(layout.clone()).expect("allocation"); | |
+ let ptr = a.alloc(layout.clone()).expect("allocation").as_ptr(); | |
assert!(ptr as usize % layout.align() == 0, | |
"{:x} is not aligned to {}", ptr as usize, layout.align()); | |
scribble(ptr, layout.size()); | |
@@ -206,17 +207,17 @@ | |
} | |
for (ptr, layout) in ptrs { | |
- a.dealloc(ptr, layout); | |
+ a.dealloc(NonNull::new(ptr).unwrap(), layout); | |
} | |
} | |
for _ in 0..500 { | |
for layout in &layouts { | |
- let ptr = a.alloc(layout.clone()).expect("allocation"); | |
+ let ptr = a.alloc(layout.clone()).expect("allocation").as_ptr(); | |
scribble(ptr, layout.size()); | |
assert!(ptr as usize % layout.align() == 0, | |
"{:x} is not aligned to {}", ptr as usize, layout.align()); | |
- a.dealloc(ptr, layout.clone()); | |
+ a.dealloc(NonNull::new(ptr).unwrap(), layout.clone()); | |
} | |
} | |
}); | |
@@ -232,14 +233,14 @@ | |
for _ in 0..1000 { | |
let mut ptrs = vec![]; | |
for layout in &layouts { | |
- let ptr = a.alloc(layout.clone()).expect("allocation"); | |
+ let ptr = a.alloc(layout.clone()).expect("allocation").as_ptr(); | |
scribble(ptr, layout.size()); | |
ptrs.push(ptr as usize); | |
} | |
for (layout, ptr) in layouts.iter().zip(ptrs.into_iter()) { | |
scribble(ptr as *mut u8, layout.size()); | |
- a.dealloc(ptr as *mut u8, layout.clone()); | |
+ a.dealloc(NonNull::new(ptr as *mut u8).unwrap(), layout.clone()); | |
} | |
} | |
}); | |
diff -ruN orig/kernel/src/kmain.rs new/kernel/src/kmain.rs | |
--- orig/kernel/src/kmain.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/kernel/src/kmain.rs 2018-08-02 13:34:52.000000000 +0800 | |
@@ -4,14 +4,14 @@ | |
#![feature(asm)] | |
#![feature(optin_builtin_traits)] | |
#![feature(decl_macro)] | |
-#![feature(repr_align)] | |
#![feature(attr_literals)] | |
#![feature(exclusive_range_pattern)] | |
-#![feature(alloc, allocator_api, global_allocator)] | |
+#![feature(alloc, allocator_api)] | |
#[macro_use] | |
#[allow(unused_imports)] | |
extern crate alloc; | |
+extern crate core; | |
extern crate pi; | |
extern crate stack_vec; | |
extern crate fat32; | |
diff -ruN orig/kernel/src/lang_items.rs new/kernel/src/lang_items.rs | |
--- orig/kernel/src/lang_items.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/kernel/src/lang_items.rs 2018-08-02 11:38:48.000000000 +0800 | |
@@ -1,7 +1,9 @@ | |
+use core::panic::PanicInfo; | |
+ | |
#[no_mangle] | |
#[cfg(not(test))] | |
-#[lang = "panic_fmt"] | |
-pub extern fn panic_fmt(fmt: ::std::fmt::Arguments, file: &'static str, line: u32, col: u32) -> ! { | |
+#[lang = "panic_impl"] | |
+pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { | |
// FIXME: Print `fmt`, `file`, and `line` to the console. | |
loop { unsafe { asm!("wfe") } } | |
Binary files orig/std/.DS_Store and new/std/.DS_Store differ | |
diff -ruN orig/std/src/alloc.rs new/std/src/alloc.rs | |
--- orig/std/src/alloc.rs 1970-01-01 08:00:00.000000000 +0800 | |
+++ new/std/src/alloc.rs 2018-08-02 11:04:41.000000000 +0800 | |
@@ -0,0 +1,184 @@ | |
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | |
+// file at the top-level directory of this distribution and at | |
+// http://rust-lang.org/COPYRIGHT. | |
+// | |
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
+// option. This file may not be copied, modified, or distributed | |
+// except according to those terms. | |
+ | |
+//! Memory allocation APIs | |
+//! | |
+//! In a given program, the standard library has one “global” memory allocator | |
+//! that is used for example by `Box<T>` and `Vec<T>`. | |
+//! | |
+//! Currently the default global allocator is unspecified. | |
+//! The compiler may link to a version of [jemalloc] on some platforms, | |
+//! but this is not guaranteed. | |
+//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed | |
+//! to use the [`System`] by default. | |
+//! | |
+//! [jemalloc]: https://github.com/jemalloc/jemalloc | |
+//! [`System`]: struct.System.html | |
+//! | |
+//! # The `#[global_allocator]` attribute | |
+//! | |
+//! This attribute allows configuring the choice of global allocator. | |
+//! You can use this to implement a completely custom global allocator | |
+//! to route all default allocation requests to a custom object. | |
+//! | |
+//! ```rust | |
+//! use std::alloc::{GlobalAlloc, System, Layout}; | |
+//! | |
+//! struct MyAllocator; | |
+//! | |
+//! unsafe impl GlobalAlloc for MyAllocator { | |
+//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | |
+//! System.alloc(layout) | |
+//! } | |
+//! | |
+//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | |
+//! System.dealloc(ptr, layout) | |
+//! } | |
+//! } | |
+//! | |
+//! #[global_allocator] | |
+//! static GLOBAL: MyAllocator = MyAllocator; | |
+//! | |
+//! fn main() { | |
+//! // This `Vec` will allocate memory through `GLOBAL` above | |
+//! let mut v = Vec::new(); | |
+//! v.push(1); | |
+//! } | |
+//! ``` | |
+//! | |
+//! The attribute is used on a `static` item whose type implements the | |
+//! [`GlobalAlloc`] trait. This type can be provided by an external library: | |
+//! | |
+//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html | |
+//! | |
+//! ```rust,ignore (demonstrates crates.io usage) | |
+//! extern crate jemallocator; | |
+//! | |
+//! use jemallacator::Jemalloc; | |
+//! | |
+//! #[global_allocator] | |
+//! static GLOBAL: Jemalloc = Jemalloc; | |
+//! | |
+//! fn main() {} | |
+//! ``` | |
+//! | |
+//! The `#[global_allocator]` can only be used once in a crate | |
+//! or its recursive dependencies. | |
+ | |
+#![stable(feature = "alloc_module", since = "1.28.0")] | |
+ | |
+use core::sync::atomic::{AtomicPtr, Ordering}; | |
+use core::{mem, ptr}; | |
+// use sys_common::util::dumb_print; | |
+ | |
+#[stable(feature = "alloc_module", since = "1.28.0")] | |
+#[doc(inline)] | |
+pub use alloc_crate::alloc::*; | |
+ | |
+// #[stable(feature = "alloc_system_type", since = "1.28.0")] | |
+// #[doc(inline)] | |
+// pub use alloc_system::System; | |
+ | |
+static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); | |
+ | |
+/// Registers a custom allocation error hook, replacing any that was previously registered. | |
+/// | |
+/// The allocation error hook is invoked when an infallible memory allocation fails, before | |
+/// the runtime aborts. The default hook prints a message to standard error, | |
+/// but this behavior can be customized with the [`set_alloc_error_hook`] and | |
+/// [`take_alloc_error_hook`] functions. | |
+/// | |
+/// The hook is provided with a `Layout` struct which contains information | |
+/// about the allocation that failed. | |
+/// | |
+/// The allocation error hook is a global resource. | |
+#[unstable(feature = "alloc_error_hook", issue = "51245")] | |
+pub fn set_alloc_error_hook(hook: fn(Layout)) { | |
+ HOOK.store(hook as *mut (), Ordering::SeqCst); | |
+} | |
+ | |
+/// Unregisters the current allocation error hook, returning it. | |
+/// | |
+/// *See also the function [`set_alloc_error_hook`].* | |
+/// | |
+/// If no custom hook is registered, the default hook will be returned. | |
+#[unstable(feature = "alloc_error_hook", issue = "51245")] | |
+pub fn take_alloc_error_hook() -> fn(Layout) { | |
+ let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); | |
+ if hook.is_null() { | |
+ default_alloc_error_hook | |
+ } else { | |
+ unsafe { mem::transmute(hook) } | |
+ } | |
+} | |
+ | |
+fn default_alloc_error_hook(_layout: Layout) { | |
+ // dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); | |
+} | |
+ | |
+#[cfg(not(test))] | |
+#[doc(hidden)] | |
+#[lang = "oom"] | |
+#[unstable(feature = "alloc_internals", issue = "0")] | |
+pub extern fn rust_oom(layout: Layout) -> ! { | |
+ let hook = HOOK.load(Ordering::SeqCst); | |
+ let hook: fn(Layout) = if hook.is_null() { | |
+ default_alloc_error_hook | |
+ } else { | |
+ unsafe { mem::transmute(hook) } | |
+ }; | |
+ hook(layout); | |
+ unsafe { ::sys::abort_internal(); } | |
+} | |
+ | |
+// #[cfg(not(test))] | |
+// #[doc(hidden)] | |
+// #[allow(unused_attributes)] | |
+// #[unstable(feature = "alloc_internals", issue = "0")] | |
+// pub mod __default_lib_allocator { | |
+// use super::{System, Layout, GlobalAlloc}; | |
+// // for symbol names src/librustc/middle/allocator.rs | |
+// // for signatures src/librustc_allocator/lib.rs | |
+ | |
+// // linkage directives are provided as part of the current compiler allocator | |
+// // ABI | |
+ | |
+// #[no_mangle] | |
+// #[rustc_std_internal_symbol] | |
+// pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { | |
+// let layout = Layout::from_size_align_unchecked(size, align); | |
+// System.alloc(layout) | |
+// } | |
+ | |
+// #[no_mangle] | |
+// #[rustc_std_internal_symbol] | |
+// pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, | |
+// size: usize, | |
+// align: usize) { | |
+// System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) | |
+// } | |
+ | |
+// #[no_mangle] | |
+// #[rustc_std_internal_symbol] | |
+// pub unsafe extern fn __rdl_realloc(ptr: *mut u8, | |
+// old_size: usize, | |
+// align: usize, | |
+// new_size: usize) -> *mut u8 { | |
+// let old_layout = Layout::from_size_align_unchecked(old_size, align); | |
+// System.realloc(ptr, old_layout, new_size) | |
+// } | |
+ | |
+// #[no_mangle] | |
+// #[rustc_std_internal_symbol] | |
+// pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { | |
+// let layout = Layout::from_size_align_unchecked(size, align); | |
+// System.alloc_zeroed(layout) | |
+// } | |
+// } | |
diff -ruN orig/std/src/ascii.rs new/std/src/ascii.rs | |
--- orig/std/src/ascii.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/ascii.rs 2018-08-02 11:04:18.000000000 +0800 | |
@@ -24,11 +24,10 @@ | |
//! [`AsciiExt`]: trait.AsciiExt.html | |
//! [`escape_default`]: fn.escape_default.html | |
-#![stable(feature = "rust1", since = "1.0.0")] | |
+// #![stable(feature = "rust1", since = "1.0.0")] | |
-use fmt; | |
-use ops::Range; | |
-use iter::FusedIterator; | |
+#[stable(feature = "rust1", since = "1.0.0")] | |
+pub use core::ascii::{EscapeDefault, escape_default}; | |
/// Extension methods for ASCII-subset only operations. | |
/// | |
@@ -53,6 +52,7 @@ | |
/// | |
/// [combining character]: https://en.wikipedia.org/wiki/Combining_character | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
pub trait AsciiExt { | |
/// Container type for copied ASCII characters. | |
#[stable(feature = "rust1", since = "1.0.0")] | |
@@ -85,6 +85,7 @@ | |
/// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase | |
/// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+ #[allow(deprecated)] | |
fn to_ascii_uppercase(&self) -> Self::Owned; | |
/// Makes a copy of the value in its ASCII lower case equivalent. | |
@@ -105,6 +106,7 @@ | |
/// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase | |
/// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+ #[allow(deprecated)] | |
fn to_ascii_lowercase(&self) -> Self::Owned; | |
/// Checks that two values are an ASCII case-insensitive match. | |
@@ -163,6 +165,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII uppercase character: | |
@@ -175,6 +178,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII lowercase character: | |
@@ -187,6 +191,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII alphanumeric character: | |
@@ -200,6 +205,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII decimal digit: | |
@@ -212,6 +218,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_digit(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII hexadecimal digit: | |
@@ -225,6 +232,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII punctuation character: | |
@@ -242,10 +250,11 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII graphic character: | |
- /// U+0021 '@' ... U+007E '~'. | |
+ /// U+0021 '!' ... U+007E '~'. | |
/// For strings, true if all characters in the string are | |
/// ASCII graphic characters. | |
/// | |
@@ -254,6 +263,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_graphic(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII whitespace character: | |
@@ -283,6 +293,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } | |
/// Checks if the value is an ASCII control character: | |
@@ -295,6 +306,7 @@ | |
/// This method will be deprecated in favor of the identically-named | |
/// inherent methods on `u8`, `char`, `[u8]` and `str`. | |
#[unstable(feature = "ascii_ctype", issue = "39658")] | |
+ #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] | |
fn is_ascii_control(&self) -> bool { unimplemented!(); } | |
} | |
@@ -355,6 +367,7 @@ | |
} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+#[allow(deprecated)] | |
impl AsciiExt for u8 { | |
type Owned = u8; | |
@@ -363,6 +376,7 @@ | |
} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+#[allow(deprecated)] | |
impl AsciiExt for char { | |
type Owned = char; | |
@@ -371,6 +385,7 @@ | |
} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+#[allow(deprecated)] | |
impl AsciiExt for [u8] { | |
type Owned = Vec<u8>; | |
@@ -428,6 +443,7 @@ | |
} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
+#[allow(deprecated)] | |
impl AsciiExt for str { | |
type Owned = String; | |
@@ -483,477 +499,3 @@ | |
self.bytes().all(|b| b.is_ascii_control()) | |
} | |
} | |
- | |
-/// An iterator over the escaped version of a byte. | |
-/// | |
-/// This `struct` is created by the [`escape_default`] function. See its | |
-/// documentation for more. | |
-/// | |
-/// [`escape_default`]: fn.escape_default.html | |
-#[stable(feature = "rust1", since = "1.0.0")] | |
-pub struct EscapeDefault { | |
- range: Range<usize>, | |
- data: [u8; 4], | |
-} | |
- | |
-/// Returns an iterator that produces an escaped version of a `u8`. | |
-/// | |
-/// The default is chosen with a bias toward producing literals that are | |
-/// legal in a variety of languages, including C++11 and similar C-family | |
-/// languages. The exact rules are: | |
-/// | |
-/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. | |
-/// - Single-quote, double-quote and backslash chars are backslash-escaped. | |
-/// - Any other chars in the range [0x20,0x7e] are not escaped. | |
-/// - Any other chars are given hex escapes of the form '\xNN'. | |
-/// - Unicode escapes are never generated by this function. | |
-/// | |
-/// # Examples | |
-/// | |
-/// ``` | |
-/// use std::ascii; | |
-/// | |
-/// let escaped = ascii::escape_default(b'0').next().unwrap(); | |
-/// assert_eq!(b'0', escaped); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'\t'); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b't', escaped.next().unwrap()); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'\r'); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b'r', escaped.next().unwrap()); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'\n'); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b'n', escaped.next().unwrap()); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'\''); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b'\'', escaped.next().unwrap()); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'"'); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b'"', escaped.next().unwrap()); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'\\'); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// | |
-/// let mut escaped = ascii::escape_default(b'\x9d'); | |
-/// | |
-/// assert_eq!(b'\\', escaped.next().unwrap()); | |
-/// assert_eq!(b'x', escaped.next().unwrap()); | |
-/// assert_eq!(b'9', escaped.next().unwrap()); | |
-/// assert_eq!(b'd', escaped.next().unwrap()); | |
-/// ``` | |
-#[stable(feature = "rust1", since = "1.0.0")] | |
-pub fn escape_default(c: u8) -> EscapeDefault { | |
- let (data, len) = match c { | |
- b'\t' => ([b'\\', b't', 0, 0], 2), | |
- b'\r' => ([b'\\', b'r', 0, 0], 2), | |
- b'\n' => ([b'\\', b'n', 0, 0], 2), | |
- b'\\' => ([b'\\', b'\\', 0, 0], 2), | |
- b'\'' => ([b'\\', b'\'', 0, 0], 2), | |
- b'"' => ([b'\\', b'"', 0, 0], 2), | |
- b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), | |
- _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), | |
- }; | |
- | |
- return EscapeDefault { range: (0.. len), data: data }; | |
- | |
- fn hexify(b: u8) -> u8 { | |
- match b { | |
- 0 ... 9 => b'0' + b, | |
- _ => b'a' + b - 10, | |
- } | |
- } | |
-} | |
- | |
-#[stable(feature = "rust1", since = "1.0.0")] | |
-impl Iterator for EscapeDefault { | |
- type Item = u8; | |
- fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) } | |
- fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() } | |
-} | |
-#[stable(feature = "rust1", since = "1.0.0")] | |
-impl DoubleEndedIterator for EscapeDefault { | |
- fn next_back(&mut self) -> Option<u8> { | |
- self.range.next_back().map(|i| self.data[i]) | |
- } | |
-} | |
-#[stable(feature = "rust1", since = "1.0.0")] | |
-impl ExactSizeIterator for EscapeDefault {} | |
-#[unstable(feature = "fused", issue = "35602")] | |
-impl FusedIterator for EscapeDefault {} | |
- | |
-#[stable(feature = "std_debug", since = "1.16.0")] | |
-impl fmt::Debug for EscapeDefault { | |
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
- f.pad("EscapeDefault { .. }") | |
- } | |
-} | |
- | |
- | |
-#[cfg(test)] | |
-mod tests { | |
- //! Note that most of these tests are not testing `AsciiExt` methods, but | |
- //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is | |
- //! just using those methods, though. | |
- use super::AsciiExt; | |
- use char::from_u32; | |
- | |
- #[test] | |
- fn test_is_ascii() { | |
- assert!(b"".is_ascii()); | |
- assert!(b"banana\0\x7F".is_ascii()); | |
- assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); | |
- assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); | |
- assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); | |
- assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); | |
- | |
- assert!("".is_ascii()); | |
- assert!("banana\0\u{7F}".is_ascii()); | |
- assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); | |
- assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); | |
- assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); | |
- } | |
- | |
- #[test] | |
- fn test_to_ascii_uppercase() { | |
- assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); | |
- assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); | |
- | |
- for i in 0..501 { | |
- let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } | |
- else { i }; | |
- assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), | |
- (from_u32(upper).unwrap()).to_string()); | |
- } | |
- } | |
- | |
- #[test] | |
- fn test_to_ascii_lowercase() { | |
- assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); | |
- // Dotted capital I, Kelvin sign, Sharp S. | |
- assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); | |
- | |
- for i in 0..501 { | |
- let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } | |
- else { i }; | |
- assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), | |
- (from_u32(lower).unwrap()).to_string()); | |
- } | |
- } | |
- | |
- #[test] | |
- fn test_make_ascii_lower_case() { | |
- macro_rules! test { | |
- ($from: expr, $to: expr) => { | |
- { | |
- let mut x = $from; | |
- x.make_ascii_lowercase(); | |
- assert_eq!(x, $to); | |
- } | |
- } | |
- } | |
- test!(b'A', b'a'); | |
- test!(b'a', b'a'); | |
- test!(b'!', b'!'); | |
- test!('A', 'a'); | |
- test!('À', 'À'); | |
- test!('a', 'a'); | |
- test!('!', '!'); | |
- test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); | |
- test!("HİKß".to_string(), "hİKß"); | |
- } | |
- | |
- | |
- #[test] | |
- fn test_make_ascii_upper_case() { | |
- macro_rules! test { | |
- ($from: expr, $to: expr) => { | |
- { | |
- let mut x = $from; | |
- x.make_ascii_uppercase(); | |
- assert_eq!(x, $to); | |
- } | |
- } | |
- } | |
- test!(b'a', b'A'); | |
- test!(b'A', b'A'); | |
- test!(b'!', b'!'); | |
- test!('a', 'A'); | |
- test!('à', 'à'); | |
- test!('A', 'A'); | |
- test!('!', '!'); | |
- test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); | |
- test!("hıKß".to_string(), "HıKß"); | |
- | |
- let mut x = "Hello".to_string(); | |
- x[..3].make_ascii_uppercase(); // Test IndexMut on String. | |
- assert_eq!(x, "HELlo") | |
- } | |
- | |
- #[test] | |
- fn test_eq_ignore_ascii_case() { | |
- assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); | |
- assert!(!"Ürl".eq_ignore_ascii_case("ürl")); | |
- // Dotted capital I, Kelvin sign, Sharp S. | |
- assert!("HİKß".eq_ignore_ascii_case("hİKß")); | |
- assert!(!"İ".eq_ignore_ascii_case("i")); | |
- assert!(!"K".eq_ignore_ascii_case("k")); | |
- assert!(!"ß".eq_ignore_ascii_case("s")); | |
- | |
- for i in 0..501 { | |
- let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } | |
- else { i }; | |
- assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( | |
- &from_u32(lower).unwrap().to_string())); | |
- } | |
- } | |
- | |
- #[test] | |
- fn inference_works() { | |
- let x = "a".to_string(); | |
- x.eq_ignore_ascii_case("A"); | |
- } | |
- | |
- // Shorthands used by the is_ascii_* tests. | |
- macro_rules! assert_all { | |
- ($what:ident, $($str:tt),+) => {{ | |
- $( | |
- for b in $str.chars() { | |
- if !b.$what() { | |
- panic!("expected {}({}) but it isn't", | |
- stringify!($what), b); | |
- } | |
- } | |
- for b in $str.as_bytes().iter() { | |
- if !b.$what() { | |
- panic!("expected {}(0x{:02x})) but it isn't", | |
- stringify!($what), b); | |
- } | |
- } | |
- assert!($str.$what()); | |
- assert!($str.as_bytes().$what()); | |
- )+ | |
- }}; | |
- ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) | |
- } | |
- macro_rules! assert_none { | |
- ($what:ident, $($str:tt),+) => {{ | |
- $( | |
- for b in $str.chars() { | |
- if b.$what() { | |
- panic!("expected not-{}({}) but it is", | |
- stringify!($what), b); | |
- } | |
- } | |
- for b in $str.as_bytes().iter() { | |
- if b.$what() { | |
- panic!("expected not-{}(0x{:02x})) but it is", | |
- stringify!($what), b); | |
- } | |
- } | |
- )* | |
- }}; | |
- ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_alphabetic() { | |
- assert_all!(is_ascii_alphabetic, | |
- "", | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- ); | |
- assert_none!(is_ascii_alphabetic, | |
- "0123456789", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_uppercase() { | |
- assert_all!(is_ascii_uppercase, | |
- "", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- ); | |
- assert_none!(is_ascii_uppercase, | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "0123456789", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_lowercase() { | |
- assert_all!(is_ascii_lowercase, | |
- "abcdefghijklmnopqrstuvwxyz", | |
- ); | |
- assert_none!(is_ascii_lowercase, | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "0123456789", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_alphanumeric() { | |
- assert_all!(is_ascii_alphanumeric, | |
- "", | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "0123456789", | |
- ); | |
- assert_none!(is_ascii_alphanumeric, | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_digit() { | |
- assert_all!(is_ascii_digit, | |
- "", | |
- "0123456789", | |
- ); | |
- assert_none!(is_ascii_digit, | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_hexdigit() { | |
- assert_all!(is_ascii_hexdigit, | |
- "", | |
- "0123456789", | |
- "abcdefABCDEF", | |
- ); | |
- assert_none!(is_ascii_hexdigit, | |
- "ghijklmnopqrstuvwxyz", | |
- "GHIJKLMNOQPRSTUVWXYZ", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_punctuation() { | |
- assert_all!(is_ascii_punctuation, | |
- "", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- ); | |
- assert_none!(is_ascii_punctuation, | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "0123456789", | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_graphic() { | |
- assert_all!(is_ascii_graphic, | |
- "", | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "0123456789", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- ); | |
- assert_none!(is_ascii_graphic, | |
- " \t\n\x0c\r", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_whitespace() { | |
- assert_all!(is_ascii_whitespace, | |
- "", | |
- " \t\n\x0c\r", | |
- ); | |
- assert_none!(is_ascii_whitespace, | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "0123456789", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x0b\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- } | |
- | |
- #[test] | |
- fn test_is_ascii_control() { | |
- assert_all!(is_ascii_control, | |
- "", | |
- "\x00\x01\x02\x03\x04\x05\x06\x07", | |
- "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", | |
- "\x10\x11\x12\x13\x14\x15\x16\x17", | |
- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", | |
- "\x7f", | |
- ); | |
- assert_none!(is_ascii_control, | |
- "abcdefghijklmnopqrstuvwxyz", | |
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ", | |
- "0123456789", | |
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", | |
- " ", | |
- ); | |
- } | |
-} | |
diff -ruN orig/std/src/collections/hash/map.rs new/std/src/collections/hash/map.rs | |
--- orig/std/src/collections/hash/map.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/collections/hash/map.rs 2018-08-02 10:58:05.000000000 +0800 | |
@@ -11,7 +11,8 @@ | |
use self::Entry::*; | |
use self::VacantEntryState::*; | |
-//- use cell::Cell; | |
+use alloc::CollectionAllocErr; | |
+// use cell::Cell; | |
use borrow::Borrow; | |
use cmp::max; | |
use fmt::{self, Debug}; | |
@@ -19,12 +20,13 @@ | |
use hash::{Hash, Hasher, BuildHasher, SipHasher13}; | |
use iter::{FromIterator, FusedIterator}; | |
use mem::{self, replace}; | |
-use ops::{Deref, Index, InPlace, Place, Placer}; | |
-use ptr; | |
-//- use sys; | |
+use ops::{Deref, Index}; | |
+// use sys; | |
-use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; | |
+use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable, | |
+ SafeHash}; | |
use super::table::BucketState::{Empty, Full}; | |
+use super::table::Fallibility::{Fallible, Infallible}; | |
const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two | |
@@ -33,6 +35,7 @@ | |
struct DefaultResizePolicy; | |
impl DefaultResizePolicy { | |
+ #[inline] | |
fn new() -> DefaultResizePolicy { | |
DefaultResizePolicy | |
} | |
@@ -42,21 +45,28 @@ | |
/// provide that capacity, accounting for maximum loading. The raw capacity | |
/// is always zero or a power of two. | |
#[inline] | |
- fn raw_capacity(&self, len: usize) -> usize { | |
+ fn try_raw_capacity(&self, len: usize) -> Result<usize, CollectionAllocErr> { | |
if len == 0 { | |
- 0 | |
+ Ok(0) | |
} else { | |
// 1. Account for loading: `raw_capacity >= len * 1.1`. | |
// 2. Ensure it is a power of two. | |
// 3. Ensure it is at least the minimum size. | |
- let mut raw_cap = len * 11 / 10; | |
- assert!(raw_cap >= len, "raw_cap overflow"); | |
- raw_cap = raw_cap.checked_next_power_of_two().expect("raw_capacity overflow"); | |
+ let mut raw_cap = len.checked_mul(11) | |
+ .map(|l| l / 10) | |
+ .and_then(|l| l.checked_next_power_of_two()) | |
+ .ok_or(CollectionAllocErr::CapacityOverflow)?; | |
+ | |
raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); | |
- raw_cap | |
+ Ok(raw_cap) | |
} | |
} | |
+ #[inline] | |
+ fn raw_capacity(&self, len: usize) -> usize { | |
+ self.try_raw_capacity(len).expect("raw_capacity overflow") | |
+ } | |
+ | |
/// The capacity of the given raw capacity. | |
#[inline] | |
fn capacity(&self, raw_cap: usize) -> usize { | |
@@ -266,17 +276,31 @@ | |
/// ``` | |
/// use std::collections::HashMap; | |
/// | |
-/// // type inference lets us omit an explicit type signature (which | |
-/// // would be `HashMap<&str, &str>` in this example). | |
+/// // Type inference lets us omit an explicit type signature (which | |
+/// // would be `HashMap<String, String>` in this example). | |
/// let mut book_reviews = HashMap::new(); | |
/// | |
-/// // review some books. | |
-/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); | |
-/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); | |
-/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); | |
-/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); | |
-/// | |
-/// // check for a specific one. | |
+/// // Review some books. | |
+/// book_reviews.insert( | |
+/// "Adventures of Huckleberry Finn".to_string(), | |
+/// "My favorite book.".to_string(), | |
+/// ); | |
+/// book_reviews.insert( | |
+/// "Grimms' Fairy Tales".to_string(), | |
+/// "Masterpiece.".to_string(), | |
+/// ); | |
+/// book_reviews.insert( | |
+/// "Pride and Prejudice".to_string(), | |
+/// "Very enjoyable.".to_string(), | |
+/// ); | |
+/// book_reviews.insert( | |
+/// "The Adventures of Sherlock Holmes".to_string(), | |
+/// "Eye lyked it alot.".to_string(), | |
+/// ); | |
+/// | |
+/// // Check for a specific one. | |
+/// // When collections store owned values (String), they can still be | |
+/// // queried using references (&str). | |
/// if !book_reviews.contains_key("Les Misérables") { | |
/// println!("We've got {} reviews, but Les Misérables ain't one.", | |
/// book_reviews.len()); | |
@@ -285,16 +309,16 @@ | |
/// // oops, this review has a lot of spelling mistakes, let's delete it. | |
/// book_reviews.remove("The Adventures of Sherlock Holmes"); | |
/// | |
-/// // look up the values associated with some keys. | |
+/// // Look up the values associated with some keys. | |
/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; | |
-/// for book in &to_find { | |
+/// for &book in &to_find { | |
/// match book_reviews.get(book) { | |
/// Some(review) => println!("{}: {}", book, review), | |
/// None => println!("{} is unreviewed.", book) | |
/// } | |
/// } | |
/// | |
-/// // iterate over everything. | |
+/// // Iterate over everything. | |
/// for (book, review) in &book_reviews { | |
/// println!("{}: \"{}\"", book, review); | |
/// } | |
@@ -398,8 +422,9 @@ | |
} | |
/// Search for a pre-hashed key. | |
+/// If you don't already know the hash, use search or search_mut instead | |
#[inline] | |
-fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry<K, V, M> | |
+fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, is_match: F) -> InternalEntry<K, V, M> | |
where M: Deref<Target = RawTable<K, V>>, | |
F: FnMut(&K) -> bool | |
{ | |
@@ -410,6 +435,18 @@ | |
return InternalEntry::TableIsEmpty; | |
} | |
+ search_hashed_nonempty(table, hash, is_match) | |
+} | |
+ | |
+/// Search for a pre-hashed key when the hash map is known to be non-empty. | |
+#[inline] | |
+fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) | |
+ -> InternalEntry<K, V, M> | |
+ where M: Deref<Target = RawTable<K, V>>, | |
+ F: FnMut(&K) -> bool | |
+{ | |
+ // Do not check the capacity as an extra branch could slow the lookup. | |
+ | |
let size = table.size(); | |
let mut probe = Bucket::new(table, hash); | |
let mut displacement = 0; | |
@@ -543,24 +580,36 @@ | |
} | |
/// Search for a key, yielding the index if it's found in the hashtable. | |
- /// If you already have the hash for the key lying around, use | |
- /// search_hashed. | |
+ /// If you already have the hash for the key lying around, or if you need an | |
+ /// InternalEntry, use search_hashed or search_hashed_nonempty. | |
#[inline] | |
- fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry<K, V, &'a RawTable<K, V>> | |
+ fn search<'a, Q: ?Sized>(&'a self, q: &Q) | |
+ -> Option<FullBucket<K, V, &'a RawTable<K, V>>> | |
where K: Borrow<Q>, | |
Q: Eq + Hash | |
{ | |
+ if self.is_empty() { | |
+ return None; | |
+ } | |
+ | |
let hash = self.make_hash(q); | |
- search_hashed(&self.table, hash, |k| q.eq(k.borrow())) | |
+ search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) | |
+ .into_occupied_bucket() | |
} | |
#[inline] | |
- fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry<K, V, &'a mut RawTable<K, V>> | |
+ fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) | |
+ -> Option<FullBucket<K, V, &'a mut RawTable<K, V>>> | |
where K: Borrow<Q>, | |
Q: Eq + Hash | |
{ | |
+ if self.is_empty() { | |
+ return None; | |
+ } | |
+ | |
let hash = self.make_hash(q); | |
- search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) | |
+ search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) | |
+ .into_occupied_bucket() | |
} | |
// The caller should ensure that invariants by Robin Hood Hashing hold | |
@@ -595,7 +644,7 @@ | |
/// | |
/// ``` | |
/// use std::collections::HashMap; | |
- /// let mut map: HashMap<&str, isize> = HashMap::new(); | |
+ /// let mut map: HashMap<&str, i32> = HashMap::new(); | |
/// ``` | |
#[inline] | |
#[stable(feature = "rust1", since = "1.0.0")] | |
@@ -612,7 +661,7 @@ | |
/// | |
/// ``` | |
/// use std::collections::HashMap; | |
- /// let mut map: HashMap<&str, isize> = HashMap::with_capacity(10); | |
+ /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); | |
/// ``` | |
#[inline] | |
#[stable(feature = "rust1", since = "1.0.0")] | |
@@ -699,7 +748,7 @@ | |
/// use std::collections::hash_map::RandomState; | |
/// | |
/// let hasher = RandomState::new(); | |
- /// let map: HashMap<isize, isize> = HashMap::with_hasher(hasher); | |
+ /// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher); | |
/// let hasher: &RandomState = map.hasher(); | |
/// ``` | |
#[stable(feature = "hashmap_public_hasher", since = "1.9.0")] | |
@@ -716,7 +765,7 @@ | |
/// | |
/// ``` | |
/// use std::collections::HashMap; | |
- /// let map: HashMap<isize, isize> = HashMap::with_capacity(100); | |
+ /// let map: HashMap<i32, i32> = HashMap::with_capacity(100); | |
/// assert!(map.capacity() >= 100); | |
/// ``` | |
#[inline] | |
@@ -745,22 +794,57 @@ | |
/// | |
/// ``` | |
/// use std::collections::HashMap; | |
- /// let mut map: HashMap<&str, isize> = HashMap::new(); | |
+ /// let mut map: HashMap<&str, i32> = HashMap::new(); | |
/// map.reserve(10); | |
/// ``` | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub fn reserve(&mut self, additional: usize) { | |
+ match self.reserve_internal(additional, Infallible) { | |
+ Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), | |
+ Err(CollectionAllocErr::AllocErr) => unreachable!(), | |
+ Ok(()) => { /* yay */ } | |
+ } | |
+ } | |
+ | |
+ /// Tries to reserve capacity for at least `additional` more elements to be inserted | |
+ /// in the given `HashMap<K,V>`. The collection may reserve more space to avoid | |
+ /// frequent reallocations. | |
+ /// | |
+ /// # Errors | |
+ /// | |
+ /// If the capacity overflows, or the allocator reports a failure, then an error | |
+ /// is returned. | |
+ /// | |
+ /// # Examples | |
+ /// | |
+ /// ``` | |
+ /// #![feature(try_reserve)] | |
+ /// use std::collections::HashMap; | |
+ /// let mut map: HashMap<&str, isize> = HashMap::new(); | |
+ /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); | |
+ /// ``` | |
+ #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] | |
+ pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { | |
+ self.reserve_internal(additional, Fallible) | |
+ } | |
+ | |
+ fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility) | |
+ -> Result<(), CollectionAllocErr> { | |
+ | |
let remaining = self.capacity() - self.len(); // this can't overflow | |
if remaining < additional { | |
- let min_cap = self.len().checked_add(additional).expect("reserve overflow"); | |
- let raw_cap = self.resize_policy.raw_capacity(min_cap); | |
- self.resize(raw_cap); | |
+ let min_cap = self.len() | |
+ .checked_add(additional) | |
+ .ok_or(CollectionAllocErr::CapacityOverflow)?; | |
+ let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; | |
+ self.try_resize(raw_cap, fallibility)?; | |
} else if self.table.tag() && remaining <= self.len() { | |
// Probe sequence is too long and table is half full, | |
// resize early to reduce probing length. | |
let new_capacity = self.table.capacity() * 2; | |
- self.resize(new_capacity); | |
+ self.try_resize(new_capacity, fallibility)?; | |
} | |
+ Ok(()) | |
} | |
/// Resizes the internal vectors to a new capacity. It's your | |
@@ -770,15 +854,25 @@ | |
/// 2) Ensure `new_raw_cap` is a power of two or zero. | |
#[inline(never)] | |
#[cold] | |
- fn resize(&mut self, new_raw_cap: usize) { | |
+ fn try_resize( | |
+ &mut self, | |
+ new_raw_cap: usize, | |
+ fallibility: Fallibility, | |
+ ) -> Result<(), CollectionAllocErr> { | |
assert!(self.table.size() <= new_raw_cap); | |
assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); | |
- let mut old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); | |
+ let mut old_table = replace( | |
+ &mut self.table, | |
+ match fallibility { | |
+ Infallible => RawTable::new(new_raw_cap), | |
+ Fallible => RawTable::try_new(new_raw_cap)?, | |
+ } | |
+ ); | |
let old_size = old_table.size(); | |
if old_table.size() == 0 { | |
- return; | |
+ return Ok(()); | |
} | |
let mut bucket = Bucket::head_bucket(&mut old_table); | |
@@ -813,6 +907,7 @@ | |
} | |
assert_eq!(self.table.size(), old_size); | |
+ Ok(()) | |
} | |
/// Shrinks the capacity of the map as much as possible. It will drop | |
@@ -824,7 +919,7 @@ | |
/// ``` | |
/// use std::collections::HashMap; | |
/// | |
- /// let mut map: HashMap<isize, isize> = HashMap::with_capacity(100); | |
+ /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100); | |
/// map.insert(1, 2); | |
/// map.insert(3, 4); | |
/// assert!(map.capacity() >= 100); | |
@@ -847,6 +942,46 @@ | |
} | |
} | |
+ /// Shrinks the capacity of the map with a lower limit. It will drop | |
+ /// down no lower than the supplied limit while maintaining the internal rules | |
+ /// and possibly leaving some space in accordance with the resize policy. | |
+ /// | |
+ /// Panics if the current capacity is smaller than the supplied | |
+ /// minimum capacity. | |
+ /// | |
+ /// # Examples | |
+ /// | |
+ /// ``` | |
+ /// #![feature(shrink_to)] | |
+ /// use std::collections::HashMap; | |
+ /// | |
+ /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100); | |
+ /// map.insert(1, 2); | |
+ /// map.insert(3, 4); | |
+ /// assert!(map.capacity() >= 100); | |
+ /// map.shrink_to(10); | |
+ /// assert!(map.capacity() >= 10); | |
+ /// map.shrink_to(0); | |
+ /// assert!(map.capacity() >= 2); | |
+ /// ``` | |
+ #[unstable(feature = "shrink_to", reason = "new API", issue="0")] | |
+ pub fn shrink_to(&mut self, min_capacity: usize) { | |
+ assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); | |
+ | |
+ let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity)); | |
+ if self.raw_capacity() != new_raw_cap { | |
+ let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); | |
+ let old_size = old_table.size(); | |
+ | |
+ // Shrink the table. Naive algorithm for resizing: | |
+ for (h, k, v) in old_table.into_iter() { | |
+ self.insert_hashed_nocheck(h, k, v); | |
+ } | |
+ | |
+ debug_assert_eq!(self.table.size(), old_size); | |
+ } | |
+ } | |
+ | |
/// Insert a pre-hashed key-value pair, without first checking | |
/// that there's enough room in the buckets. Returns a reference to the | |
/// newly insert value. | |
@@ -1118,7 +1253,35 @@ | |
where K: Borrow<Q>, | |
Q: Hash + Eq | |
{ | |
- self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) | |
+ self.search(k).map(|bucket| bucket.into_refs().1) | |
+ } | |
+ | |
+ /// Returns the key-value pair corresponding to the supplied key. | |
+ /// | |
+ /// The supplied key may be any borrowed form of the map's key type, but | |
+ /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for | |
+ /// the key type. | |
+ /// | |
+ /// [`Eq`]: ../../std/cmp/trait.Eq.html | |
+ /// [`Hash`]: ../../std/hash/trait.Hash.html | |
+ /// | |
+ /// # Examples | |
+ /// | |
+ /// ``` | |
+ /// #![feature(map_get_key_value)] | |
+ /// use std::collections::HashMap; | |
+ /// | |
+ /// let mut map = HashMap::new(); | |
+ /// map.insert(1, "a"); | |
+ /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); | |
+ /// assert_eq!(map.get_key_value(&2), None); | |
+ /// ``` | |
+ #[unstable(feature = "map_get_key_value", issue = "49347")] | |
+ pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)> | |
+ where K: Borrow<Q>, | |
+ Q: Hash + Eq | |
+ { | |
+ self.search(k).map(|bucket| bucket.into_refs()) | |
} | |
/// Returns true if the map contains a value for the specified key. | |
@@ -1145,7 +1308,7 @@ | |
where K: Borrow<Q>, | |
Q: Hash + Eq | |
{ | |
- self.search(k).into_occupied_bucket().is_some() | |
+ self.search(k).is_some() | |
} | |
/// Returns a mutable reference to the value corresponding to the key. | |
@@ -1174,7 +1337,7 @@ | |
where K: Borrow<Q>, | |
Q: Hash + Eq | |
{ | |
- self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) | |
+ self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) | |
} | |
/// Inserts a key-value pair into the map. | |
@@ -1234,11 +1397,7 @@ | |
where K: Borrow<Q>, | |
Q: Hash + Eq | |
{ | |
- if self.table.size() == 0 { | |
- return None; | |
- } | |
- | |
- self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) | |
+ self.search_mut(k).map(|bucket| pop_internal(bucket).1) | |
} | |
/// Removes a key from the map, returning the stored key and value if the | |
@@ -1254,7 +1413,6 @@ | |
/// # Examples | |
/// | |
/// ``` | |
- /// #![feature(hash_map_remove_entry)] | |
/// use std::collections::HashMap; | |
/// | |
/// # fn main() { | |
@@ -1264,17 +1422,12 @@ | |
/// assert_eq!(map.remove(&1), None); | |
/// # } | |
/// ``` | |
- #[unstable(feature = "hash_map_remove_entry", issue = "46344")] | |
+ #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] | |
pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)> | |
where K: Borrow<Q>, | |
Q: Hash + Eq | |
{ | |
- if self.table.size() == 0 { | |
- return None; | |
- } | |
- | |
self.search_mut(k) | |
- .into_occupied_bucket() | |
.map(|bucket| { | |
let (k, v, _) = pop_internal(bucket); | |
(k, v) | |
@@ -1290,7 +1443,7 @@ | |
/// ``` | |
/// use std::collections::HashMap; | |
/// | |
- /// let mut map: HashMap<isize, isize> = (0..8).map(|x|(x, x*10)).collect(); | |
+ /// let mut map: HashMap<i32, i32> = (0..8).map(|x|(x, x*10)).collect(); | |
/// map.retain(|&k, _| k % 2 == 0); | |
/// assert_eq!(map.len(), 4); | |
/// ``` | |
@@ -1384,9 +1537,14 @@ | |
{ | |
type Output = V; | |
+ /// Returns a reference to the value corresponding to the supplied key. | |
+ /// | |
+ /// # Panics | |
+ /// | |
+ /// Panics if the key is not present in the `HashMap`. | |
#[inline] | |
- fn index(&self, index: &Q) -> &V { | |
- self.get(index).expect("no entry found for key") | |
+ fn index(&self, key: &Q) -> &V { | |
+ self.get(key).expect("no entry found for key") | |
} | |
} | |
@@ -1701,7 +1859,7 @@ | |
/// map.insert("c", 3); | |
/// | |
/// // Not possible with .iter() | |
- /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); | |
+ /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); | |
/// ``` | |
fn into_iter(self) -> IntoIter<K, V> { | |
IntoIter { inner: self.table.into_iter() } | |
@@ -1729,7 +1887,7 @@ | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
@@ -1752,7 +1910,7 @@ | |
self.inner.len() | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} | |
#[stable(feature = "std_debug", since = "1.16.0")] | |
@@ -1787,7 +1945,7 @@ | |
self.inner.len() | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<K, V> FusedIterator for IntoIter<K, V> {} | |
#[stable(feature = "std_debug", since = "1.16.0")] | |
@@ -1819,7 +1977,7 @@ | |
self.inner.len() | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
@@ -1842,7 +2000,7 @@ | |
self.inner.len() | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<'a, K, V> FusedIterator for Values<'a, K, V> {} | |
#[stable(feature = "map_values_mut", since = "1.10.0")] | |
@@ -1865,7 +2023,7 @@ | |
self.inner.len() | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} | |
#[stable(feature = "std_debug", since = "1.16.0")] | |
@@ -1900,7 +2058,7 @@ | |
self.inner.len() | |
} | |
} | |
-#[unstable(feature = "fused", issue = "35602")] | |
+#[stable(feature = "fused", since = "1.26.0")] | |
impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} | |
#[stable(feature = "std_debug", since = "1.16.0")] | |
@@ -1915,80 +2073,6 @@ | |
} | |
} | |
-/// A place for insertion to a `Entry`. | |
-/// | |
-/// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details. | |
-#[must_use = "places do nothing unless written to with `<-` syntax"] | |
-#[unstable(feature = "collection_placement", | |
- reason = "struct name and placement protocol is subject to change", | |
- issue = "30172")] | |
-pub struct EntryPlace<'a, K: 'a, V: 'a> { | |
- bucket: FullBucketMut<'a, K, V>, | |
-} | |
- | |
-#[unstable(feature = "collection_placement", | |
- reason = "struct name and placement protocol is subject to change", | |
- issue = "30172")] | |
-impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for EntryPlace<'a, K, V> { | |
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
- f.debug_struct("EntryPlace") | |
- .field("key", self.bucket.read().0) | |
- .field("value", self.bucket.read().1) | |
- .finish() | |
- } | |
-} | |
- | |
-#[unstable(feature = "collection_placement", | |
- reason = "struct name and placement protocol is subject to change", | |
- issue = "30172")] | |
-impl<'a, K, V> Drop for EntryPlace<'a, K, V> { | |
- fn drop(&mut self) { | |
- // Inplacement insertion failed. Only key need to drop. | |
- // The value is failed to insert into map. | |
- unsafe { self.bucket.remove_key() }; | |
- } | |
-} | |
- | |
-#[unstable(feature = "collection_placement", | |
- reason = "placement protocol is subject to change", | |
- issue = "30172")] | |
-impl<'a, K, V> Placer<V> for Entry<'a, K, V> { | |
- type Place = EntryPlace<'a, K, V>; | |
- | |
- fn make_place(self) -> EntryPlace<'a, K, V> { | |
- let b = match self { | |
- Occupied(mut o) => { | |
- unsafe { ptr::drop_in_place(o.elem.read_mut().1); } | |
- o.elem | |
- } | |
- Vacant(v) => { | |
- unsafe { v.insert_key() } | |
- } | |
- }; | |
- EntryPlace { bucket: b } | |
- } | |
-} | |
- | |
-#[unstable(feature = "collection_placement", | |
- reason = "placement protocol is subject to change", | |
- issue = "30172")] | |
-impl<'a, K, V> Place<V> for EntryPlace<'a, K, V> { | |
- fn pointer(&mut self) -> *mut V { | |
- self.bucket.read_mut().1 | |
- } | |
-} | |
- | |
-#[unstable(feature = "collection_placement", | |
- reason = "placement protocol is subject to change", | |
- issue = "30172")] | |
-impl<'a, K, V> InPlace<V> for EntryPlace<'a, K, V> { | |
- type Owner = (); | |
- | |
- unsafe fn finalize(self) { | |
- mem::forget(self); | |
- } | |
-} | |
- | |
impl<'a, K, V> Entry<'a, K, V> { | |
#[stable(feature = "rust1", since = "1.0.0")] | |
/// Ensures a value is in the entry by inserting the default if empty, and returns | |
@@ -2061,7 +2145,6 @@ | |
/// # Examples | |
/// | |
/// ``` | |
- /// #![feature(entry_and_modify)] | |
/// use std::collections::HashMap; | |
/// | |
/// let mut map: HashMap<&str, u32> = HashMap::new(); | |
@@ -2076,9 +2159,9 @@ | |
/// .or_insert(42); | |
/// assert_eq!(map["poneyland"], 43); | |
/// ``` | |
- #[unstable(feature = "entry_and_modify", issue = "44733")] | |
- pub fn and_modify<F>(self, mut f: F) -> Self | |
- where F: FnMut(&mut V) | |
+ #[stable(feature = "entry_and_modify", since = "1.26.0")] | |
+ pub fn and_modify<F>(self, f: F) -> Self | |
+ where F: FnOnce(&mut V) | |
{ | |
match self { | |
Occupied(mut entry) => { | |
@@ -2092,14 +2175,13 @@ | |
} | |
impl<'a, K, V: Default> Entry<'a, K, V> { | |
- #[unstable(feature = "entry_or_default", issue = "44324")] | |
+ #[stable(feature = "entry_or_default", since = "1.28.0")] | |
/// Ensures a value is in the entry by inserting the default value if empty, | |
/// and returns a mutable reference to the value in the entry. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
- /// #![feature(entry_or_default)] | |
/// # fn main() { | |
/// use std::collections::HashMap; | |
/// | |
@@ -2115,7 +2197,6 @@ | |
Vacant(entry) => entry.insert(Default::default()), | |
} | |
} | |
- | |
} | |
impl<'a, K, V> OccupiedEntry<'a, K, V> { | |
@@ -2181,6 +2262,11 @@ | |
/// Gets a mutable reference to the value in the entry. | |
/// | |
+ /// If you need a reference to the `OccupiedEntry` which may outlive the | |
+ /// destruction of the `Entry` value, see [`into_mut`]. | |
+ /// | |
+ /// [`into_mut`]: #method.into_mut | |
+ /// | |
/// # Examples | |
/// | |
/// ``` | |
@@ -2192,10 +2278,14 @@ | |
/// | |
/// assert_eq!(map["poneyland"], 12); | |
/// if let Entry::Occupied(mut o) = map.entry("poneyland") { | |
- /// *o.get_mut() += 10; | |
+ /// *o.get_mut() += 10; | |
+ /// assert_eq!(*o.get(), 22); | |
+ /// | |
+ /// // We can use the same Entry multiple times. | |
+ /// *o.get_mut() += 2; | |
/// } | |
/// | |
- /// assert_eq!(map["poneyland"], 22); | |
+ /// assert_eq!(map["poneyland"], 24); | |
/// ``` | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub fn get_mut(&mut self) -> &mut V { | |
@@ -2205,6 +2295,10 @@ | |
/// Converts the OccupiedEntry into a mutable reference to the value in the entry | |
/// with a lifetime bound to the map itself. | |
/// | |
+ /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. | |
+ /// | |
+ /// [`get_mut`]: #method.get_mut | |
+ /// | |
/// # Examples | |
/// | |
/// ``` | |
@@ -2412,26 +2506,6 @@ | |
}; | |
b.into_mut_refs().1 | |
} | |
- | |
- // Only used for InPlacement insert. Avoid unnecessary value copy. | |
- // The value remains uninitialized. | |
- unsafe fn insert_key(self) -> FullBucketMut<'a, K, V> { | |
- match self.elem { | |
- NeqElem(mut bucket, disp) => { | |
- if disp >= DISPLACEMENT_THRESHOLD { | |
- bucket.table_mut().set_tag(true); | |
- } | |
- let uninit = mem::uninitialized(); | |
- robin_hood(bucket, disp, self.hash, self.key, uninit) | |
- }, | |
- NoElem(mut bucket, disp) => { | |
- if disp >= DISPLACEMENT_THRESHOLD { | |
- bucket.table_mut().set_tag(true); | |
- } | |
- bucket.put_key(self.hash, self.key) | |
- }, | |
- } | |
- } | |
} | |
#[stable(feature = "rust1", since = "1.0.0")] | |
@@ -2628,15 +2702,11 @@ | |
#[inline] | |
fn get(&self, key: &Q) -> Option<&K> { | |
- self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) | |
+ self.search(key).map(|bucket| bucket.into_refs().0) | |
} | |
fn take(&mut self, key: &Q) -> Option<K> { | |
- if self.table.size() == 0 { | |
- return None; | |
- } | |
- | |
- self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) | |
+ self.search_mut(key).map(|bucket| pop_internal(bucket).0) | |
} | |
#[inline] | |
@@ -2701,7 +2771,9 @@ | |
use super::RandomState; | |
use cell::RefCell; | |
use rand::{thread_rng, Rng}; | |
- use panic; | |
+ use realstd::collections::CollectionAllocErr::*; | |
+ use realstd::mem::size_of; | |
+ use realstd::usize; | |
#[test] | |
fn test_zero_capacities() { | |
@@ -2771,24 +2843,24 @@ | |
assert_eq!(m2.len(), 2); | |
} | |
- thread_local! { static DROP_VECTOR: RefCell<Vec<isize>> = RefCell::new(Vec::new()) } | |
+ thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) } | |
#[derive(Hash, PartialEq, Eq)] | |
- struct Dropable { | |
+ struct Droppable { | |
k: usize, | |
} | |
- impl Dropable { | |
- fn new(k: usize) -> Dropable { | |
+ impl Droppable { | |
+ fn new(k: usize) -> Droppable { | |
DROP_VECTOR.with(|slot| { | |
slot.borrow_mut()[k] += 1; | |
}); | |
- Dropable { k: k } | |
+ Droppable { k: k } | |
} | |
} | |
- impl Drop for Dropable { | |
+ impl Drop for Droppable { | |
fn drop(&mut self) { | |
DROP_VECTOR.with(|slot| { | |
slot.borrow_mut()[self.k] -= 1; | |
@@ -2796,9 +2868,9 @@ | |
} | |
} | |
- impl Clone for Dropable { | |
- fn clone(&self) -> Dropable { | |
- Dropable::new(self.k) | |
+ impl Clone for Droppable { | |
+ fn clone(&self) -> Droppable { | |
+ Droppable::new(self.k) | |
} | |
} | |
@@ -2818,8 +2890,8 @@ | |
}); | |
for i in 0..100 { | |
- let d1 = Dropable::new(i); | |
- let d2 = Dropable::new(i + 100); | |
+ let d1 = Droppable::new(i); | |
+ let d2 = Droppable::new(i + 100); | |
m.insert(d1, d2); | |
} | |
@@ -2830,7 +2902,7 @@ | |
}); | |
for i in 0..50 { | |
- let k = Dropable::new(i); | |
+ let k = Droppable::new(i); | |
let v = m.remove(&k); | |
assert!(v.is_some()); | |
@@ -2877,8 +2949,8 @@ | |
}); | |
for i in 0..100 { | |
- let d1 = Dropable::new(i); | |
- let d2 = Dropable::new(i + 100); | |
+ let d1 = Droppable::new(i); | |
+ let d2 = Droppable::new(i + 100); | |
hm.insert(d1, d2); | |
} | |
@@ -2928,13 +3000,13 @@ | |
#[test] | |
fn test_empty_remove() { | |
- let mut m: HashMap<isize, bool> = HashMap::new(); | |
+ let mut m: HashMap<i32, bool> = HashMap::new(); | |
assert_eq!(m.remove(&0), None); | |
} | |
#[test] | |
fn test_empty_entry() { | |
- let mut m: HashMap<isize, bool> = HashMap::new(); | |
+ let mut m: HashMap<i32, bool> = HashMap::new(); | |
match m.entry(0) { | |
Occupied(_) => panic!(), | |
Vacant(_) => {} | |
@@ -2945,7 +3017,7 @@ | |
#[test] | |
fn test_empty_iter() { | |
- let mut m: HashMap<isize, bool> = HashMap::new(); | |
+ let mut m: HashMap<i32, bool> = HashMap::new(); | |
assert_eq!(m.drain().next(), None); | |
assert_eq!(m.keys().next(), None); | |
assert_eq!(m.values().next(), None); | |
@@ -3446,7 +3518,7 @@ | |
fn test_entry_take_doesnt_corrupt() { | |
#![allow(deprecated)] //rand | |
// Test for #19292 | |
- fn check(m: &HashMap<isize, ()>) { | |
+ fn check(m: &HashMap<i32, ()>) { | |
for k in m.keys() { | |
assert!(m.contains_key(k), | |
"{} is in keys() but not in the map?", k); | |
@@ -3555,7 +3627,7 @@ | |
#[test] | |
fn test_retain() { | |
- let mut map: HashMap<isize, isize> = (0..100).map(|x|(x, x*10)).collect(); | |
+ let mut map: HashMap<i32, i32> = (0..100).map(|x|(x, x*10)).collect(); | |
map.retain(|&k, _| k % 2 == 0); | |
assert_eq!(map.len(), 50); | |
@@ -3585,55 +3657,31 @@ | |
} | |
#[test] | |
- fn test_placement_in() { | |
- let mut map = HashMap::new(); | |
- map.extend((0..10).map(|i| (i, i))); | |
- | |
- map.entry(100) <- 100; | |
- assert_eq!(map[&100], 100); | |
- | |
- map.entry(0) <- 10; | |
- assert_eq!(map[&0], 10); | |
- | |
- assert_eq!(map.len(), 11); | |
- } | |
- | |
- #[test] | |
- fn test_placement_panic() { | |
- let mut map = HashMap::new(); | |
- map.extend((0..10).map(|i| (i, i))); | |
+ fn test_try_reserve() { | |
- fn mkpanic() -> usize { panic!() } | |
+ let mut empty_bytes: HashMap<u8,u8> = HashMap::new(); | |
- // modify existing key | |
- // when panic happens, previous key is removed. | |
- let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); })); | |
- assert_eq!(map.len(), 9); | |
- assert!(!map.contains_key(&0)); | |
+ const MAX_USIZE: usize = usize::MAX; | |
- // add new key | |
- let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(100) <- mkpanic(); })); | |
- assert_eq!(map.len(), 9); | |
- assert!(!map.contains_key(&100)); | |
- } | |
- | |
- #[test] | |
- fn test_placement_drop() { | |
- // correctly drop | |
- struct TestV<'a>(&'a mut bool); | |
- impl<'a> Drop for TestV<'a> { | |
- fn drop(&mut self) { | |
- if !*self.0 { panic!("value double drop!"); } // no double drop | |
- *self.0 = false; | |
- } | |
+ // HashMap and RawTables use complicated size calculations | |
+ // hashes_size is sizeof(HashUint) * capacity; | |
+ // pairs_size is sizeof((K. V)) * capacity; | |
+ // alignment_hashes_size is 8 | |
+ // alignment_pairs size is 4 | |
+ let size_of_multiplier = (size_of::<usize>() + size_of::<(u8, u8)>()).next_power_of_two(); | |
+ // The following formula is used to calculate the new capacity | |
+ let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1; | |
+ | |
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { | |
+ } else { panic!("usize::MAX should trigger an overflow!"); } | |
+ | |
+ if size_of::<usize>() < 8 { | |
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { | |
+ } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } | |
+ } else { | |
+ if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { | |
+ } else { panic!("isize::MAX + 1 should trigger an OOM!") } | |
} | |
- | |
- fn makepanic<'a>() -> TestV<'a> { panic!() } | |
- | |
- let mut can_drop = true; | |
- let mut hm = HashMap::new(); | |
- hm.insert(0, TestV(&mut can_drop)); | |
- let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); })); | |
- assert_eq!(hm.len(), 0); | |
} | |
+ | |
} | |
diff -ruN orig/std/src/collections/hash/table.rs new/std/src/collections/hash/table.rs | |
--- orig/std/src/collections/hash/table.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/collections/hash/table.rs 2018-08-02 10:40:06.000000000 +0800 | |
@@ -8,15 +8,14 @@ | |
// option. This file may not be copied, modified, or distributed | |
// except according to those terms. | |
-use alloc::heap::{Heap, Alloc, Layout}; | |
- | |
-use cmp; | |
+use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, handle_alloc_error}; | |
use hash::{BuildHasher, Hash, Hasher}; | |
use marker; | |
-use mem::{align_of, size_of, needs_drop}; | |
+use mem::{size_of, needs_drop}; | |
use mem; | |
use ops::{Deref, DerefMut}; | |
-use ptr::{self, Unique, Shared}; | |
+use ptr::{self, Unique, NonNull}; | |
+use hint; | |
use self::BucketState::*; | |
@@ -80,7 +79,7 @@ | |
/// | |
/// Essential invariants of this structure: | |
/// | |
-/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` | |
+/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` | |
/// points to 'undefined' contents. Don't read from it. This invariant is | |
/// enforced outside this module with the `EmptyBucket`, `FullBucket`, | |
/// and `SafeHash` types. | |
@@ -484,21 +483,6 @@ | |
table: self.table, | |
} | |
} | |
- | |
- /// Puts given key, remain value uninitialized. | |
- /// It is only used for inplacement insertion. | |
- pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> { | |
- *self.raw.hash() = hash.inspect(); | |
- let pair_ptr = self.raw.pair(); | |
- ptr::write(&mut (*pair_ptr).0, key); | |
- | |
- self.table.borrow_table_mut().size += 1; | |
- | |
- FullBucket { | |
- raw: self.raw, | |
- table: self.table, | |
- } | |
- } | |
} | |
impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { | |
@@ -574,17 +558,6 @@ | |
v) | |
} | |
} | |
- | |
- /// Remove this bucket's `key` from the hashtable. | |
- /// Only used for inplacement insertion. | |
- /// NOTE: `Value` is uninitialized when this function is called, don't try to drop the `Value`. | |
- pub unsafe fn remove_key(&mut self) { | |
- self.table.size -= 1; | |
- | |
- *self.raw.hash() = EMPTY_BUCKET; | |
- let pair_ptr = self.raw.pair(); | |
- ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key | |
- } | |
} | |
// This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases | |
@@ -678,144 +651,114 @@ | |
} | |
} | |
- | |
-/// Rounds up to a multiple of a power of two. Returns the closest multiple | |
-/// of `target_alignment` that is higher or equal to `unrounded`. | |
-/// | |
-/// # Panics | |
-/// | |
-/// Panics if `target_alignment` is not a power of two. | |
-#[inline] | |
-fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize { | |
- assert!(target_alignment.is_power_of_two()); | |
- (unrounded + target_alignment - 1) & !(target_alignment - 1) | |
+// Returns a Layout which describes the allocation required for a hash table, | |
+// and the offset of the array of (key, value) pairs in the allocation. | |
+fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> { | |
+ let hashes = Layout::array::<HashUint>(capacity)?; | |
+ let pairs = Layout::array::<(K, V)>(capacity)?; | |
+ hashes.extend(pairs).map(|(layout, _)| { | |
+ // LLVM seems to have trouble properly const-propagating pairs.align(), | |
+ // possibly due to the use of NonZeroUsize. This little hack allows it | |
+ // to generate optimal code. | |
+ // | |
+ // See https://github.com/rust-lang/rust/issues/51346 for more details. | |
+ ( | |
+ layout, | |
+ hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()), | |
+ ) | |
+ }) | |
} | |
-#[test] | |
-fn test_rounding() { | |
- assert_eq!(round_up_to_next(0, 4), 0); | |
- assert_eq!(round_up_to_next(1, 4), 4); | |
- assert_eq!(round_up_to_next(2, 4), 4); | |
- assert_eq!(round_up_to_next(3, 4), 4); | |
- assert_eq!(round_up_to_next(4, 4), 4); | |
- assert_eq!(round_up_to_next(5, 4), 8); | |
-} | |
- | |
-// Returns a tuple of (pairs_offset, end_of_pairs_offset), | |
-// from the start of a mallocated array. | |
-#[inline] | |
-fn calculate_offsets(hashes_size: usize, | |
- pairs_size: usize, | |
- pairs_align: usize) | |
- -> (usize, usize, bool) { | |
- let pairs_offset = round_up_to_next(hashes_size, pairs_align); | |
- let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); | |
- | |
- (pairs_offset, end_of_pairs, oflo) | |
-} | |
- | |
-// Returns a tuple of (minimum required malloc alignment, | |
-// array_size), from the start of a mallocated array. | |
-fn calculate_allocation(hash_size: usize, | |
- hash_align: usize, | |
- pairs_size: usize, | |
- pairs_align: usize) | |
- -> (usize, usize, bool) { | |
- let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); | |
- | |
- let align = cmp::max(hash_align, pairs_align); | |
- | |
- (align, end_of_pairs, oflo) | |
+pub(crate) enum Fallibility { | |
+ Fallible, | |
+ Infallible, | |
} | |
-#[test] | |
-fn test_offset_calculation() { | |
- assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); | |
- assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); | |
- assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); | |
- assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); | |
- assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); | |
- assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); | |
-} | |
+use self::Fallibility::*; | |
impl<K, V> RawTable<K, V> { | |
/// Does not initialize the buckets. The caller should ensure they, | |
/// at the very least, set every hash to EMPTY_BUCKET. | |
- unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { | |
+ /// Returns an error if it cannot allocate or capacity overflows. | |
+ unsafe fn new_uninitialized_internal( | |
+ capacity: usize, | |
+ fallibility: Fallibility, | |
+ ) -> Result<RawTable<K, V>, CollectionAllocErr> { | |
if capacity == 0 { | |
- return RawTable { | |
+ return Ok(RawTable { | |
size: 0, | |
capacity_mask: capacity.wrapping_sub(1), | |
hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), | |
marker: marker::PhantomData, | |
- }; | |
+ }); | |
} | |
- // No need for `checked_mul` before a more restrictive check performed | |
- // later in this method. | |
- let hashes_size = capacity.wrapping_mul(size_of::<HashUint>()); | |
- let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>()); | |
- | |
// Allocating hashmaps is a little tricky. We need to allocate two | |
// arrays, but since we know their sizes and alignments up front, | |
// we just allocate a single array, and then have the subarrays | |
// point into it. | |
- // | |
- // This is great in theory, but in practice getting the alignment | |
- // right is a little subtle. Therefore, calculating offsets has been | |
- // factored out into a different function. | |
- let (alignment, size, oflo) = calculate_allocation(hashes_size, | |
- align_of::<HashUint>(), | |
- pairs_size, | |
- align_of::<(K, V)>()); | |
- assert!(!oflo, "capacity overflow"); | |
- | |
- // One check for overflow that covers calculation and rounding of size. | |
- let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>()).unwrap(); | |
- assert!(size >= | |
- capacity.checked_mul(size_of_bucket) | |
- .expect("capacity overflow"), | |
- "capacity overflow"); | |
- | |
- let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) | |
- .unwrap_or_else(|e| Heap.oom(e)); | |
+ let (layout, _) = calculate_layout::<K, V>(capacity)?; | |
+ let buffer = Global.alloc(layout).map_err(|e| match fallibility { | |
+ Infallible => handle_alloc_error(layout), | |
+ Fallible => e, | |
+ })?; | |
- let hashes = buffer as *mut HashUint; | |
- | |
- RawTable { | |
+ Ok(RawTable { | |
capacity_mask: capacity.wrapping_sub(1), | |
size: 0, | |
- hashes: TaggedHashUintPtr::new(hashes), | |
+ hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), | |
marker: marker::PhantomData, | |
+ }) | |
+ } | |
+ | |
+ /// Does not initialize the buckets. The caller should ensure they, | |
+ /// at the very least, set every hash to EMPTY_BUCKET. | |
+ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { | |
+ match Self::new_uninitialized_internal(capacity, Infallible) { | |
+ Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), | |
+ Err(CollectionAllocErr::AllocErr) => unreachable!(), | |
+ Ok(table) => { table } | |
} | |
} | |
fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> { | |
- let hashes_size = self.capacity() * size_of::<HashUint>(); | |
- let pairs_size = self.capacity() * size_of::<(K, V)>(); | |
- | |
- let (pairs_offset, _, oflo) = | |
- calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); | |
- debug_assert!(!oflo, "capacity overflow"); | |
- | |
+ let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity()) | |
+ .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); | |
let buffer = self.hashes.ptr() as *mut u8; | |
unsafe { | |
RawBucket { | |
hash_start: buffer as *mut HashUint, | |
- pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), | |
+ pair_start: buffer.add(pairs_offset) as *const (K, V), | |
idx: index, | |
_marker: marker::PhantomData, | |
} | |
} | |
} | |
+ fn new_internal( | |
+ capacity: usize, | |
+ fallibility: Fallibility, | |
+ ) -> Result<RawTable<K, V>, CollectionAllocErr> { | |
+ unsafe { | |
+ let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?; | |
+ ptr::write_bytes(ret.hashes.ptr(), 0, capacity); | |
+ Ok(ret) | |
+ } | |
+ } | |
+ | |
+ /// Tries to create a new raw table from a given capacity. If it cannot allocate, | |
+ /// it returns with AllocErr. | |
+ pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> { | |
+ Self::new_internal(capacity, Fallible) | |
+ } | |
+ | |
/// Creates a new raw table from a given capacity. All buckets are | |
/// initially empty. | |
pub fn new(capacity: usize) -> RawTable<K, V> { | |
- unsafe { | |
- let ret = RawTable::new_uninitialized(capacity); | |
- ptr::write_bytes(ret.hashes.ptr(), 0, capacity); | |
- ret | |
+ match Self::new_internal(capacity, Infallible) { | |
+ Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), | |
+ Err(CollectionAllocErr::AllocErr) => unreachable!(), | |
+ Ok(table) => { table } | |
} | |
} | |
@@ -873,7 +816,7 @@ | |
elems_left, | |
marker: marker::PhantomData, | |
}, | |
- table: Shared::from(self), | |
+ table: NonNull::from(self), | |
marker: marker::PhantomData, | |
} | |
} | |
@@ -1020,7 +963,7 @@ | |
/// Iterator over the entries in a table, clearing the table. | |
pub struct Drain<'a, K: 'a, V: 'a> { | |
- table: Shared<RawTable<K, V>>, | |
+ table: NonNull<RawTable<K, V>>, | |
iter: RawBuckets<'static, K, V>, | |
marker: marker::PhantomData<&'a RawTable<K, V>>, | |
} | |
@@ -1129,7 +1072,7 @@ | |
impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { | |
fn drop(&mut self) { | |
- for _ in self {} | |
+ self.for_each(drop); | |
} | |
} | |
@@ -1178,18 +1121,10 @@ | |
} | |
} | |
- let hashes_size = self.capacity() * size_of::<HashUint>(); | |
- let pairs_size = self.capacity() * size_of::<(K, V)>(); | |
- let (align, size, oflo) = calculate_allocation(hashes_size, | |
- align_of::<HashUint>(), | |
- pairs_size, | |
- align_of::<(K, V)>()); | |
- | |
- debug_assert!(!oflo, "should be impossible"); | |
- | |
+ let (layout, _) = calculate_layout::<K, V>(self.capacity()) | |
+ .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); | |
unsafe { | |
- Heap.dealloc(self.hashes.ptr() as *mut u8, | |
- Layout::from_size_align(size, align).unwrap()); | |
+ Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); | |
// Remember how everything was allocated out of one buffer | |
// during initialization? We only need one call to free here. | |
} | |
diff -ruN orig/std/src/collections/mod.rs new/std/src/collections/mod.rs | |
--- orig/std/src/collections/mod.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/collections/mod.rs 2018-08-02 10:36:02.000000000 +0800 | |
@@ -420,23 +420,26 @@ | |
#![stable(feature = "rust1", since = "1.0.0")] | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::Bound; | |
+ | |
+#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] | |
+#[doc(hidden)] | |
+pub use ops::Bound; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; | |
+pub use alloc_crate::{BinaryHeap, BTreeMap, BTreeSet}; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::{LinkedList, VecDeque}; | |
+pub use alloc_crate::{LinkedList, VecDeque}; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::{binary_heap, btree_map, btree_set}; | |
+pub use alloc_crate::{binary_heap, btree_map, btree_set}; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::{linked_list, vec_deque}; | |
+pub use alloc_crate::{linked_list, vec_deque}; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub use self::hash_map::HashMap; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub use self::hash_set::HashSet; | |
-#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::range; | |
+#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] | |
+pub use alloc::CollectionAllocErr; | |
mod hash; | |
diff -ruN orig/std/src/error.rs new/std/src/error.rs | |
--- orig/std/src/error.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/error.rs 2018-08-02 10:42:28.000000000 +0800 | |
@@ -9,34 +9,6 @@ | |
// except according to those terms. | |
//! Traits for working with Errors. | |
-//! | |
-//! # The `Error` trait | |
-//! | |
-//! `Error` is a trait representing the basic expectations for error values, | |
-//! i.e. values of type `E` in [`Result<T, E>`]. At a minimum, errors must provide | |
-//! a description, but they may optionally provide additional detail (via | |
-//! [`Display`]) and cause chain information: | |
-//! | |
-//! ``` | |
-//! use std::fmt::Display; | |
-//! | |
-//! trait Error: Display { | |
-//! fn description(&self) -> &str; | |
-//! | |
-//! fn cause(&self) -> Option<&Error> { None } | |
-//! } | |
-//! ``` | |
-//! | |
-//! The [`cause`] method is generally used when errors cross "abstraction | |
-//! boundaries", i.e. when a one module must report an error that is "caused" | |
-//! by an error from a lower-level module. This setup makes it possible for the | |
-//! high-level module to provide its own errors that do not commit to any | |
-//! particular implementation, but also reveal some of its implementation for | |
-//! debugging via [`cause`] chains. | |
-//! | |
-//! [`Result<T, E>`]: ../result/enum.Result.html | |
-//! [`Display`]: ../fmt/trait.Display.html | |
-//! [`cause`]: trait.Error.html#method.cause | |
#![stable(feature = "rust1", since = "1.0.0")] | |
@@ -51,12 +23,11 @@ | |
// coherence challenge (e.g., specialization, neg impls, etc) we can | |
// reconsider what crate these items belong in. | |
-use alloc::allocator; | |
+use alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; | |
use any::TypeId; | |
use borrow::Cow; | |
use cell; | |
use char; | |
-use convert; | |
use core::array; | |
use fmt::{self, Debug, Display}; | |
use mem::transmute; | |
@@ -64,33 +35,48 @@ | |
use str; | |
use string; | |
-/// Base functionality for all errors in Rust. | |
+/// `Error` is a trait representing the basic expectations for error values, | |
+/// i.e. values of type `E` in [`Result<T, E>`]. Errors must describe | |
+/// themselves through the [`Display`] and [`Debug`] traits, and may provide | |
+/// cause chain information: | |
+/// | |
+/// The [`cause`] method is generally used when errors cross "abstraction | |
+/// boundaries", i.e. when a one module must report an error that is "caused" | |
+/// by an error from a lower-level module. This setup makes it possible for the | |
+/// high-level module to provide its own errors that do not commit to any | |
+/// particular implementation, but also reveal some of its implementation for | |
+/// debugging via [`cause`] chains. | |
+/// | |
+/// [`Result<T, E>`]: ../result/enum.Result.html | |
+/// [`Display`]: ../fmt/trait.Display.html | |
+/// [`cause`]: trait.Error.html#method.cause | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub trait Error: Debug + Display { | |
- /// A short description of the error. | |
+ /// **This method is soft-deprecated.** | |
/// | |
- /// The description should only be used for a simple message. | |
- /// It should not contain newlines or sentence-ending punctuation, | |
- /// to facilitate embedding in larger user-facing strings. | |
- /// For showing formatted error messages with more information see | |
- /// [`Display`]. | |
+ /// Although using it won’t cause compilation warning, | |
+ /// new code should use [`Display`] instead | |
+ /// and new `impl`s can omit it. | |
+ /// | |
+ /// To obtain error description as a string, use `to_string()`. | |
/// | |
/// [`Display`]: ../fmt/trait.Display.html | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
- /// use std::error::Error; | |
- /// | |
/// match "xc".parse::<u32>() { | |
/// Err(e) => { | |
- /// println!("Error: {}", e.description()); | |
+ /// // Print `e` itself, not `e.description()`. | |
+ /// println!("Error: {}", e); | |
/// } | |
/// _ => println!("No error"), | |
/// } | |
/// ``` | |
#[stable(feature = "rust1", since = "1.0.0")] | |
- fn description(&self) -> &str; | |
+ fn description(&self) -> &str { | |
+ "description() is deprecated; use Display" | |
+ } | |
/// The lower-level cause of this error, if any. | |
/// | |
@@ -242,18 +228,27 @@ | |
#[unstable(feature = "allocator_api", | |
reason = "the precise API and guarantees it provides may be tweaked.", | |
issue = "32838")] | |
-impl Error for allocator::AllocErr { | |
+impl Error for AllocErr { | |
+ fn description(&self) -> &str { | |
+ "memory allocation failed" | |
+ } | |
+} | |
+ | |
+#[unstable(feature = "allocator_api", | |
+ reason = "the precise API and guarantees it provides may be tweaked.", | |
+ issue = "32838")] | |
+impl Error for LayoutErr { | |
fn description(&self) -> &str { | |
- allocator::AllocErr::description(self) | |
+ "invalid parameters to Layout::from_size_align" | |
} | |
} | |
#[unstable(feature = "allocator_api", | |
reason = "the precise API and guarantees it provides may be tweaked.", | |
issue = "32838")] | |
-impl Error for allocator::CannotReallocInPlace { | |
+impl Error for CannotReallocInPlace { | |
fn description(&self) -> &str { | |
- allocator::CannotReallocInPlace::description(self) | |
+ CannotReallocInPlace::description(self) | |
} | |
} | |
@@ -371,14 +366,6 @@ | |
} | |
} | |
-#[unstable(feature = "try_from", issue = "33417")] | |
-impl Error for convert::Infallible { | |
- fn description(&self) -> &str { | |
- match *self { | |
- } | |
- } | |
-} | |
- | |
// copied from any.rs | |
impl Error + 'static { | |
/// Returns true if the boxed type is the same as `T` | |
diff -ruN orig/std/src/io/cursor.rs new/std/src/io/cursor.rs | |
--- orig/std/src/io/cursor.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/io/cursor.rs 2018-08-02 11:01:27.000000000 +0800 | |
@@ -10,7 +10,6 @@ | |
use io::prelude::*; | |
-use core::convert::TryInto; | |
use cmp; | |
use io::{self, Initializer, SeekFrom, Error, ErrorKind}; | |
@@ -260,9 +259,26 @@ | |
Ok(amt) | |
} | |
+/// Compensate removal of some impls per | |
+/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 | |
+#[cfg(any(target_pointer_width = "16", | |
+ target_pointer_width = "32"))] | |
+fn try_into(n: u64) -> Result<usize, ()> { | |
+ if n <= (<usize>::max_value() as u64) { | |
+ Ok(n as usize) | |
+ } else { | |
+ Err(()) | |
+ } | |
+} | |
+ | |
+#[cfg(any(target_pointer_width = "64"))] | |
+fn try_into(n: u64) -> Result<usize, ()> { | |
+ Ok(n as usize) | |
+} | |
+ | |
// Resizing write implementation | |
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> { | |
- let pos: usize = (*pos_mut).try_into().map_err(|_| { | |
+ let pos: usize = try_into(*pos_mut).map_err(|_| { | |
Error::new(ErrorKind::InvalidInput, | |
"cursor position exceeds maximum possible vector length") | |
})?; | |
@@ -296,7 +312,7 @@ | |
fn flush(&mut self) -> io::Result<()> { Ok(()) } | |
} | |
-#[unstable(feature = "cursor_mut_vec", issue = "30132")] | |
+#[stable(feature = "cursor_mut_vec", since = "1.25.0")] | |
impl<'a> Write for Cursor<&'a mut Vec<u8>> { | |
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
vec_write(&mut self.pos, self.inner, buf) | |
@@ -550,6 +566,7 @@ | |
} | |
#[test] | |
+ #[allow(deprecated)] | |
fn test_read_char() { | |
let b = &b"Vi\xE1\xBB\x87t"[..]; | |
let mut c = Cursor::new(b).chars(); | |
@@ -561,6 +578,7 @@ | |
} | |
#[test] | |
+ #[allow(deprecated)] | |
fn test_read_bad_char() { | |
let b = &b"\x80"[..]; | |
let mut c = Cursor::new(b).chars(); | |
diff -ruN orig/std/src/lib.rs new/std/src/lib.rs | |
--- orig/std/src/lib.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/lib.rs 2018-08-02 11:31:36.000000000 +0800 | |
@@ -266,11 +266,10 @@ | |
#![feature(fn_traits)] | |
#![feature(fnbox)] | |
#![feature(fused)] | |
-#![feature(generic_param_attrs)] | |
#![feature(hashmap_hasher)] | |
+#![feature(hashmap_internals)] | |
#![feature(heap_api)] | |
#![feature(i128)] | |
-#![feature(i128_type)] | |
#![feature(inclusive_range)] | |
#![feature(int_error_internals)] | |
#![feature(integer_atomics)] | |
@@ -279,7 +278,7 @@ | |
#![feature(libc)] | |
#![feature(link_args)] | |
#![feature(linkage)] | |
-#![feature(macro_reexport)] | |
+#![feature(use_extern_macros)] | |
#![feature(macro_vis_matcher)] | |
#![feature(needs_panic_runtime)] | |
#![feature(never_type)] | |
@@ -296,7 +295,6 @@ | |
#![feature(ptr_internals)] | |
#![feature(rand)] | |
#![feature(raw)] | |
-#![feature(repr_align)] | |
#![feature(rustc_attrs)] | |
#![feature(sip_hash_13)] | |
#![feature(slice_bytes)] | |
@@ -308,11 +306,11 @@ | |
#![feature(str_char)] | |
#![feature(str_internals)] | |
#![feature(str_utf16)] | |
-#![feature(termination_trait)] | |
#![feature(test, rustc_private)] | |
#![feature(thread_local)] | |
#![feature(toowned_clone_into)] | |
#![feature(try_from)] | |
+#![feature(try_reserve)] | |
#![feature(unboxed_closures)] | |
#![feature(unicode)] | |
#![feature(untagged_unions)] | |
@@ -321,6 +319,8 @@ | |
#![feature(doc_cfg)] | |
#![feature(doc_masked)] | |
#![feature(doc_spotlight)] | |
+#![feature(core_panic_info)] | |
+ | |
#![feature(shared)] //- added due to no NonNull changes | |
#![feature(unique)] //- added due to no NonNull changes | |
@@ -354,19 +354,17 @@ | |
//- #[cfg(test)] extern crate test; | |
//- #[cfg(test)] extern crate rand; | |
-// We want to re-export a few macros from core but libcore has already been | |
-// imported by the compiler (via our #[no_std] attribute) In this case we just | |
-// add a new crate name so we can attach the re-exports to it. | |
-//- #[macro_reexport(assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, | |
-#[macro_reexport(panic, assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, | |
- debug_assert_ne, unreachable, unimplemented, write, writeln, try)] | |
-extern crate core as __core; | |
- | |
-// #[macro_use] | |
-#[macro_reexport(vec, format)] | |
-extern crate alloc; | |
+ | |
+// Re-export a few macros from core | |
+#[stable(feature = "rust1", since = "1.0.0")] | |
+pub use core::{panic, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; | |
+#[stable(feature = "rust1", since = "1.0.0")] | |
+pub use core::{unreachable, unimplemented, write, writeln, try}; | |
+ | |
+#[allow(unused_imports)] // macros from `alloc` are not used on all platforms | |
+#[macro_use] | |
+extern crate alloc as alloc_crate; | |
//- extern crate alloc_system; | |
-extern crate std_unicode; | |
//- #[doc(masked)] | |
//- extern crate libc; | |
@@ -377,7 +375,6 @@ | |
// compiler-rt intrinsics | |
#[doc(masked)] | |
-extern crate compiler_builtins; | |
//- // During testing, this crate is not actually the "real" std library, but rather | |
//- // it links to the real std library, which was compiled from this same source | |
@@ -450,25 +447,30 @@ | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub use core::u64; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::boxed; | |
+pub use alloc_crate::boxed; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::rc; | |
+pub use alloc_crate::rc; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::borrow; | |
+pub use alloc_crate::borrow; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::fmt; | |
+pub use alloc_crate::fmt; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::slice; | |
+pub use alloc_crate::format; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::str; | |
+pub use alloc_crate::slice; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::string; | |
+pub use alloc_crate::str; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::vec; | |
+pub use alloc_crate::string; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use std_unicode::char; | |
-#[unstable(feature = "i128", issue = "35118")] | |
+pub use alloc_crate::vec; | |
+#[stable(feature = "rust1", since = "1.0.0")] | |
+pub use core::char; | |
+#[stable(feature = "i128", since = "1.26.0")] | |
pub use core::u128; | |
+#[stable(feature = "core_hint", since = "1.27.0")] | |
+pub use core::hint; | |
+#[stable(feature = "rust1", since = "1.0.0")] | |
//- pub mod f32; | |
//- pub mod f64; | |
@@ -497,6 +499,8 @@ | |
mod sys_common; | |
mod sys; | |
+pub mod alloc; | |
+ | |
// Private support modules | |
//- mod panicking; | |
mod memchr; | |
diff -ruN orig/std/src/sync/mod.rs new/std/src/sync/mod.rs | |
--- orig/std/src/sync/mod.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/sync/mod.rs 2018-08-02 10:43:44.000000000 +0800 | |
@@ -18,7 +18,7 @@ | |
#![stable(feature = "rust1", since = "1.0.0")] | |
#[stable(feature = "rust1", since = "1.0.0")] | |
-pub use alloc::arc::{Arc, Weak}; | |
+pub use alloc_crate::arc::{Arc, Weak}; | |
#[stable(feature = "rust1", since = "1.0.0")] | |
pub use core::sync::atomic; | |
diff -ruN orig/std/src/sys/mod.rs new/std/src/sys/mod.rs | |
--- orig/std/src/sys/mod.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/sys/mod.rs 2018-08-02 10:57:26.000000000 +0800 | |
@@ -103,3 +103,15 @@ | |
//- pub mod windows_ext; | |
//- } | |
//- } | |
+ | |
+// On Unix-like platforms, libc::abort will unregister signal handlers | |
+// including the SIGABRT handler, preventing the abort from being blocked, and | |
+// fclose streams, with the side effect of flushing them so libc bufferred | |
+// output will be printed. Additionally the shell will generally print a more | |
+// understandable error message like "Abort trap" rather than "Illegal | |
+// instruction" that intrinsics::abort would cause, as intrinsics::abort is | |
+// implemented as an illegal instruction. | |
+pub unsafe fn abort_internal() -> ! { | |
+ // ::libc::abort() | |
+ loop {} | |
+} | |
diff -ruN orig/std/src/sys/ros/mod.rs new/std/src/sys/ros/mod.rs | |
--- orig/std/src/sys/ros/mod.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/sys/ros/mod.rs 2018-08-02 10:46:42.000000000 +0800 | |
@@ -34,7 +34,7 @@ | |
use sync::Arc; | |
use sys_common::{AsInner, IntoInner}; | |
use sys_common::bytestring::debug_fmt_bytestring; | |
- use std_unicode::lossy::Utf8Lossy; | |
+ use core::str::lossy::Utf8Lossy; | |
#[derive(Clone, Hash)] | |
pub struct Buf { | |
diff -ruN orig/std/src/sys_common/bytestring.rs new/std/src/sys_common/bytestring.rs | |
--- orig/std/src/sys_common/bytestring.rs 2018-08-02 19:23:14.000000000 +0800 | |
+++ new/std/src/sys_common/bytestring.rs 2018-08-02 10:44:55.000000000 +0800 | |
@@ -11,7 +11,7 @@ | |
#![allow(dead_code)] | |
use fmt::{Formatter, Result, Write}; | |
-use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk}; | |
+use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; | |
pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { | |
// Writes out a valid unicode string with the correct escape sequences |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment