Skip to content

Instantly share code, notes, and snippets.

@abcdabcd987
Created August 16, 2018 01:53
Show Gist options
  • Save abcdabcd987/fb1f93a569bd6e4ddd7ac0b748b71af4 to your computer and use it in GitHub Desktop.
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/
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