Merge remote-tracking branch 'origin/master' into gen
This commit is contained in:
@@ -40,7 +40,7 @@ fn size_align<T>() -> (usize, usize) {
|
||||
///
|
||||
/// (Note however that layouts are *not* required to have positive
|
||||
/// size, even though many allocators require that all memory
|
||||
/// requeusts have positive size. A caller to the `Alloc::alloc`
|
||||
/// requests have positive size. A caller to the `Alloc::alloc`
|
||||
/// method must either ensure that conditions like this are met, or
|
||||
/// use specific allocators with looser requirements.)
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -240,7 +240,7 @@ impl Layout {
|
||||
///
|
||||
/// Returns `Some((k, offset))`, where `k` is layout of the concatenated
|
||||
/// record and `offset` is the relative location, in bytes, of the
|
||||
/// start of the `next` embedded witnin the concatenated record
|
||||
/// start of the `next` embedded within the concatenated record
|
||||
/// (assuming that the record itself starts at offset 0).
|
||||
///
|
||||
/// On arithmetic overflow, returns `None`.
|
||||
@@ -297,7 +297,7 @@ impl Layout {
|
||||
///
|
||||
/// Returns `(k, offset)`, where `k` is layout of the concatenated
|
||||
/// record and `offset` is the relative location, in bytes, of the
|
||||
/// start of the `next` embedded witnin the concatenated record
|
||||
/// start of the `next` embedded within the concatenated record
|
||||
/// (assuming that the record itself starts at offset 0).
|
||||
///
|
||||
/// (The `offset` is always the same as `self.size()`; we use this
|
||||
@@ -354,15 +354,19 @@ pub enum AllocErr {
|
||||
}
|
||||
|
||||
impl AllocErr {
|
||||
#[inline]
|
||||
pub fn invalid_input(details: &'static str) -> Self {
|
||||
AllocErr::Unsupported { details: details }
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_memory_exhausted(&self) -> bool {
|
||||
if let AllocErr::Exhausted { .. } = *self { true } else { false }
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_request_unsupported(&self) -> bool {
|
||||
if let AllocErr::Unsupported { .. } = *self { true } else { false }
|
||||
}
|
||||
#[inline]
|
||||
pub fn description(&self) -> &str {
|
||||
match *self {
|
||||
AllocErr::Exhausted { .. } => "allocator memory exhausted",
|
||||
@@ -544,7 +548,7 @@ pub unsafe trait Alloc {
|
||||
/// practice this means implementors should eschew allocating,
|
||||
/// especially from `self` (directly or indirectly).
|
||||
///
|
||||
/// Implementions of the allocation and reallocation methods
|
||||
/// Implementations of the allocation and reallocation methods
|
||||
/// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from
|
||||
/// panicking (or aborting) in the event of memory exhaustion;
|
||||
/// instead they should return an appropriate error from the
|
||||
|
||||
@@ -132,7 +132,7 @@ impl<K, V> InternalNode<K, V> {
|
||||
|
||||
/// An owned pointer to a node. This basically is either `Box<LeafNode<K, V>>` or
|
||||
/// `Box<InternalNode<K, V>>`. However, it contains no information as to which of the two types
|
||||
/// of nodes is acutally behind the box, and, partially due to this lack of information, has no
|
||||
/// of nodes is actually behind the box, and, partially due to this lack of information, has no
|
||||
/// destructor.
|
||||
struct BoxedNode<K, V> {
|
||||
ptr: Unique<LeafNode<K, V>>
|
||||
@@ -264,7 +264,7 @@ impl<K, V> Root<K, V> {
|
||||
// correct variance.
|
||||
/// A reference to a node.
|
||||
///
|
||||
/// This type has a number of paramaters that controls how it acts:
|
||||
/// This type has a number of parameters that controls how it acts:
|
||||
/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`.
|
||||
/// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`,
|
||||
/// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`,
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
|
||||
//! Utilities for formatting and printing `String`s
|
||||
//!
|
||||
//! This module contains the runtime support for the `format!` syntax extension.
|
||||
//! This module contains the runtime support for the [`format!`] syntax extension.
|
||||
//! This macro is implemented in the compiler to emit calls to this module in
|
||||
//! order to format arguments at runtime into strings.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! The `format!` macro is intended to be familiar to those coming from C's
|
||||
//! printf/fprintf functions or Python's `str.format` function.
|
||||
//! The [`format!`] macro is intended to be familiar to those coming from C's
|
||||
//! `printf`/`fprintf` functions or Python's `str.format` function.
|
||||
//!
|
||||
//! Some examples of the `format!` extension are:
|
||||
//! Some examples of the [`format!`] extension are:
|
||||
//!
|
||||
//! ```
|
||||
//! format!("Hello"); // => "Hello"
|
||||
@@ -67,7 +67,7 @@
|
||||
//! ## Named parameters
|
||||
//!
|
||||
//! Rust itself does not have a Python-like equivalent of named parameters to a
|
||||
//! function, but the `format!` macro is a syntax extension which allows it to
|
||||
//! function, but the [`format!`] macro is a syntax extension which allows it to
|
||||
//! leverage named parameters. Named parameters are listed at the end of the
|
||||
//! argument list and have the syntax:
|
||||
//!
|
||||
@@ -75,7 +75,7 @@
|
||||
//! identifier '=' expression
|
||||
//! ```
|
||||
//!
|
||||
//! For example, the following `format!` expressions all use named argument:
|
||||
//! For example, the following [`format!`] expressions all use named argument:
|
||||
//!
|
||||
//! ```
|
||||
//! format!("{argument}", argument = "test"); // => "test"
|
||||
@@ -102,30 +102,30 @@
|
||||
//!
|
||||
//! If this syntax is used, then the number of characters to print precedes the
|
||||
//! actual object being formatted, and the number of characters must have the
|
||||
//! type `usize`.
|
||||
//! type [`usize`].
|
||||
//!
|
||||
//! ## Formatting traits
|
||||
//!
|
||||
//! When requesting that an argument be formatted with a particular type, you
|
||||
//! are actually requesting that an argument ascribes to a particular trait.
|
||||
//! This allows multiple actual types to be formatted via `{:x}` (like `i8` as
|
||||
//! well as `isize`). The current mapping of types to traits is:
|
||||
//! This allows multiple actual types to be formatted via `{:x}` (like [`i8`] as
|
||||
//! well as [`isize`]). The current mapping of types to traits is:
|
||||
//!
|
||||
//! * *nothing* ⇒ [`Display`](trait.Display.html)
|
||||
//! * `?` ⇒ [`Debug`](trait.Debug.html)
|
||||
//! * *nothing* ⇒ [`Display`]
|
||||
//! * `?` ⇒ [`Debug`]
|
||||
//! * `o` ⇒ [`Octal`](trait.Octal.html)
|
||||
//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
|
||||
//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
|
||||
//! * `p` ⇒ [`Pointer`](trait.Pointer.html)
|
||||
//! * `b` ⇒ [`Binary`](trait.Binary.html)
|
||||
//! * `b` ⇒ [`Binary`]
|
||||
//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html)
|
||||
//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html)
|
||||
//!
|
||||
//! What this means is that any type of argument which implements the
|
||||
//! `fmt::Binary` trait can then be formatted with `{:b}`. Implementations
|
||||
//! [`fmt::Binary`][`Binary`] trait can then be formatted with `{:b}`. Implementations
|
||||
//! are provided for these traits for a number of primitive types by the
|
||||
//! standard library as well. If no format is specified (as in `{}` or `{:6}`),
|
||||
//! then the format trait used is the `Display` trait.
|
||||
//! then the format trait used is the [`Display`] trait.
|
||||
//!
|
||||
//! When implementing a format trait for your own type, you will have to
|
||||
//! implement a method of the signature:
|
||||
@@ -144,15 +144,15 @@
|
||||
//! should emit output into the `f.buf` stream. It is up to each format trait
|
||||
//! implementation to correctly adhere to the requested formatting parameters.
|
||||
//! The values of these parameters will be listed in the fields of the
|
||||
//! `Formatter` struct. In order to help with this, the `Formatter` struct also
|
||||
//! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also
|
||||
//! provides some helper methods.
|
||||
//!
|
||||
//! Additionally, the return value of this function is `fmt::Result` which is a
|
||||
//! type alias of `Result<(), std::fmt::Error>`. Formatting implementations
|
||||
//! should ensure that they propagate errors from the `Formatter` (e.g., when
|
||||
//! calling `write!`) however, they should never return errors spuriously. That
|
||||
//! Additionally, the return value of this function is [`fmt::Result`] which is a
|
||||
//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
|
||||
//! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when
|
||||
//! calling [`write!`]) however, they should never return errors spuriously. That
|
||||
//! is, a formatting implementation must and may only return an error if the
|
||||
//! passed-in `Formatter` returns an error. This is because, contrary to what
|
||||
//! passed-in [`Formatter`] returns an error. This is because, contrary to what
|
||||
//! the function signature might suggest, string formatting is an infallible
|
||||
//! operation. This function only returns a result because writing to the
|
||||
//! underlying stream might fail and it must provide a way to propagate the fact
|
||||
@@ -209,12 +209,12 @@
|
||||
//!
|
||||
//! These two formatting traits have distinct purposes:
|
||||
//!
|
||||
//! - `fmt::Display` implementations assert that the type can be faithfully
|
||||
//! - [`fmt::Display`][`Display`] implementations assert that the type can be faithfully
|
||||
//! represented as a UTF-8 string at all times. It is **not** expected that
|
||||
//! all types implement the `Display` trait.
|
||||
//! - `fmt::Debug` implementations should be implemented for **all** public types.
|
||||
//! - [`fmt::Debug`][`Debug`] implementations should be implemented for **all** public types.
|
||||
//! Output will typically represent the internal state as faithfully as possible.
|
||||
//! The purpose of the `Debug` trait is to facilitate debugging Rust code. In
|
||||
//! The purpose of the [`Debug`] trait is to facilitate debugging Rust code. In
|
||||
//! most cases, using `#[derive(Debug)]` is sufficient and recommended.
|
||||
//!
|
||||
//! Some examples of the output from both traits:
|
||||
@@ -227,7 +227,7 @@
|
||||
//!
|
||||
//! ## Related macros
|
||||
//!
|
||||
//! There are a number of related macros in the `format!` family. The ones that
|
||||
//! There are a number of related macros in the [`format!`] family. The ones that
|
||||
//! are currently implemented are:
|
||||
//!
|
||||
//! ```ignore (only-for-syntax-highlight)
|
||||
@@ -241,11 +241,11 @@
|
||||
//!
|
||||
//! ### `write!`
|
||||
//!
|
||||
//! This and `writeln` are two macros which are used to emit the format string
|
||||
//! This and [`writeln!`] are two macros which are used to emit the format string
|
||||
//! to a specified stream. This is used to prevent intermediate allocations of
|
||||
//! format strings and instead directly write the output. Under the hood, this
|
||||
//! function is actually invoking the `write_fmt` function defined on the
|
||||
//! `std::io::Write` trait. Example usage is:
|
||||
//! function is actually invoking the [`write_fmt`] function defined on the
|
||||
//! [`std::io::Write`] trait. Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
@@ -256,7 +256,7 @@
|
||||
//!
|
||||
//! ### `print!`
|
||||
//!
|
||||
//! This and `println` emit their output to stdout. Similarly to the `write!`
|
||||
//! This and [`println!`] emit their output to stdout. Similarly to the [`write!`]
|
||||
//! macro, the goal of these macros is to avoid intermediate allocations when
|
||||
//! printing output. Example usage is:
|
||||
//!
|
||||
@@ -288,8 +288,8 @@
|
||||
//! my_fmt_fn(format_args!(", or a {} too", "function"));
|
||||
//! ```
|
||||
//!
|
||||
//! The result of the `format_args!` macro is a value of type `fmt::Arguments`.
|
||||
//! This structure can then be passed to the `write` and `format` functions
|
||||
//! The result of the [`format_args!`] macro is a value of type [`fmt::Arguments`].
|
||||
//! This structure can then be passed to the [`write`] and [`format`] functions
|
||||
//! inside this module in order to process the format string.
|
||||
//! The goal of this macro is to even further prevent intermediate allocations
|
||||
//! when dealing formatting strings.
|
||||
@@ -357,7 +357,7 @@
|
||||
//! * `-` - Currently not used
|
||||
//! * `#` - This flag is indicates that the "alternate" form of printing should
|
||||
//! be used. The alternate forms are:
|
||||
//! * `#?` - pretty-print the `Debug` formatting
|
||||
//! * `#?` - pretty-print the [`Debug`] formatting
|
||||
//! * `#x` - precedes the argument with a `0x`
|
||||
//! * `#X` - precedes the argument with a `0x`
|
||||
//! * `#b` - precedes the argument with a `0b`
|
||||
@@ -384,9 +384,9 @@
|
||||
//! the `0` flag is specified for numerics, then the implicit fill character is
|
||||
//! `0`.
|
||||
//!
|
||||
//! The value for the width can also be provided as a `usize` in the list of
|
||||
//! The value for the width can also be provided as a [`usize`] in the list of
|
||||
//! parameters by using the dollar syntax indicating that the second argument is
|
||||
//! a `usize` specifying the width, for example:
|
||||
//! a [`usize`] specifying the width, for example:
|
||||
//!
|
||||
//! ```
|
||||
//! // All of these print "Hello x !"
|
||||
@@ -474,6 +474,29 @@
|
||||
//! The literal characters `{` and `}` may be included in a string by preceding
|
||||
//! them with the same character. For example, the `{` character is escaped with
|
||||
//! `{{` and the `}` character is escaped with `}}`.
|
||||
//!
|
||||
//! [`format!`]: ../../macro.format.html
|
||||
//! [`usize`]: ../../std/primitive.usize.html
|
||||
//! [`isize`]: ../../std/primitive.isize.html
|
||||
//! [`i8`]: ../../std/primitive.i8.html
|
||||
//! [`Display`]: trait.Display.html
|
||||
//! [`Binary`]: trait.Binary.html
|
||||
//! [`fmt::Result`]: type.Result.html
|
||||
//! [`Result`]: ../../std/result/enum.Result.html
|
||||
//! [`std::fmt::Error`]: struct.Error.html
|
||||
//! [`Formatter`]: struct.Formatter.html
|
||||
//! [`write!`]: ../../std/macro.write.html
|
||||
//! [`Debug`]: trait.Debug.html
|
||||
//! [`format!`]: ../../std/macro.format.html
|
||||
//! [`writeln!`]: ../../std/macro.writeln.html
|
||||
//! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt
|
||||
//! [`std::io::Write`]: ../../std/io/trait.Write.html
|
||||
//! [`println!`]: ../../std/macro.println.html
|
||||
//! [`write!`]: ../../std/macro.write.html
|
||||
//! [`format_args!`]: ../../std/macro.format_args.html
|
||||
//! [`fmt::Arguments`]: struct.Arguments.html
|
||||
//! [`write`]: fn.write.html
|
||||
//! [`format`]: fn.format.html
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
@@ -498,10 +521,10 @@ pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
|
||||
|
||||
use string;
|
||||
|
||||
/// The `format` function takes an `Arguments` struct and returns the resulting
|
||||
/// The `format` function takes an [`Arguments`] struct and returns the resulting
|
||||
/// formatted string.
|
||||
///
|
||||
/// The `Arguments` instance can be created with the `format_args!` macro.
|
||||
/// The [`Arguments`] instance can be created with the [`format_args!`] macro.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -514,7 +537,7 @@ use string;
|
||||
/// assert_eq!(s, "Hello, world!");
|
||||
/// ```
|
||||
///
|
||||
/// Please note that using [`format!`][format!] might be preferrable.
|
||||
/// Please note that using [`format!`] might be preferrable.
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
@@ -522,7 +545,9 @@ use string;
|
||||
/// assert_eq!(s, "Hello, world!");
|
||||
/// ```
|
||||
///
|
||||
/// [format!]: ../macro.format.html
|
||||
/// [`Arguments`]: struct.Arguments.html
|
||||
/// [`format_args!`]: ../../std/macro.format_args.html
|
||||
/// [`format!`]: ../../std/macro.format.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn format(args: Arguments) -> string::String {
|
||||
let capacity = args.estimated_capacity();
|
||||
|
||||
@@ -28,6 +28,7 @@ pub mod __core {
|
||||
extern "Rust" {
|
||||
#[allocator]
|
||||
fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
||||
#[cold]
|
||||
fn __rust_oom(err: *const u8) -> !;
|
||||
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
|
||||
fn __rust_usable_size(layout: *const u8,
|
||||
@@ -81,6 +82,7 @@ unsafe impl Alloc for Heap {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cold]
|
||||
fn oom(&mut self, err: AllocErr) -> ! {
|
||||
unsafe {
|
||||
__rust_oom(&err as *const AllocErr as *const u8)
|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use allocator::{Alloc, Layout};
|
||||
use core::ptr::{self, Unique};
|
||||
use core::mem;
|
||||
use core::slice;
|
||||
use heap::Heap;
|
||||
use super::boxed::Box;
|
||||
use core::ops::Drop;
|
||||
use core::cmp;
|
||||
use core::mem;
|
||||
use core::ops::Drop;
|
||||
use core::ptr::{self, Unique};
|
||||
use core::slice;
|
||||
use heap::{Alloc, Layout, Heap};
|
||||
use super::boxed::Box;
|
||||
|
||||
/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
|
||||
/// a buffer of memory on the heap without having to worry about all the corner cases
|
||||
@@ -222,6 +221,20 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
&mut self.a
|
||||
}
|
||||
|
||||
fn current_layout(&self) -> Option<Layout> {
|
||||
if self.cap == 0 {
|
||||
None
|
||||
} else {
|
||||
// We have an allocated chunk of memory, so we can bypass runtime
|
||||
// checks to get our current layout.
|
||||
unsafe {
|
||||
let align = mem::align_of::<T>();
|
||||
let size = mem::size_of::<T>() * self.cap;
|
||||
Some(Layout::from_size_align_unchecked(size, align))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Doubles the size of the type's backing allocation. This is common enough
|
||||
/// to want to do that it's easiest to just have a dedicated method. Slightly
|
||||
/// more efficient logic can be provided for this than the general case.
|
||||
@@ -280,27 +293,40 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
// 0, getting to here necessarily means the RawVec is overfull.
|
||||
assert!(elem_size != 0, "capacity overflow");
|
||||
|
||||
let (new_cap, ptr_res) = if self.cap == 0 {
|
||||
// skip to 4 because tiny Vec's are dumb; but not if that would cause overflow
|
||||
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
|
||||
let ptr_res = self.a.alloc_array::<T>(new_cap);
|
||||
(new_cap, ptr_res)
|
||||
} else {
|
||||
// Since we guarantee that we never allocate more than isize::MAX bytes,
|
||||
// `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow
|
||||
let new_cap = 2 * self.cap;
|
||||
let new_alloc_size = new_cap * elem_size;
|
||||
alloc_guard(new_alloc_size);
|
||||
let ptr_res = self.a.realloc_array(self.ptr, self.cap, new_cap);
|
||||
(new_cap, ptr_res)
|
||||
let (new_cap, uniq) = match self.current_layout() {
|
||||
Some(cur) => {
|
||||
// Since we guarantee that we never allocate more than
|
||||
// isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as
|
||||
// a precondition, so this can't overflow. Additionally the
|
||||
// alignment will never be too large as to "not be
|
||||
// satisfiable", so `Layout::from_size_align` will always
|
||||
// return `Some`.
|
||||
//
|
||||
// tl;dr; we bypass runtime checks due to dynamic assertions
|
||||
// in this module, allowing us to use
|
||||
// `from_size_align_unchecked`.
|
||||
let new_cap = 2 * self.cap;
|
||||
let new_size = new_cap * elem_size;
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, cur.align());
|
||||
alloc_guard(new_size);
|
||||
let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8,
|
||||
cur,
|
||||
new_layout);
|
||||
match ptr_res {
|
||||
Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)),
|
||||
Err(e) => self.a.oom(e),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// skip to 4 because tiny Vec's are dumb; but not if that
|
||||
// would cause overflow
|
||||
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
|
||||
match self.a.alloc_array::<T>(new_cap) {
|
||||
Ok(ptr) => (new_cap, ptr),
|
||||
Err(e) => self.a.oom(e),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If allocate or reallocate fail, we'll get `null` back
|
||||
let uniq = match ptr_res {
|
||||
Err(err) => self.a.oom(err),
|
||||
Ok(uniq) => uniq,
|
||||
};
|
||||
|
||||
self.ptr = uniq;
|
||||
self.cap = new_cap;
|
||||
}
|
||||
@@ -323,21 +349,27 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
pub fn double_in_place(&mut self) -> bool {
|
||||
unsafe {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
let old_layout = match self.current_layout() {
|
||||
Some(layout) => layout,
|
||||
None => return false, // nothing to double
|
||||
};
|
||||
|
||||
// since we set the capacity to usize::MAX when elem_size is
|
||||
// 0, getting to here necessarily means the RawVec is overfull.
|
||||
assert!(elem_size != 0, "capacity overflow");
|
||||
|
||||
// Since we guarantee that we never allocate more than isize::MAX bytes,
|
||||
// `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow
|
||||
// Since we guarantee that we never allocate more than isize::MAX
|
||||
// bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so
|
||||
// this can't overflow.
|
||||
//
|
||||
// Similarly like with `double` above we can go straight to
|
||||
// `Layout::from_size_align_unchecked` as we know this won't
|
||||
// overflow and the alignment is sufficiently small.
|
||||
let new_cap = 2 * self.cap;
|
||||
let new_alloc_size = new_cap * elem_size;
|
||||
|
||||
alloc_guard(new_alloc_size);
|
||||
|
||||
let new_size = new_cap * elem_size;
|
||||
alloc_guard(new_size);
|
||||
let ptr = self.ptr() as *mut _;
|
||||
let old_layout = Layout::new::<T>().repeat(self.cap).unwrap().0;
|
||||
let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
|
||||
match self.a.grow_in_place(ptr, old_layout, new_layout) {
|
||||
Ok(_) => {
|
||||
// We can't directly divide `size`.
|
||||
@@ -373,8 +405,6 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
/// Aborts on OOM
|
||||
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
|
||||
unsafe {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
|
||||
// NOTE: we don't early branch on ZSTs here because we want this
|
||||
// to actually catch "asking for more than usize::MAX" in that case.
|
||||
// If we make it past the first branch then we are guaranteed to
|
||||
@@ -388,21 +418,22 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
|
||||
// Nothing we can really do about these checks :(
|
||||
let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow");
|
||||
let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow");
|
||||
alloc_guard(new_alloc_size);
|
||||
|
||||
let result = if self.cap == 0 {
|
||||
self.a.alloc_array::<T>(new_cap)
|
||||
} else {
|
||||
self.a.realloc_array(self.ptr, self.cap, new_cap)
|
||||
let new_layout = match Layout::array::<T>(new_cap) {
|
||||
Some(layout) => layout,
|
||||
None => panic!("capacity overflow"),
|
||||
};
|
||||
|
||||
// If allocate or reallocate fail, we'll get `null` back
|
||||
let uniq = match result {
|
||||
Err(err) => self.a.oom(err),
|
||||
Ok(uniq) => uniq,
|
||||
alloc_guard(new_layout.size());
|
||||
let res = match self.current_layout() {
|
||||
Some(layout) => {
|
||||
let old_ptr = self.ptr.as_ptr() as *mut u8;
|
||||
self.a.realloc(old_ptr, layout, new_layout)
|
||||
}
|
||||
None => self.a.alloc(new_layout),
|
||||
};
|
||||
let uniq = match res {
|
||||
Ok(ptr) => Unique::new_unchecked(ptr as *mut T),
|
||||
Err(e) => self.a.oom(e),
|
||||
};
|
||||
|
||||
self.ptr = uniq;
|
||||
self.cap = new_cap;
|
||||
}
|
||||
@@ -411,17 +442,14 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
/// Calculates the buffer's new size given that it'll hold `used_cap +
|
||||
/// needed_extra_cap` elements. This logic is used in amortized reserve methods.
|
||||
/// Returns `(new_capacity, new_alloc_size)`.
|
||||
fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) -> (usize, usize) {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) -> usize {
|
||||
// Nothing we can really do about these checks :(
|
||||
let required_cap = used_cap.checked_add(needed_extra_cap)
|
||||
.expect("capacity overflow");
|
||||
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
|
||||
let double_cap = self.cap * 2;
|
||||
// `double_cap` guarantees exponential growth.
|
||||
let new_cap = cmp::max(double_cap, required_cap);
|
||||
let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow");
|
||||
(new_cap, new_alloc_size)
|
||||
cmp::max(double_cap, required_cap)
|
||||
}
|
||||
|
||||
/// Ensures that the buffer contains at least enough space to hold
|
||||
@@ -489,21 +517,25 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
return;
|
||||
}
|
||||
|
||||
let (new_cap, new_alloc_size) = self.amortized_new_size(used_cap, needed_extra_cap);
|
||||
let new_cap = self.amortized_new_size(used_cap, needed_extra_cap);
|
||||
|
||||
let new_layout = match Layout::array::<T>(new_cap) {
|
||||
Some(layout) => layout,
|
||||
None => panic!("capacity overflow"),
|
||||
};
|
||||
// FIXME: may crash and burn on over-reserve
|
||||
alloc_guard(new_alloc_size);
|
||||
|
||||
let result = if self.cap == 0 {
|
||||
self.a.alloc_array::<T>(new_cap)
|
||||
} else {
|
||||
self.a.realloc_array(self.ptr, self.cap, new_cap)
|
||||
alloc_guard(new_layout.size());
|
||||
let res = match self.current_layout() {
|
||||
Some(layout) => {
|
||||
let old_ptr = self.ptr.as_ptr() as *mut u8;
|
||||
self.a.realloc(old_ptr, layout, new_layout)
|
||||
}
|
||||
None => self.a.alloc(new_layout),
|
||||
};
|
||||
|
||||
let uniq = match result {
|
||||
Err(err) => self.a.oom(err),
|
||||
Ok(uniq) => uniq,
|
||||
let uniq = match res {
|
||||
Ok(ptr) => Unique::new_unchecked(ptr as *mut T),
|
||||
Err(e) => self.a.oom(e),
|
||||
};
|
||||
|
||||
self.ptr = uniq;
|
||||
self.cap = new_cap;
|
||||
}
|
||||
@@ -536,21 +568,24 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
// Don't actually need any more capacity. If the current `cap` is 0, we can't
|
||||
// reallocate in place.
|
||||
// Wrapping in case they give a bad `used_cap`
|
||||
if self.cap().wrapping_sub(used_cap) >= needed_extra_cap || self.cap == 0 {
|
||||
let old_layout = match self.current_layout() {
|
||||
Some(layout) => layout,
|
||||
None => return false,
|
||||
};
|
||||
if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
|
||||
return false;
|
||||
}
|
||||
|
||||
let (new_cap, new_alloc_size) = self.amortized_new_size(used_cap, needed_extra_cap);
|
||||
// FIXME: may crash and burn on over-reserve
|
||||
alloc_guard(new_alloc_size);
|
||||
let new_cap = self.amortized_new_size(used_cap, needed_extra_cap);
|
||||
|
||||
// Here, `cap < used_cap + needed_extra_cap <= new_cap`
|
||||
// (regardless of whether `self.cap - used_cap` wrapped).
|
||||
// Therefore we can safely call grow_in_place.
|
||||
|
||||
let ptr = self.ptr() as *mut _;
|
||||
let old_layout = Layout::new::<T>().repeat(self.cap).unwrap().0;
|
||||
let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
|
||||
// FIXME: may crash and burn on over-reserve
|
||||
alloc_guard(new_layout.size());
|
||||
match self.a.grow_in_place(ptr, old_layout, new_layout) {
|
||||
Ok(_) => {
|
||||
self.cap = new_cap;
|
||||
@@ -599,9 +634,24 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
}
|
||||
} else if self.cap != amount {
|
||||
unsafe {
|
||||
match self.a.realloc_array(self.ptr, self.cap, amount) {
|
||||
// We know here that our `amount` is greater than zero. This
|
||||
// implies, via the assert above, that capacity is also greater
|
||||
// than zero, which means that we've got a current layout that
|
||||
// "fits"
|
||||
//
|
||||
// We also know that `self.cap` is greater than `amount`, and
|
||||
// consequently we don't need runtime checks for creating either
|
||||
// layout
|
||||
let old_size = elem_size * self.cap;
|
||||
let new_size = elem_size * amount;
|
||||
let align = mem::align_of::<T>();
|
||||
let old_layout = Layout::from_size_align_unchecked(old_size, align);
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, align);
|
||||
match self.a.realloc(self.ptr.as_ptr() as *mut u8,
|
||||
old_layout,
|
||||
new_layout) {
|
||||
Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T),
|
||||
Err(err) => self.a.oom(err),
|
||||
Ok(uniq) => self.ptr = uniq,
|
||||
}
|
||||
}
|
||||
self.cap = amount;
|
||||
@@ -631,10 +681,11 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
/// Frees the memory owned by the RawVec *without* trying to Drop its contents.
|
||||
pub unsafe fn dealloc_buffer(&mut self) {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
if elem_size != 0 && self.cap != 0 {
|
||||
let ptr = self.ptr() as *mut u8;
|
||||
let layout = Layout::new::<T>().repeat(self.cap).unwrap().0;
|
||||
self.a.dealloc(ptr, layout);
|
||||
if elem_size != 0 {
|
||||
if let Some(layout) = self.current_layout() {
|
||||
let ptr = self.ptr() as *mut u8;
|
||||
self.a.dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ impl String {
|
||||
/// * `capacity` needs to be the correct value.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal datastructures.
|
||||
/// internal data structures.
|
||||
///
|
||||
/// The ownership of `ptr` is effectively transferred to the
|
||||
/// `String` which may then deallocate, reallocate or change the
|
||||
|
||||
@@ -374,7 +374,7 @@ impl<T> Vec<T> {
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal datastructures. For example it is **not** safe
|
||||
/// internal data structures. For example it is **not** safe
|
||||
/// to build a `Vec<u8>` from a pointer to a C `char` array and a `size_t`.
|
||||
///
|
||||
/// The ownership of `ptr` is effectively transferred to the
|
||||
|
||||
Reference in New Issue
Block a user