mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-21 05:53:09 +00:00
Bump bumpalo from 3.10.0 to 3.12.0 in /zeroidc (#1857)
* Bump bumpalo from 3.10.0 to 3.12.0 in /zeroidc Bumps [bumpalo](https://github.com/fitzgen/bumpalo) from 3.10.0 to 3.12.0. - [Release notes](https://github.com/fitzgen/bumpalo/releases) - [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md) - [Commits](https://github.com/fitzgen/bumpalo/compare/3.10.0...3.12.0) --- updated-dependencies: - dependency-name: bumpalo dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> * vendor bumpalo update to fix dependabot --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Grant Limberg <grant.limberg@zerotier.com>
This commit is contained in:
parent
e0a3291235
commit
6aea546d6f
4
zeroidc/Cargo.lock
generated
4
zeroidc/Cargo.lock
generated
@ -57,9 +57,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.10.0"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
|
2
zeroidc/vendor/bumpalo/.cargo-checksum.json
vendored
2
zeroidc/vendor/bumpalo/.cargo-checksum.json
vendored
@ -1 +1 @@
|
||||
{"files":{"CHANGELOG.md":"506ba9e82e7d0354739d7ea9a051fd8e77e0a2842b25063d97d72c84f73b5620","Cargo.toml":"ef3049ea38d9acf8d7a1b3a72fb559548232e5e4562fde190e29530d1caff9f2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"65f94e99ddaf4f5d1782a6dae23f35d4293a9a01444a13135a6887017d353cee","README.md":"1b8b798489668a6053520f90534a795ba73e33928022d10d364dfd8f8df7b5a3","src/alloc.rs":"ab0f23fa11c26efdd8f0596ebdf0e3faa75d097881fb59639b0fb23340c106bc","src/boxed.rs":"8a54f74527691012a1416e7e65ae1dc9f9f4711afd252704a7222b04cce60194","src/collections/collect_in.rs":"0588a4ff3967a4323abb4218bbd615af4b123639ab4fae9130c6590c258b3d15","src/collections/mod.rs":"d58dc46eb4f9fcdde574f09bc5b8646f53e42d49c169561d98e0c23e5b36848a","src/collections/raw_vec.rs":"a4eebed2bd81a039e4f120f1e4230585b8f3bbb42c27f79af28d0c05ee7b6866","src/collections/str/lossy.rs":"c5d62b16e01071e2a574ae41ef6693ad12f1e6c786c5d38f7a13ebd6cb23c088","src/collections/str/mod.rs":"d82a8bd417fbf52a589d89a16ea2a0ac4f6ac920c3976ab1f5b6ac0c8493c4f2","src/collections/string.rs":"7719005ca29d6031c7bf06ebcfd94ea27891da1aadd797ca45aadff598d2b7ee","src/collections/vec.rs":"7a757c495e4688a8db8482105206338e86df0ea2774765382091a36602cf3638","src/lib.rs":"72d2f350246d7365b893f40bc106c6bdd6bb2dbb1fc836d6e04f6d76ca2c282f"},"package":"37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"}
|
||||
{"files":{"CHANGELOG.md":"8b5a7a49c720ba2678c07184f50b3608e2165fbf6704da494fba23c864e691e0","Cargo.toml":"8d5fd21d2b3ed1d7149e864d43f843fd469ccdcd9893ac3c2bef8518294a61dd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"65f94e99ddaf4f5d1782a6dae23f35d4293a9a01444a13135a6887017d353cee","README.md":"00c9224790248ec71d1505615429699fd685b0290a0c2b6d7c0df0214e7f80eb","src/alloc.rs":"ab0f23fa11c26efdd8f0596ebdf0e3faa75d097881fb59639b0fb23340c106bc","src/boxed.rs":"5fc935f8e1a7bc1b8f6a39b2bcc4355a2be4743f2308fe3ffd557455a3a27cb2","src/collections/collect_in.rs":"0588a4ff3967a4323abb4218bbd615af4b123639ab4fae9130c6590c258b3d15","src/collections/mod.rs":"d58dc46eb4f9fcdde574f09bc5b8646f53e42d49c169561d98e0c23e5b36848a","src/collections/raw_vec.rs":"8829cc9a693fde38aa93e47a7bbbc2dac247620d07f60519f2e6cb44f5494bc5","src/collections/str/lossy.rs":"c5d62b16e01071e2a574ae41ef6693ad12f1e6c786c5d38f7a13ebd6cb23c088","src/collections/str/mod.rs":"d82a8bd417fbf52a589d89a16ea2a0ac4f6ac920c3976ab1f5b6ac0c8493c4f2","src/collections/string.rs":"388d39b999788baf5c14ccc3f5cb57da728060ea3295ddfc28f0f2e1ca5858ec","src/collections/vec.rs":"2eaf52e085e6d04767e97b224e82688dd0debd231c6536d6034f431376aa8bf0","src/lib.rs":"9eb2bdb8359b368a6f3091a66b3a5eb1216672ec1605cb18d5da28292c381cb9"},"package":"0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"}
|
49
zeroidc/vendor/bumpalo/CHANGELOG.md
vendored
49
zeroidc/vendor/bumpalo/CHANGELOG.md
vendored
@ -28,6 +28,55 @@ Released YYYY-MM-DD.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 3.12.0
|
||||
|
||||
Released 2023-01-17.
|
||||
|
||||
### Added
|
||||
|
||||
* Added the `bumpalo::boxed::Box::bump` and `bumpalo::collections::String::bump`
|
||||
getters to get the underlying `Bump` that a string or box was allocated into.
|
||||
|
||||
### Changed
|
||||
|
||||
* Some uses of `Box` that MIRI did not previously consider as UB are now
|
||||
reported as UB, and `bumpalo`'s internals have been adjusted to avoid the new
|
||||
UB.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 3.11.1
|
||||
|
||||
Released 2022-10-18.
|
||||
|
||||
### Security
|
||||
|
||||
* Fixed a bug where when `std::vec::IntoIter` was ported to
|
||||
`bumpalo::collections::vec::IntoIter`, it didn't get its underlying `Bump`'s
|
||||
lifetime threaded through. This meant that `rustc` was not checking the
|
||||
borrows for `bumpalo::collections::IntoIter` and this could result in
|
||||
use-after-free bugs.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 3.11.0
|
||||
|
||||
Released 2022-08-17.
|
||||
|
||||
### Added
|
||||
|
||||
* Added support for per-`Bump` allocation limits. These are enforced only in the
|
||||
slow path when allocating new chunks in the `Bump`, not in the bump allocation
|
||||
hot path, and therefore impose near zero overhead.
|
||||
* Added the `bumpalo::boxed::Box::into_inner` method.
|
||||
|
||||
### Changed
|
||||
|
||||
* Updated to Rust 2021 edition.
|
||||
* The minimum supported Rust version (MSRV) is now 1.56.0.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 3.10.0
|
||||
|
||||
Released 2022-06-01.
|
||||
|
10
zeroidc/vendor/bumpalo/Cargo.toml
vendored
10
zeroidc/vendor/bumpalo/Cargo.toml
vendored
@ -10,9 +10,9 @@
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
name = "bumpalo"
|
||||
version = "3.10.0"
|
||||
version = "3.12.0"
|
||||
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
|
||||
exclude = [
|
||||
"/.github/*",
|
||||
@ -51,13 +51,13 @@ harness = false
|
||||
required-features = ["collections"]
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3.0"
|
||||
version = "0.3.6"
|
||||
|
||||
[dev-dependencies.quickcheck]
|
||||
version = "0.9.0"
|
||||
version = "1.0.3"
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.7"
|
||||
version = "0.8.5"
|
||||
|
||||
[features]
|
||||
allocator_api = []
|
||||
|
20
zeroidc/vendor/bumpalo/README.md
vendored
20
zeroidc/vendor/bumpalo/README.md
vendored
@ -147,7 +147,8 @@ in its space itself.
|
||||
// Drop our `Box<CountDrops>`.
|
||||
drop(c);
|
||||
|
||||
// Its `Drop` implementation was run, and so `NUM_DROPS` has been incremented.
|
||||
// Its `Drop` implementation was run, and so `NUM_DROPS` has been
|
||||
// incremented.
|
||||
assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
```
|
||||
@ -158,11 +159,11 @@ Bumpalo is a `no_std` crate. It depends only on the `alloc` and `core` crates.
|
||||
|
||||
### Thread support
|
||||
|
||||
The `Bump` is `!Sync`, which makes it hard to use in certain situations around threads ‒ for
|
||||
example in `rayon`.
|
||||
The `Bump` is `!Sync`, which makes it hard to use in certain situations around
|
||||
threads ‒ for example in `rayon`.
|
||||
|
||||
The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a pool of `Bump`
|
||||
allocators for use in such situations.
|
||||
The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a
|
||||
pool of `Bump` allocators for use in such situations.
|
||||
|
||||
### Nightly Rust `allocator_api` Support
|
||||
|
||||
@ -181,7 +182,8 @@ First, enable the `allocator_api` feature in your `Cargo.toml`:
|
||||
bumpalo = { version = "3.9", features = ["allocator_api"] }
|
||||
```
|
||||
|
||||
Next, enable the `allocator_api` nightly Rust feature in your `src/lib.rs` or `src/main.rs`:
|
||||
Next, enable the `allocator_api` nightly Rust feature in your `src/lib.rs` or
|
||||
`src/main.rs`:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(allocator_api)]
|
||||
@ -207,8 +209,8 @@ v.push(2);
|
||||
|
||||
#### Minimum Supported Rust Version (MSRV)
|
||||
|
||||
This crate is guaranteed to compile on stable Rust **1.54** and up. It might
|
||||
This crate is guaranteed to compile on stable Rust **1.56** and up. It might
|
||||
compile with older versions but that may change in any new patch release.
|
||||
|
||||
We reserve the right to increment the MSRV on minor releases, however we will strive
|
||||
to only do it deliberately and for good reasons.
|
||||
We reserve the right to increment the MSRV on minor releases, however we will
|
||||
strive to only do it deliberately and for good reasons.
|
||||
|
33
zeroidc/vendor/bumpalo/src/boxed.rs
vendored
33
zeroidc/vendor/bumpalo/src/boxed.rs
vendored
@ -130,7 +130,7 @@ use {
|
||||
future::Future,
|
||||
hash::{Hash, Hasher},
|
||||
iter::FusedIterator,
|
||||
mem,
|
||||
mem::ManuallyDrop,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
@ -171,6 +171,24 @@ impl<'a, T> Box<'a, T> {
|
||||
pub fn pin_in(x: T, a: &'a Bump) -> Pin<Box<'a, T>> {
|
||||
Box(a.alloc(x)).into()
|
||||
}
|
||||
|
||||
/// Consumes the `Box`, returning the wrapped value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bumpalo::{Bump, boxed::Box};
|
||||
///
|
||||
/// let b = Bump::new();
|
||||
///
|
||||
/// let hello = Box::new_in("hello".to_owned(), &b);
|
||||
/// assert_eq!(Box::into_inner(hello), "hello");
|
||||
/// ```
|
||||
pub fn into_inner(b: Box<'a, T>) -> T {
|
||||
// `Box::into_raw` returns a pointer that is properly aligned and non-null.
|
||||
// The underlying `Bump` only frees the memory, but won't call the destructor.
|
||||
unsafe { core::ptr::read(Box::into_raw(b)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Box<'a, T> {
|
||||
@ -262,9 +280,8 @@ impl<'a, T: ?Sized> Box<'a, T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn into_raw(b: Box<'a, T>) -> *mut T {
|
||||
let ptr = b.0 as *mut T;
|
||||
mem::forget(b);
|
||||
ptr
|
||||
let mut b = ManuallyDrop::new(b);
|
||||
b.deref_mut().0 as *mut T
|
||||
}
|
||||
|
||||
/// Consumes and leaks the `Box`, returning a mutable reference,
|
||||
@ -644,9 +661,9 @@ impl<'a, F: ?Sized + Future + Unpin> Future for Box<'a, F> {
|
||||
|
||||
/// This impl replaces unsize coercion.
|
||||
impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
|
||||
fn from(mut arr: Box<'a, [T; N]>) -> Box<'a, [T]> {
|
||||
fn from(arr: Box<'a, [T; N]>) -> Box<'a, [T]> {
|
||||
let mut arr = ManuallyDrop::new(arr);
|
||||
let ptr = core::ptr::slice_from_raw_parts_mut(arr.as_mut_ptr(), N);
|
||||
mem::forget(arr);
|
||||
unsafe { Box::from_raw(ptr) }
|
||||
}
|
||||
}
|
||||
@ -654,10 +671,10 @@ impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
|
||||
/// This impl replaces unsize coercion.
|
||||
impl<'a, T, const N: usize> TryFrom<Box<'a, [T]>> for Box<'a, [T; N]> {
|
||||
type Error = Box<'a, [T]>;
|
||||
fn try_from(mut slice: Box<'a, [T]>) -> Result<Box<'a, [T; N]>, Box<'a, [T]>> {
|
||||
fn try_from(slice: Box<'a, [T]>) -> Result<Box<'a, [T; N]>, Box<'a, [T]>> {
|
||||
if slice.len() == N {
|
||||
let mut slice = ManuallyDrop::new(slice);
|
||||
let ptr = slice.as_mut_ptr() as *mut [T; N];
|
||||
mem::forget(slice);
|
||||
Ok(unsafe { Box::from_raw(ptr) })
|
||||
} else {
|
||||
Err(slice)
|
||||
|
@ -60,15 +60,10 @@ impl<'a, T> RawVec<'a, T> {
|
||||
/// Like `new` but parameterized over the choice of allocator for
|
||||
/// the returned RawVec.
|
||||
pub fn new_in(a: &'a Bump) -> Self {
|
||||
// !0 is usize::MAX. This branch should be stripped at compile time.
|
||||
// FIXME(mark-i-m): use this line when `if`s are allowed in `const`
|
||||
//let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
|
||||
|
||||
// Unique::empty() doubles as "unallocated" and "zero-sized allocation"
|
||||
// `cap: 0` means "unallocated". zero-sized types are ignored.
|
||||
RawVec {
|
||||
ptr: unsafe { NonNull::new_unchecked(mem::align_of::<T>() as *mut T) },
|
||||
// FIXME(mark-i-m): use `cap` when ifs are allowed in const
|
||||
cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
|
||||
ptr: NonNull::dangling(),
|
||||
cap: 0,
|
||||
a,
|
||||
}
|
||||
}
|
||||
|
34
zeroidc/vendor/bumpalo/src/collections/string.rs
vendored
34
zeroidc/vendor/bumpalo/src/collections/string.rs
vendored
@ -228,9 +228,9 @@ macro_rules! format {
|
||||
///
|
||||
/// let b = Bump::new();
|
||||
///
|
||||
/// let story = String::from_str_in("Once upon a time...", &b);
|
||||
/// let mut story = String::from_str_in("Once upon a time...", &b);
|
||||
///
|
||||
/// let ptr = story.as_ptr();
|
||||
/// let ptr = story.as_mut_ptr();
|
||||
/// let len = story.len();
|
||||
/// let capacity = story.capacity();
|
||||
///
|
||||
@ -243,7 +243,7 @@ macro_rules! format {
|
||||
/// // We can re-build a String out of ptr, len, and capacity. This is all
|
||||
/// // unsafe because we are responsible for making sure the components are
|
||||
/// // valid:
|
||||
/// let s = unsafe { String::from_raw_parts_in(ptr as *mut _, len, capacity, &b) } ;
|
||||
/// let s = unsafe { String::from_raw_parts_in(ptr, len, capacity, &b) } ;
|
||||
///
|
||||
/// assert_eq!(String::from_str_in("Once upon a time...", &b), s);
|
||||
/// ```
|
||||
@ -737,14 +737,14 @@ impl<'bump> String<'bump> {
|
||||
/// let b = Bump::new();
|
||||
///
|
||||
/// unsafe {
|
||||
/// let s = String::from_str_in("hello", &b);
|
||||
/// let ptr = s.as_ptr();
|
||||
/// let mut s = String::from_str_in("hello", &b);
|
||||
/// let ptr = s.as_mut_ptr();
|
||||
/// let len = s.len();
|
||||
/// let capacity = s.capacity();
|
||||
///
|
||||
/// mem::forget(s);
|
||||
///
|
||||
/// let s = String::from_raw_parts_in(ptr as *mut _, len, capacity, &b);
|
||||
/// let s = String::from_raw_parts_in(ptr, len, capacity, &b);
|
||||
///
|
||||
/// assert_eq!(s, "hello");
|
||||
/// }
|
||||
@ -798,6 +798,24 @@ impl<'bump> String<'bump> {
|
||||
String { vec: bytes }
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the allocator backing this `String`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bumpalo::{Bump, collections::String};
|
||||
///
|
||||
/// // uses the same allocator as the provided `String`
|
||||
/// fn copy_string<'bump>(s: &String<'bump>) -> &'bump str {
|
||||
/// s.bump().alloc_str(s.as_str())
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn bump(&self) -> &'bump Bump {
|
||||
self.vec.bump()
|
||||
}
|
||||
|
||||
/// Converts a `String` into a byte vector.
|
||||
///
|
||||
/// This consumes the `String`, so we do not need to copy its contents.
|
||||
@ -1550,7 +1568,7 @@ impl<'bump> String<'bump> {
|
||||
/// assert_eq!(s, "β is beta");
|
||||
///
|
||||
/// // A full range clears the string
|
||||
/// s.drain(..);
|
||||
/// drop(s.drain(..));
|
||||
/// assert_eq!(s, "");
|
||||
/// ```
|
||||
pub fn drain<'a, R>(&'a mut self, range: R) -> Drain<'a, 'bump>
|
||||
@ -2098,6 +2116,8 @@ impl<'a, 'bump> Drop for Drain<'a, 'bump> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement `AsRef<str/[u8]>` and `as_str`
|
||||
|
||||
impl<'a, 'bump> Iterator for Drain<'a, 'bump> {
|
||||
type Item = char;
|
||||
|
||||
|
156
zeroidc/vendor/bumpalo/src/collections/vec.rs
vendored
156
zeroidc/vendor/bumpalo/src/collections/vec.rs
vendored
@ -675,6 +675,26 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the allocator backing this `Vec`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bumpalo::{Bump, collections::Vec};
|
||||
///
|
||||
/// // uses the same allocator as the provided `Vec`
|
||||
/// fn add_strings<'bump>(vec: &mut Vec<'bump, &'bump str>) {
|
||||
/// for string in ["foo", "bar", "baz"] {
|
||||
/// vec.push(vec.bump().alloc_str(string));
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn bump(&self) -> &'bump Bump {
|
||||
self.buf.bump()
|
||||
}
|
||||
|
||||
/// Returns the number of elements the vector can hold without
|
||||
/// reallocating.
|
||||
///
|
||||
@ -977,6 +997,91 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
|
||||
/// valid for zero sized reads if the vector didn't allocate.
|
||||
///
|
||||
/// The caller must ensure that the vector outlives the pointer this
|
||||
/// function returns, or else it will end up pointing to garbage.
|
||||
/// Modifying the vector may cause its buffer to be reallocated,
|
||||
/// which would also make any pointers to it invalid.
|
||||
///
|
||||
/// The caller must also ensure that the memory the pointer (non-transitively) points to
|
||||
/// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
|
||||
/// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bumpalo::{Bump, collections::Vec};
|
||||
///
|
||||
/// let bump = Bump::new();
|
||||
///
|
||||
/// let x = bumpalo::vec![in ≎ 1, 2, 4];
|
||||
/// let x_ptr = x.as_ptr();
|
||||
///
|
||||
/// unsafe {
|
||||
/// for i in 0..x.len() {
|
||||
/// assert_eq!(*x_ptr.add(i), 1 << i);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`as_mut_ptr`]: Vec::as_mut_ptr
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
// We shadow the slice method of the same name to avoid going through
|
||||
// `deref`, which creates an intermediate reference.
|
||||
let ptr = self.buf.ptr();
|
||||
unsafe {
|
||||
if ptr.is_null() {
|
||||
core::hint::unreachable_unchecked();
|
||||
}
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
|
||||
/// raw pointer valid for zero sized reads if the vector didn't allocate.
|
||||
///
|
||||
/// The caller must ensure that the vector outlives the pointer this
|
||||
/// function returns, or else it will end up pointing to garbage.
|
||||
/// Modifying the vector may cause its buffer to be reallocated,
|
||||
/// which would also make any pointers to it invalid.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bumpalo::{Bump, collections::Vec};
|
||||
///
|
||||
/// let bump = Bump::new();
|
||||
///
|
||||
/// // Allocate vector big enough for 4 elements.
|
||||
/// let size = 4;
|
||||
/// let mut x: Vec<i32> = Vec::with_capacity_in(size, &bump);
|
||||
/// let x_ptr = x.as_mut_ptr();
|
||||
///
|
||||
/// // Initialize elements via raw pointer writes, then set length.
|
||||
/// unsafe {
|
||||
/// for i in 0..size {
|
||||
/// x_ptr.add(i).write(i as i32);
|
||||
/// }
|
||||
/// x.set_len(size);
|
||||
/// }
|
||||
/// assert_eq!(&*x, &[0, 1, 2, 3]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||
// We shadow the slice method of the same name to avoid going through
|
||||
// `deref_mut`, which creates an intermediate reference.
|
||||
let ptr = self.buf.ptr();
|
||||
unsafe {
|
||||
if ptr.is_null() {
|
||||
core::hint::unreachable_unchecked();
|
||||
}
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Sets the length of a vector.
|
||||
///
|
||||
/// This will explicitly set the size of the vector, without actually
|
||||
@ -1026,19 +1131,27 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||
/// ```
|
||||
///
|
||||
/// In this example, the vector gets expanded from zero to four items
|
||||
/// without any memory allocations occurring, resulting in vector
|
||||
/// values of unallocated memory:
|
||||
/// but we directly initialize uninitialized memory:
|
||||
///
|
||||
// TODO: rely upon `spare_capacity_mut`
|
||||
/// ```
|
||||
/// use bumpalo::{Bump, collections::Vec};
|
||||
///
|
||||
/// let len = 4;
|
||||
/// let b = Bump::new();
|
||||
///
|
||||
/// let mut vec: Vec<char> = Vec::new_in(&b);
|
||||
/// let mut vec: Vec<u8> = Vec::with_capacity_in(len, &b);
|
||||
///
|
||||
/// for i in 0..len {
|
||||
/// // SAFETY: we initialize memory via `pointer::write`
|
||||
/// unsafe { vec.as_mut_ptr().add(i).write(b'a') }
|
||||
/// }
|
||||
///
|
||||
/// unsafe {
|
||||
/// vec.set_len(4);
|
||||
/// vec.set_len(len);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(b"aaaa", &*vec);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub unsafe fn set_len(&mut self, new_len: usize) {
|
||||
@ -1343,7 +1456,7 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||
} else {
|
||||
unsafe {
|
||||
self.len -= 1;
|
||||
Some(ptr::read(self.get_unchecked(self.len())))
|
||||
Some(ptr::read(self.as_ptr().add(self.len())))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1381,7 +1494,7 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||
let count = (*other).len();
|
||||
self.reserve(count);
|
||||
let len = self.len();
|
||||
ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count);
|
||||
ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count);
|
||||
self.len += count;
|
||||
}
|
||||
|
||||
@ -1848,7 +1961,7 @@ impl<'bump, T: 'bump> ops::DerefMut for Vec<'bump, T> {
|
||||
|
||||
impl<'bump, T: 'bump> IntoIterator for Vec<'bump, T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
type IntoIter = IntoIter<'bump, T>;
|
||||
|
||||
/// Creates a consuming iterator, that is, one that moves each value out of
|
||||
/// the vector (from start to end). The vector cannot be used after calling
|
||||
@ -1868,7 +1981,7 @@ impl<'bump, T: 'bump> IntoIterator for Vec<'bump, T> {
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
fn into_iter(mut self) -> IntoIter<T> {
|
||||
fn into_iter(mut self) -> IntoIter<'bump, T> {
|
||||
unsafe {
|
||||
let begin = self.as_mut_ptr();
|
||||
// assume(!begin.is_null());
|
||||
@ -2129,19 +2242,19 @@ impl<'bump, T> Drop for Vec<'bump, T> {
|
||||
/// (provided by the [`IntoIterator`] trait).
|
||||
///
|
||||
/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
|
||||
pub struct IntoIter<T> {
|
||||
phantom: PhantomData<T>,
|
||||
pub struct IntoIter<'bump, T> {
|
||||
phantom: PhantomData<&'bump [T]>,
|
||||
ptr: *const T,
|
||||
end: *const T,
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
|
||||
impl<'bump, T: fmt::Debug> fmt::Debug for IntoIter<'bump, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'bump, T: 'bump> IntoIter<T> {
|
||||
impl<'bump, T: 'bump> IntoIter<'bump, T> {
|
||||
/// Returns the remaining items of this iterator as a slice.
|
||||
///
|
||||
/// # Examples
|
||||
@ -2183,10 +2296,10 @@ impl<'bump, T: 'bump> IntoIter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for IntoIter<T> {}
|
||||
unsafe impl<T: Sync> Sync for IntoIter<T> {}
|
||||
unsafe impl<'bump, T: Send> Send for IntoIter<'bump, T> {}
|
||||
unsafe impl<'bump, T: Sync> Sync for IntoIter<'bump, T> {}
|
||||
|
||||
impl<'bump, T: 'bump> Iterator for IntoIter<T> {
|
||||
impl<'bump, T: 'bump> Iterator for IntoIter<'bump, T> {
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
@ -2227,7 +2340,7 @@ impl<'bump, T: 'bump> Iterator for IntoIter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<T> {
|
||||
impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<'bump, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
@ -2248,9 +2361,16 @@ impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'bump, T: 'bump> ExactSizeIterator for IntoIter<T> {}
|
||||
impl<'bump, T: 'bump> ExactSizeIterator for IntoIter<'bump, T> {}
|
||||
|
||||
impl<'bump, T: 'bump> FusedIterator for IntoIter<T> {}
|
||||
impl<'bump, T: 'bump> FusedIterator for IntoIter<'bump, T> {}
|
||||
|
||||
impl<'bump, T> Drop for IntoIter<'bump, T> {
|
||||
fn drop(&mut self) {
|
||||
// drop all remaining elements
|
||||
self.for_each(drop);
|
||||
}
|
||||
}
|
||||
|
||||
/// A draining iterator for `Vec<'bump, T>`.
|
||||
///
|
||||
|
356
zeroidc/vendor/bumpalo/src/lib.rs
vendored
356
zeroidc/vendor/bumpalo/src/lib.rs
vendored
@ -252,10 +252,46 @@ impl<E: Display> Display for AllocOrInitError<E> {
|
||||
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
||||
/// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
|
||||
/// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// ### `Bump` Allocation Limits
|
||||
///
|
||||
/// `bumpalo` supports setting a limit on the maximum bytes of memory that can
|
||||
/// be allocated for use in a particular `Bump` arena. This limit can be set and removed with
|
||||
/// [`set_allocation_limit`][Bump::set_allocation_limit].
|
||||
/// The allocation limit is only enforced when allocating new backing chunks for
|
||||
/// a `Bump`. Updating the allocation limit will not affect existing allocations
|
||||
/// or any future allocations within the `Bump`'s current chunk.
|
||||
///
|
||||
/// #### Example
|
||||
///
|
||||
/// ```
|
||||
/// let bump = bumpalo::Bump::new();
|
||||
///
|
||||
/// assert_eq!(bump.allocation_limit(), None);
|
||||
/// bump.set_allocation_limit(Some(0));
|
||||
///
|
||||
/// assert!(bump.try_alloc(5).is_err());
|
||||
///
|
||||
/// bump.set_allocation_limit(Some(6));
|
||||
///
|
||||
/// assert_eq!(bump.allocation_limit(), Some(6));
|
||||
///
|
||||
/// bump.set_allocation_limit(None);
|
||||
///
|
||||
/// assert_eq!(bump.allocation_limit(), None);
|
||||
/// ```
|
||||
///
|
||||
/// #### Warning
|
||||
///
|
||||
/// Because of backwards compatibility, allocations that fail
|
||||
/// due to allocation limits will not present differently than
|
||||
/// errors due to resource exhaustion.
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Bump {
|
||||
// The current chunk we are bump allocating within.
|
||||
current_chunk_footer: Cell<NonNull<ChunkFooter>>,
|
||||
allocation_limit: Cell<Option<usize>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -276,6 +312,12 @@ struct ChunkFooter {
|
||||
|
||||
// Bump allocation finger that is always in the range `self.data..=self`.
|
||||
ptr: Cell<NonNull<u8>>,
|
||||
|
||||
// The bytes allocated in all chunks so far, the canonical empty chunk has
|
||||
// a size of 0 and for all other chunks, `allocated_bytes` will be
|
||||
// the allocated_bytes of the current chunk plus the allocated bytes
|
||||
// of the `prev` chunk.
|
||||
allocated_bytes: usize,
|
||||
}
|
||||
|
||||
/// A wrapper type for the canonical, statically allocated empty chunk.
|
||||
@ -305,6 +347,9 @@ static EMPTY_CHUNK: EmptyChunkFooter = EmptyChunkFooter(ChunkFooter {
|
||||
prev: Cell::new(unsafe {
|
||||
NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut ChunkFooter)
|
||||
}),
|
||||
|
||||
// Empty chunks count as 0 allocated bytes in an arena.
|
||||
allocated_bytes: 0,
|
||||
});
|
||||
|
||||
impl EmptyChunkFooter {
|
||||
@ -407,6 +452,15 @@ const FIRST_ALLOCATION_GOAL: usize = 1 << 9;
|
||||
// take the alignment into account.
|
||||
const DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER: usize = FIRST_ALLOCATION_GOAL - OVERHEAD;
|
||||
|
||||
/// The memory size and alignment details for a potential new chunk
|
||||
/// allocation.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct NewChunkMemoryDetails {
|
||||
new_size_without_footer: usize,
|
||||
align: usize,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
/// Wrapper around `Layout::from_size_align` that adds debug assertions.
|
||||
#[inline]
|
||||
unsafe fn layout_from_size_align(size: usize, align: usize) -> Layout {
|
||||
@ -422,6 +476,12 @@ fn allocation_size_overflow<T>() -> T {
|
||||
panic!("requested allocation size overflowed")
|
||||
}
|
||||
|
||||
// This can be migrated to directly use `usize::abs_diff` when the MSRV
|
||||
// reaches `1.60`
|
||||
fn abs_diff(a: usize, b: usize) -> usize {
|
||||
usize::max(a, b) - usize::min(a, b)
|
||||
}
|
||||
|
||||
impl Bump {
|
||||
/// Construct a new arena to bump allocate into.
|
||||
///
|
||||
@ -471,18 +531,138 @@ impl Bump {
|
||||
if capacity == 0 {
|
||||
return Ok(Bump {
|
||||
current_chunk_footer: Cell::new(EMPTY_CHUNK.get()),
|
||||
allocation_limit: Cell::new(None),
|
||||
});
|
||||
}
|
||||
|
||||
let chunk_footer = Self::new_chunk(
|
||||
None,
|
||||
unsafe { layout_from_size_align(capacity, 1) },
|
||||
EMPTY_CHUNK.get(),
|
||||
)
|
||||
.ok_or(AllocErr)?;
|
||||
let layout = unsafe { layout_from_size_align(capacity, 1) };
|
||||
|
||||
let chunk_footer = unsafe {
|
||||
Self::new_chunk(
|
||||
Bump::new_chunk_memory_details(None, layout).ok_or(AllocErr)?,
|
||||
layout,
|
||||
EMPTY_CHUNK.get(),
|
||||
)
|
||||
.ok_or(AllocErr)?
|
||||
};
|
||||
|
||||
Ok(Bump {
|
||||
current_chunk_footer: Cell::new(chunk_footer),
|
||||
allocation_limit: Cell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
/// The allocation limit for this arena in bytes.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// let bump = bumpalo::Bump::with_capacity(0);
|
||||
///
|
||||
/// assert_eq!(bump.allocation_limit(), None);
|
||||
///
|
||||
/// bump.set_allocation_limit(Some(6));
|
||||
///
|
||||
/// assert_eq!(bump.allocation_limit(), Some(6));
|
||||
///
|
||||
/// bump.set_allocation_limit(None);
|
||||
///
|
||||
/// assert_eq!(bump.allocation_limit(), None);
|
||||
/// ```
|
||||
pub fn allocation_limit(&self) -> Option<usize> {
|
||||
self.allocation_limit.get()
|
||||
}
|
||||
|
||||
/// Set the allocation limit in bytes for this arena.
|
||||
///
|
||||
/// The allocation limit is only enforced when allocating new backing chunks for
|
||||
/// a `Bump`. Updating the allocation limit will not affect existing allocations
|
||||
/// or any future allocations within the `Bump`'s current chunk.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// let bump = bumpalo::Bump::with_capacity(0);
|
||||
///
|
||||
/// bump.set_allocation_limit(Some(0));
|
||||
///
|
||||
/// assert!(bump.try_alloc(5).is_err());
|
||||
/// ```
|
||||
pub fn set_allocation_limit(&self, limit: Option<usize>) {
|
||||
self.allocation_limit.set(limit)
|
||||
}
|
||||
|
||||
/// How much headroom an arena has before it hits its allocation
|
||||
/// limit.
|
||||
fn allocation_limit_remaining(&self) -> Option<usize> {
|
||||
self.allocation_limit.get().and_then(|allocation_limit| {
|
||||
let allocated_bytes = self.allocated_bytes();
|
||||
if allocated_bytes > allocation_limit {
|
||||
None
|
||||
} else {
|
||||
Some(abs_diff(allocation_limit, allocated_bytes))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether a request to allocate a new chunk with a given size for a given
|
||||
/// requested layout will fit under the allocation limit set on a `Bump`.
|
||||
fn chunk_fits_under_limit(
|
||||
allocation_limit_remaining: Option<usize>,
|
||||
new_chunk_memory_details: NewChunkMemoryDetails,
|
||||
) -> bool {
|
||||
allocation_limit_remaining
|
||||
.map(|allocation_limit_left| {
|
||||
allocation_limit_left >= new_chunk_memory_details.new_size_without_footer
|
||||
})
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Determine the memory details including final size, alignment and
|
||||
/// final size without footer for a new chunk that would be allocated
|
||||
/// to fulfill an allocation request.
|
||||
fn new_chunk_memory_details(
|
||||
new_size_without_footer: Option<usize>,
|
||||
requested_layout: Layout,
|
||||
) -> Option<NewChunkMemoryDetails> {
|
||||
let mut new_size_without_footer =
|
||||
new_size_without_footer.unwrap_or(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
|
||||
|
||||
// We want to have CHUNK_ALIGN or better alignment
|
||||
let mut align = CHUNK_ALIGN;
|
||||
|
||||
// If we already know we need to fulfill some request,
|
||||
// make sure we allocate at least enough to satisfy it
|
||||
align = align.max(requested_layout.align());
|
||||
let requested_size =
|
||||
round_up_to(requested_layout.size(), align).unwrap_or_else(allocation_size_overflow);
|
||||
new_size_without_footer = new_size_without_footer.max(requested_size);
|
||||
|
||||
// We want our allocations to play nice with the memory allocator,
|
||||
// and waste as little memory as possible.
|
||||
// For small allocations, this means that the entire allocation
|
||||
// including the chunk footer and mallocs internal overhead is
|
||||
// as close to a power of two as we can go without going over.
|
||||
// For larger allocations, we only need to get close to a page
|
||||
// boundary without going over.
|
||||
if new_size_without_footer < PAGE_STRATEGY_CUTOFF {
|
||||
new_size_without_footer =
|
||||
(new_size_without_footer + OVERHEAD).next_power_of_two() - OVERHEAD;
|
||||
} else {
|
||||
new_size_without_footer =
|
||||
round_up_to(new_size_without_footer + OVERHEAD, 0x1000)? - OVERHEAD;
|
||||
}
|
||||
|
||||
debug_assert_eq!(align % CHUNK_ALIGN, 0);
|
||||
debug_assert_eq!(new_size_without_footer % CHUNK_ALIGN, 0);
|
||||
let size = new_size_without_footer
|
||||
.checked_add(FOOTER_SIZE)
|
||||
.unwrap_or_else(allocation_size_overflow);
|
||||
|
||||
Some(NewChunkMemoryDetails {
|
||||
new_size_without_footer,
|
||||
size,
|
||||
align,
|
||||
})
|
||||
}
|
||||
|
||||
@ -491,74 +671,50 @@ impl Bump {
|
||||
/// If given, `layouts` is a tuple of the current chunk size and the
|
||||
/// layout of the allocation request that triggered us to fall back to
|
||||
/// allocating a new chunk of memory.
|
||||
fn new_chunk(
|
||||
new_size_without_footer: Option<usize>,
|
||||
unsafe fn new_chunk(
|
||||
new_chunk_memory_details: NewChunkMemoryDetails,
|
||||
requested_layout: Layout,
|
||||
prev: NonNull<ChunkFooter>,
|
||||
) -> Option<NonNull<ChunkFooter>> {
|
||||
unsafe {
|
||||
let mut new_size_without_footer =
|
||||
new_size_without_footer.unwrap_or(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
|
||||
let NewChunkMemoryDetails {
|
||||
new_size_without_footer,
|
||||
align,
|
||||
size,
|
||||
} = new_chunk_memory_details;
|
||||
|
||||
// We want to have CHUNK_ALIGN or better alignment
|
||||
let mut align = CHUNK_ALIGN;
|
||||
let layout = layout_from_size_align(size, align);
|
||||
|
||||
// If we already know we need to fulfill some request,
|
||||
// make sure we allocate at least enough to satisfy it
|
||||
align = align.max(requested_layout.align());
|
||||
let requested_size = round_up_to(requested_layout.size(), align)
|
||||
.unwrap_or_else(allocation_size_overflow);
|
||||
new_size_without_footer = new_size_without_footer.max(requested_size);
|
||||
debug_assert!(size >= requested_layout.size());
|
||||
|
||||
// We want our allocations to play nice with the memory allocator,
|
||||
// and waste as little memory as possible.
|
||||
// For small allocations, this means that the entire allocation
|
||||
// including the chunk footer and mallocs internal overhead is
|
||||
// as close to a power of two as we can go without going over.
|
||||
// For larger allocations, we only need to get close to a page
|
||||
// boundary without going over.
|
||||
if new_size_without_footer < PAGE_STRATEGY_CUTOFF {
|
||||
new_size_without_footer =
|
||||
(new_size_without_footer + OVERHEAD).next_power_of_two() - OVERHEAD;
|
||||
} else {
|
||||
new_size_without_footer =
|
||||
round_up_to(new_size_without_footer + OVERHEAD, 0x1000)? - OVERHEAD;
|
||||
}
|
||||
let data = alloc(layout);
|
||||
let data = NonNull::new(data)?;
|
||||
|
||||
debug_assert_eq!(align % CHUNK_ALIGN, 0);
|
||||
debug_assert_eq!(new_size_without_footer % CHUNK_ALIGN, 0);
|
||||
let size = new_size_without_footer
|
||||
.checked_add(FOOTER_SIZE)
|
||||
.unwrap_or_else(allocation_size_overflow);
|
||||
let layout = layout_from_size_align(size, align);
|
||||
// The `ChunkFooter` is at the end of the chunk.
|
||||
let footer_ptr = data.as_ptr().add(new_size_without_footer);
|
||||
debug_assert_eq!((data.as_ptr() as usize) % align, 0);
|
||||
debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0);
|
||||
let footer_ptr = footer_ptr as *mut ChunkFooter;
|
||||
|
||||
debug_assert!(size >= requested_layout.size());
|
||||
// The bump pointer is initialized to the end of the range we will
|
||||
// bump out of.
|
||||
let ptr = Cell::new(NonNull::new_unchecked(footer_ptr as *mut u8));
|
||||
|
||||
let data = alloc(layout);
|
||||
let data = NonNull::new(data)?;
|
||||
// The `allocated_bytes` of a new chunk counts the total size
|
||||
// of the chunks, not how much of the chunks are used.
|
||||
let allocated_bytes = prev.as_ref().allocated_bytes + new_size_without_footer;
|
||||
|
||||
// The `ChunkFooter` is at the end of the chunk.
|
||||
let footer_ptr = data.as_ptr().add(new_size_without_footer);
|
||||
debug_assert_eq!((data.as_ptr() as usize) % align, 0);
|
||||
debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0);
|
||||
let footer_ptr = footer_ptr as *mut ChunkFooter;
|
||||
ptr::write(
|
||||
footer_ptr,
|
||||
ChunkFooter {
|
||||
data,
|
||||
layout,
|
||||
prev: Cell::new(prev),
|
||||
ptr,
|
||||
allocated_bytes,
|
||||
},
|
||||
);
|
||||
|
||||
// The bump pointer is initialized to the end of the range we will
|
||||
// bump out of.
|
||||
let ptr = Cell::new(NonNull::new_unchecked(footer_ptr as *mut u8));
|
||||
|
||||
ptr::write(
|
||||
footer_ptr,
|
||||
ChunkFooter {
|
||||
data,
|
||||
layout,
|
||||
prev: Cell::new(prev),
|
||||
ptr,
|
||||
},
|
||||
);
|
||||
|
||||
Some(NonNull::new_unchecked(footer_ptr))
|
||||
}
|
||||
Some(NonNull::new_unchecked(footer_ptr))
|
||||
}
|
||||
|
||||
/// Reset this bump allocator.
|
||||
@ -600,7 +756,7 @@ impl Bump {
|
||||
return;
|
||||
}
|
||||
|
||||
let cur_chunk = self.current_chunk_footer.get();
|
||||
let mut cur_chunk = self.current_chunk_footer.get();
|
||||
|
||||
// Deallocate all chunks except the current one
|
||||
let prev_chunk = cur_chunk.as_ref().prev.replace(EMPTY_CHUNK.get());
|
||||
@ -609,6 +765,9 @@ impl Bump {
|
||||
// Reset the bump finger to the end of the chunk.
|
||||
cur_chunk.as_ref().ptr.set(cur_chunk.cast());
|
||||
|
||||
// Reset the allocated size of the chunk.
|
||||
cur_chunk.as_mut().allocated_bytes = cur_chunk.as_ref().layout.size();
|
||||
|
||||
debug_assert!(
|
||||
self.current_chunk_footer
|
||||
.get()
|
||||
@ -820,7 +979,6 @@ impl Bump {
|
||||
let rewind_footer = self.current_chunk_footer.get();
|
||||
let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
|
||||
let mut inner_result_ptr = NonNull::from(self.alloc_with(f));
|
||||
let inner_result_address = inner_result_ptr.as_ptr() as usize;
|
||||
match unsafe { inner_result_ptr.as_mut() } {
|
||||
Ok(t) => Ok(unsafe {
|
||||
//SAFETY:
|
||||
@ -842,7 +1000,7 @@ impl Bump {
|
||||
// reclaim any alignment padding we might have added (which
|
||||
// `dealloc` cannot do) if we didn't allocate a new chunk for
|
||||
// this result.
|
||||
if self.is_last_allocation(NonNull::new_unchecked(inner_result_address as *mut _)) {
|
||||
if self.is_last_allocation(inner_result_ptr.cast()) {
|
||||
let current_footer_p = self.current_chunk_footer.get();
|
||||
let current_ptr = ¤t_footer_p.as_ref().ptr;
|
||||
if current_footer_p == rewind_footer {
|
||||
@ -930,7 +1088,6 @@ impl Bump {
|
||||
let rewind_footer = self.current_chunk_footer.get();
|
||||
let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
|
||||
let mut inner_result_ptr = NonNull::from(self.try_alloc_with(f)?);
|
||||
let inner_result_address = inner_result_ptr.as_ptr() as usize;
|
||||
match unsafe { inner_result_ptr.as_mut() } {
|
||||
Ok(t) => Ok(unsafe {
|
||||
//SAFETY:
|
||||
@ -952,7 +1109,7 @@ impl Bump {
|
||||
// reclaim any alignment padding we might have added (which
|
||||
// `dealloc` cannot do) if we didn't allocate a new chunk for
|
||||
// this result.
|
||||
if self.is_last_allocation(NonNull::new_unchecked(inner_result_address as *mut _)) {
|
||||
if self.is_last_allocation(inner_result_ptr.cast()) {
|
||||
let current_footer_p = self.current_chunk_footer.get();
|
||||
let current_ptr = ¤t_footer_p.as_ref().ptr;
|
||||
if current_footer_p == rewind_footer {
|
||||
@ -1316,6 +1473,7 @@ impl Bump {
|
||||
fn alloc_layout_slow(&self, layout: Layout) -> Option<NonNull<u8>> {
|
||||
unsafe {
|
||||
let size = layout.size();
|
||||
let allocation_limit_remaining = self.allocation_limit_remaining();
|
||||
|
||||
// Get a new chunk from the global allocator.
|
||||
let current_footer = self.current_chunk_footer.get();
|
||||
@ -1329,18 +1487,39 @@ impl Bump {
|
||||
let mut base_size = (current_layout.size() - FOOTER_SIZE)
|
||||
.checked_mul(2)?
|
||||
.max(min_new_chunk_size);
|
||||
let sizes = iter::from_fn(|| {
|
||||
if base_size >= min_new_chunk_size {
|
||||
let chunk_memory_details = iter::from_fn(|| {
|
||||
let bypass_min_chunk_size_for_small_limits = match self.allocation_limit() {
|
||||
Some(limit)
|
||||
if layout.size() < limit
|
||||
&& base_size >= layout.size()
|
||||
&& limit < DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER
|
||||
&& self.allocated_bytes() == 0 =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if base_size >= min_new_chunk_size || bypass_min_chunk_size_for_small_limits {
|
||||
let size = base_size;
|
||||
base_size = base_size / 2;
|
||||
Some(size)
|
||||
Bump::new_chunk_memory_details(Some(size), layout)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let new_footer = sizes
|
||||
.filter_map(|size| Bump::new_chunk(Some(size), layout, current_footer))
|
||||
let new_footer = chunk_memory_details
|
||||
.filter_map(|chunk_memory_details| {
|
||||
if Bump::chunk_fits_under_limit(
|
||||
allocation_limit_remaining,
|
||||
chunk_memory_details,
|
||||
) {
|
||||
Bump::new_chunk(chunk_memory_details, layout, current_footer)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()?;
|
||||
|
||||
debug_assert_eq!(
|
||||
@ -1499,6 +1678,10 @@ impl Bump {
|
||||
/// on it only counting the sum of the sizes of the things
|
||||
/// you've allocated in the arena.
|
||||
///
|
||||
/// The allocated bytes do not include the size of bumpalo's metadata,
|
||||
/// so the amount of memory requested from the Rust allocator is higher
|
||||
/// than the returned value.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
@ -1508,24 +1691,9 @@ impl Bump {
|
||||
/// assert!(bytes >= core::mem::size_of::<u32>() * 5);
|
||||
/// ```
|
||||
pub fn allocated_bytes(&self) -> usize {
|
||||
let mut footer = self.current_chunk_footer.get();
|
||||
let footer = self.current_chunk_footer.get();
|
||||
|
||||
let mut bytes = 0;
|
||||
|
||||
unsafe {
|
||||
while !footer.as_ref().is_empty() {
|
||||
let foot = footer.as_ref();
|
||||
|
||||
let ptr = foot.ptr.get().as_ptr() as usize;
|
||||
debug_assert!(ptr <= foot as *const _ as usize);
|
||||
|
||||
bytes += foot as *const _ as usize - ptr;
|
||||
|
||||
footer = foot.prev.get();
|
||||
}
|
||||
}
|
||||
|
||||
bytes
|
||||
unsafe { footer.as_ref().allocated_bytes }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1770,15 +1938,20 @@ unsafe impl<'a> Allocator for &'a Bump {
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Only tests which require private types, fields, or methods should be in
|
||||
// here. Anything that can just be tested via public API surface should be in
|
||||
// `bumpalo/tests/all/*`.
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Uses private type `ChunkFooter`.
|
||||
#[test]
|
||||
fn chunk_footer_is_five_words() {
|
||||
assert_eq!(mem::size_of::<ChunkFooter>(), mem::size_of::<usize>() * 5);
|
||||
assert_eq!(mem::size_of::<ChunkFooter>(), mem::size_of::<usize>() * 6);
|
||||
}
|
||||
|
||||
// Uses private `alloc` module.
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_realloc() {
|
||||
@ -1828,6 +2001,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Uses our private `alloc` module.
|
||||
#[test]
|
||||
fn invalid_read() {
|
||||
use alloc::Alloc;
|
||||
|
Loading…
Reference in New Issue
Block a user