mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02: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
10 changed files with 526 additions and 149 deletions
4
zeroidc/Cargo.lock
generated
4
zeroidc/Cargo.lock
generated
|
@ -57,9 +57,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.10.0"
|
version = "3.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
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
|
## 3.10.0
|
||||||
|
|
||||||
Released 2022-06-01.
|
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.
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.10.0"
|
version = "3.12.0"
|
||||||
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
|
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
|
||||||
exclude = [
|
exclude = [
|
||||||
"/.github/*",
|
"/.github/*",
|
||||||
|
@ -51,13 +51,13 @@ harness = false
|
||||||
required-features = ["collections"]
|
required-features = ["collections"]
|
||||||
|
|
||||||
[dev-dependencies.criterion]
|
[dev-dependencies.criterion]
|
||||||
version = "0.3.0"
|
version = "0.3.6"
|
||||||
|
|
||||||
[dev-dependencies.quickcheck]
|
[dev-dependencies.quickcheck]
|
||||||
version = "0.9.0"
|
version = "1.0.3"
|
||||||
|
|
||||||
[dev-dependencies.rand]
|
[dev-dependencies.rand]
|
||||||
version = "0.7"
|
version = "0.8.5"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
allocator_api = []
|
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 our `Box<CountDrops>`.
|
||||||
drop(c);
|
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);
|
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
|
### Thread support
|
||||||
|
|
||||||
The `Bump` is `!Sync`, which makes it hard to use in certain situations around threads ‒ for
|
The `Bump` is `!Sync`, which makes it hard to use in certain situations around
|
||||||
example in `rayon`.
|
threads ‒ for example in `rayon`.
|
||||||
|
|
||||||
The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a pool of `Bump`
|
The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a
|
||||||
allocators for use in such situations.
|
pool of `Bump` allocators for use in such situations.
|
||||||
|
|
||||||
### Nightly Rust `allocator_api` Support
|
### 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"] }
|
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
|
```rust,ignore
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
|
@ -207,8 +209,8 @@ v.push(2);
|
||||||
|
|
||||||
#### Minimum Supported Rust Version (MSRV)
|
#### 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.
|
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
|
We reserve the right to increment the MSRV on minor releases, however we will
|
||||||
to only do it deliberately and for good reasons.
|
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,
|
future::Future,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::FusedIterator,
|
iter::FusedIterator,
|
||||||
mem,
|
mem::ManuallyDrop,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
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>> {
|
pub fn pin_in(x: T, a: &'a Bump) -> Pin<Box<'a, T>> {
|
||||||
Box(a.alloc(x)).into()
|
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> {
|
impl<'a, T: ?Sized> Box<'a, T> {
|
||||||
|
@ -262,9 +280,8 @@ impl<'a, T: ?Sized> Box<'a, T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_raw(b: Box<'a, T>) -> *mut T {
|
pub fn into_raw(b: Box<'a, T>) -> *mut T {
|
||||||
let ptr = b.0 as *mut T;
|
let mut b = ManuallyDrop::new(b);
|
||||||
mem::forget(b);
|
b.deref_mut().0 as *mut T
|
||||||
ptr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes and leaks the `Box`, returning a mutable reference,
|
/// 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.
|
/// This impl replaces unsize coercion.
|
||||||
impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
|
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);
|
let ptr = core::ptr::slice_from_raw_parts_mut(arr.as_mut_ptr(), N);
|
||||||
mem::forget(arr);
|
|
||||||
unsafe { Box::from_raw(ptr) }
|
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.
|
/// This impl replaces unsize coercion.
|
||||||
impl<'a, T, const N: usize> TryFrom<Box<'a, [T]>> for Box<'a, [T; N]> {
|
impl<'a, T, const N: usize> TryFrom<Box<'a, [T]>> for Box<'a, [T; N]> {
|
||||||
type Error = Box<'a, [T]>;
|
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 {
|
if slice.len() == N {
|
||||||
|
let mut slice = ManuallyDrop::new(slice);
|
||||||
let ptr = slice.as_mut_ptr() as *mut [T; N];
|
let ptr = slice.as_mut_ptr() as *mut [T; N];
|
||||||
mem::forget(slice);
|
|
||||||
Ok(unsafe { Box::from_raw(ptr) })
|
Ok(unsafe { Box::from_raw(ptr) })
|
||||||
} else {
|
} else {
|
||||||
Err(slice)
|
Err(slice)
|
||||||
|
|
|
@ -60,15 +60,10 @@ impl<'a, T> RawVec<'a, T> {
|
||||||
/// Like `new` but parameterized over the choice of allocator for
|
/// Like `new` but parameterized over the choice of allocator for
|
||||||
/// the returned RawVec.
|
/// the returned RawVec.
|
||||||
pub fn new_in(a: &'a Bump) -> Self {
|
pub fn new_in(a: &'a Bump) -> Self {
|
||||||
// !0 is usize::MAX. This branch should be stripped at compile time.
|
// `cap: 0` means "unallocated". zero-sized types are ignored.
|
||||||
// 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"
|
|
||||||
RawVec {
|
RawVec {
|
||||||
ptr: unsafe { NonNull::new_unchecked(mem::align_of::<T>() as *mut T) },
|
ptr: NonNull::dangling(),
|
||||||
// FIXME(mark-i-m): use `cap` when ifs are allowed in const
|
cap: 0,
|
||||||
cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
|
|
||||||
a,
|
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 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 len = story.len();
|
||||||
/// let capacity = story.capacity();
|
/// 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
|
/// // 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
|
/// // unsafe because we are responsible for making sure the components are
|
||||||
/// // valid:
|
/// // 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);
|
/// assert_eq!(String::from_str_in("Once upon a time...", &b), s);
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -737,14 +737,14 @@ impl<'bump> String<'bump> {
|
||||||
/// let b = Bump::new();
|
/// let b = Bump::new();
|
||||||
///
|
///
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// let s = String::from_str_in("hello", &b);
|
/// let mut s = String::from_str_in("hello", &b);
|
||||||
/// let ptr = s.as_ptr();
|
/// let ptr = s.as_mut_ptr();
|
||||||
/// let len = s.len();
|
/// let len = s.len();
|
||||||
/// let capacity = s.capacity();
|
/// let capacity = s.capacity();
|
||||||
///
|
///
|
||||||
/// mem::forget(s);
|
/// 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");
|
/// assert_eq!(s, "hello");
|
||||||
/// }
|
/// }
|
||||||
|
@ -798,6 +798,24 @@ impl<'bump> String<'bump> {
|
||||||
String { vec: bytes }
|
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.
|
/// Converts a `String` into a byte vector.
|
||||||
///
|
///
|
||||||
/// This consumes the `String`, so we do not need to copy its contents.
|
/// 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");
|
/// assert_eq!(s, "β is beta");
|
||||||
///
|
///
|
||||||
/// // A full range clears the string
|
/// // A full range clears the string
|
||||||
/// s.drain(..);
|
/// drop(s.drain(..));
|
||||||
/// assert_eq!(s, "");
|
/// assert_eq!(s, "");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn drain<'a, R>(&'a mut self, range: R) -> Drain<'a, 'bump>
|
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> {
|
impl<'a, 'bump> Iterator for Drain<'a, 'bump> {
|
||||||
type Item = char;
|
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
|
/// Returns the number of elements the vector can hold without
|
||||||
/// reallocating.
|
/// reallocating.
|
||||||
///
|
///
|
||||||
|
@ -977,6 +997,91 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||||
self
|
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.
|
/// Sets the length of a vector.
|
||||||
///
|
///
|
||||||
/// This will explicitly set the size of the vector, without actually
|
/// 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
|
/// In this example, the vector gets expanded from zero to four items
|
||||||
/// without any memory allocations occurring, resulting in vector
|
/// but we directly initialize uninitialized memory:
|
||||||
/// values of unallocated memory:
|
|
||||||
///
|
///
|
||||||
|
// TODO: rely upon `spare_capacity_mut`
|
||||||
/// ```
|
/// ```
|
||||||
/// use bumpalo::{Bump, collections::Vec};
|
/// use bumpalo::{Bump, collections::Vec};
|
||||||
///
|
///
|
||||||
|
/// let len = 4;
|
||||||
/// let b = Bump::new();
|
/// 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 {
|
/// unsafe {
|
||||||
/// vec.set_len(4);
|
/// vec.set_len(len);
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(b"aaaa", &*vec);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn set_len(&mut self, new_len: usize) {
|
pub unsafe fn set_len(&mut self, new_len: usize) {
|
||||||
|
@ -1343,7 +1456,7 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.len -= 1;
|
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();
|
let count = (*other).len();
|
||||||
self.reserve(count);
|
self.reserve(count);
|
||||||
let len = self.len();
|
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;
|
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> {
|
impl<'bump, T: 'bump> IntoIterator for Vec<'bump, T> {
|
||||||
type Item = 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
|
/// 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
|
/// 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]
|
#[inline]
|
||||||
fn into_iter(mut self) -> IntoIter<T> {
|
fn into_iter(mut self) -> IntoIter<'bump, T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let begin = self.as_mut_ptr();
|
let begin = self.as_mut_ptr();
|
||||||
// assume(!begin.is_null());
|
// assume(!begin.is_null());
|
||||||
|
@ -2129,19 +2242,19 @@ impl<'bump, T> Drop for Vec<'bump, T> {
|
||||||
/// (provided by the [`IntoIterator`] trait).
|
/// (provided by the [`IntoIterator`] trait).
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
|
/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
|
||||||
pub struct IntoIter<T> {
|
pub struct IntoIter<'bump, T> {
|
||||||
phantom: PhantomData<T>,
|
phantom: PhantomData<&'bump [T]>,
|
||||||
ptr: *const T,
|
ptr: *const T,
|
||||||
end: *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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
|
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.
|
/// Returns the remaining items of this iterator as a slice.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -2183,10 +2296,10 @@ impl<'bump, T: 'bump> IntoIter<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Send> Send for IntoIter<T> {}
|
unsafe impl<'bump, T: Send> Send for IntoIter<'bump, T> {}
|
||||||
unsafe impl<T: Sync> Sync for IntoIter<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;
|
type Item = T;
|
||||||
|
|
||||||
#[inline]
|
#[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]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<T> {
|
fn next_back(&mut self) -> Option<T> {
|
||||||
unsafe {
|
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>`.
|
/// 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
|
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
|
||||||
/// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
|
/// [`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
|
/// [`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)]
|
#[derive(Debug)]
|
||||||
pub struct Bump {
|
pub struct Bump {
|
||||||
// The current chunk we are bump allocating within.
|
// The current chunk we are bump allocating within.
|
||||||
current_chunk_footer: Cell<NonNull<ChunkFooter>>,
|
current_chunk_footer: Cell<NonNull<ChunkFooter>>,
|
||||||
|
allocation_limit: Cell<Option<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -276,6 +312,12 @@ struct ChunkFooter {
|
||||||
|
|
||||||
// Bump allocation finger that is always in the range `self.data..=self`.
|
// Bump allocation finger that is always in the range `self.data..=self`.
|
||||||
ptr: Cell<NonNull<u8>>,
|
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.
|
/// A wrapper type for the canonical, statically allocated empty chunk.
|
||||||
|
@ -305,6 +347,9 @@ static EMPTY_CHUNK: EmptyChunkFooter = EmptyChunkFooter(ChunkFooter {
|
||||||
prev: Cell::new(unsafe {
|
prev: Cell::new(unsafe {
|
||||||
NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut ChunkFooter)
|
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 {
|
impl EmptyChunkFooter {
|
||||||
|
@ -407,6 +452,15 @@ const FIRST_ALLOCATION_GOAL: usize = 1 << 9;
|
||||||
// take the alignment into account.
|
// take the alignment into account.
|
||||||
const DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER: usize = FIRST_ALLOCATION_GOAL - OVERHEAD;
|
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.
|
/// Wrapper around `Layout::from_size_align` that adds debug assertions.
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn layout_from_size_align(size: usize, align: usize) -> Layout {
|
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")
|
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 {
|
impl Bump {
|
||||||
/// Construct a new arena to bump allocate into.
|
/// Construct a new arena to bump allocate into.
|
||||||
///
|
///
|
||||||
|
@ -471,18 +531,138 @@ impl Bump {
|
||||||
if capacity == 0 {
|
if capacity == 0 {
|
||||||
return Ok(Bump {
|
return Ok(Bump {
|
||||||
current_chunk_footer: Cell::new(EMPTY_CHUNK.get()),
|
current_chunk_footer: Cell::new(EMPTY_CHUNK.get()),
|
||||||
|
allocation_limit: Cell::new(None),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk_footer = Self::new_chunk(
|
let layout = unsafe { layout_from_size_align(capacity, 1) };
|
||||||
None,
|
|
||||||
unsafe { layout_from_size_align(capacity, 1) },
|
let chunk_footer = unsafe {
|
||||||
EMPTY_CHUNK.get(),
|
Self::new_chunk(
|
||||||
)
|
Bump::new_chunk_memory_details(None, layout).ok_or(AllocErr)?,
|
||||||
.ok_or(AllocErr)?;
|
layout,
|
||||||
|
EMPTY_CHUNK.get(),
|
||||||
|
)
|
||||||
|
.ok_or(AllocErr)?
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Bump {
|
Ok(Bump {
|
||||||
current_chunk_footer: Cell::new(chunk_footer),
|
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
|
/// 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
|
/// layout of the allocation request that triggered us to fall back to
|
||||||
/// allocating a new chunk of memory.
|
/// allocating a new chunk of memory.
|
||||||
fn new_chunk(
|
unsafe fn new_chunk(
|
||||||
new_size_without_footer: Option<usize>,
|
new_chunk_memory_details: NewChunkMemoryDetails,
|
||||||
requested_layout: Layout,
|
requested_layout: Layout,
|
||||||
prev: NonNull<ChunkFooter>,
|
prev: NonNull<ChunkFooter>,
|
||||||
) -> Option<NonNull<ChunkFooter>> {
|
) -> Option<NonNull<ChunkFooter>> {
|
||||||
unsafe {
|
let NewChunkMemoryDetails {
|
||||||
let mut new_size_without_footer =
|
new_size_without_footer,
|
||||||
new_size_without_footer.unwrap_or(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
|
align,
|
||||||
|
size,
|
||||||
|
} = new_chunk_memory_details;
|
||||||
|
|
||||||
// We want to have CHUNK_ALIGN or better alignment
|
let layout = layout_from_size_align(size, align);
|
||||||
let mut align = CHUNK_ALIGN;
|
|
||||||
|
|
||||||
// If we already know we need to fulfill some request,
|
debug_assert!(size >= requested_layout.size());
|
||||||
// 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,
|
let data = alloc(layout);
|
||||||
// and waste as little memory as possible.
|
let data = NonNull::new(data)?;
|
||||||
// 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);
|
// The `ChunkFooter` is at the end of the chunk.
|
||||||
debug_assert_eq!(new_size_without_footer % CHUNK_ALIGN, 0);
|
let footer_ptr = data.as_ptr().add(new_size_without_footer);
|
||||||
let size = new_size_without_footer
|
debug_assert_eq!((data.as_ptr() as usize) % align, 0);
|
||||||
.checked_add(FOOTER_SIZE)
|
debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0);
|
||||||
.unwrap_or_else(allocation_size_overflow);
|
let footer_ptr = footer_ptr as *mut ChunkFooter;
|
||||||
let layout = layout_from_size_align(size, align);
|
|
||||||
|
|
||||||
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);
|
// The `allocated_bytes` of a new chunk counts the total size
|
||||||
let data = NonNull::new(data)?;
|
// 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.
|
ptr::write(
|
||||||
let footer_ptr = data.as_ptr().add(new_size_without_footer);
|
footer_ptr,
|
||||||
debug_assert_eq!((data.as_ptr() as usize) % align, 0);
|
ChunkFooter {
|
||||||
debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0);
|
data,
|
||||||
let footer_ptr = footer_ptr as *mut ChunkFooter;
|
layout,
|
||||||
|
prev: Cell::new(prev),
|
||||||
|
ptr,
|
||||||
|
allocated_bytes,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// The bump pointer is initialized to the end of the range we will
|
Some(NonNull::new_unchecked(footer_ptr))
|
||||||
// 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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset this bump allocator.
|
/// Reset this bump allocator.
|
||||||
|
@ -600,7 +756,7 @@ impl Bump {
|
||||||
return;
|
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
|
// Deallocate all chunks except the current one
|
||||||
let prev_chunk = cur_chunk.as_ref().prev.replace(EMPTY_CHUNK.get());
|
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.
|
// Reset the bump finger to the end of the chunk.
|
||||||
cur_chunk.as_ref().ptr.set(cur_chunk.cast());
|
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!(
|
debug_assert!(
|
||||||
self.current_chunk_footer
|
self.current_chunk_footer
|
||||||
.get()
|
.get()
|
||||||
|
@ -820,7 +979,6 @@ impl Bump {
|
||||||
let rewind_footer = self.current_chunk_footer.get();
|
let rewind_footer = self.current_chunk_footer.get();
|
||||||
let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
|
let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
|
||||||
let mut inner_result_ptr = NonNull::from(self.alloc_with(f));
|
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() } {
|
match unsafe { inner_result_ptr.as_mut() } {
|
||||||
Ok(t) => Ok(unsafe {
|
Ok(t) => Ok(unsafe {
|
||||||
//SAFETY:
|
//SAFETY:
|
||||||
|
@ -842,7 +1000,7 @@ impl Bump {
|
||||||
// reclaim any alignment padding we might have added (which
|
// reclaim any alignment padding we might have added (which
|
||||||
// `dealloc` cannot do) if we didn't allocate a new chunk for
|
// `dealloc` cannot do) if we didn't allocate a new chunk for
|
||||||
// this result.
|
// 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_footer_p = self.current_chunk_footer.get();
|
||||||
let current_ptr = ¤t_footer_p.as_ref().ptr;
|
let current_ptr = ¤t_footer_p.as_ref().ptr;
|
||||||
if current_footer_p == rewind_footer {
|
if current_footer_p == rewind_footer {
|
||||||
|
@ -930,7 +1088,6 @@ impl Bump {
|
||||||
let rewind_footer = self.current_chunk_footer.get();
|
let rewind_footer = self.current_chunk_footer.get();
|
||||||
let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
|
let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
|
||||||
let mut inner_result_ptr = NonNull::from(self.try_alloc_with(f)?);
|
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() } {
|
match unsafe { inner_result_ptr.as_mut() } {
|
||||||
Ok(t) => Ok(unsafe {
|
Ok(t) => Ok(unsafe {
|
||||||
//SAFETY:
|
//SAFETY:
|
||||||
|
@ -952,7 +1109,7 @@ impl Bump {
|
||||||
// reclaim any alignment padding we might have added (which
|
// reclaim any alignment padding we might have added (which
|
||||||
// `dealloc` cannot do) if we didn't allocate a new chunk for
|
// `dealloc` cannot do) if we didn't allocate a new chunk for
|
||||||
// this result.
|
// 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_footer_p = self.current_chunk_footer.get();
|
||||||
let current_ptr = ¤t_footer_p.as_ref().ptr;
|
let current_ptr = ¤t_footer_p.as_ref().ptr;
|
||||||
if current_footer_p == rewind_footer {
|
if current_footer_p == rewind_footer {
|
||||||
|
@ -1316,6 +1473,7 @@ impl Bump {
|
||||||
fn alloc_layout_slow(&self, layout: Layout) -> Option<NonNull<u8>> {
|
fn alloc_layout_slow(&self, layout: Layout) -> Option<NonNull<u8>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let size = layout.size();
|
let size = layout.size();
|
||||||
|
let allocation_limit_remaining = self.allocation_limit_remaining();
|
||||||
|
|
||||||
// Get a new chunk from the global allocator.
|
// Get a new chunk from the global allocator.
|
||||||
let current_footer = self.current_chunk_footer.get();
|
let current_footer = self.current_chunk_footer.get();
|
||||||
|
@ -1329,18 +1487,39 @@ impl Bump {
|
||||||
let mut base_size = (current_layout.size() - FOOTER_SIZE)
|
let mut base_size = (current_layout.size() - FOOTER_SIZE)
|
||||||
.checked_mul(2)?
|
.checked_mul(2)?
|
||||||
.max(min_new_chunk_size);
|
.max(min_new_chunk_size);
|
||||||
let sizes = iter::from_fn(|| {
|
let chunk_memory_details = iter::from_fn(|| {
|
||||||
if base_size >= min_new_chunk_size {
|
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;
|
let size = base_size;
|
||||||
base_size = base_size / 2;
|
base_size = base_size / 2;
|
||||||
Some(size)
|
Bump::new_chunk_memory_details(Some(size), layout)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let new_footer = sizes
|
let new_footer = chunk_memory_details
|
||||||
.filter_map(|size| Bump::new_chunk(Some(size), layout, current_footer))
|
.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()?;
|
.next()?;
|
||||||
|
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
|
@ -1499,6 +1678,10 @@ impl Bump {
|
||||||
/// on it only counting the sum of the sizes of the things
|
/// on it only counting the sum of the sizes of the things
|
||||||
/// you've allocated in the arena.
|
/// 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
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1508,24 +1691,9 @@ impl Bump {
|
||||||
/// assert!(bytes >= core::mem::size_of::<u32>() * 5);
|
/// assert!(bytes >= core::mem::size_of::<u32>() * 5);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn allocated_bytes(&self) -> usize {
|
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 { footer.as_ref().allocated_bytes }
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// Uses private type `ChunkFooter`.
|
||||||
#[test]
|
#[test]
|
||||||
fn chunk_footer_is_five_words() {
|
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]
|
#[test]
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
fn test_realloc() {
|
fn test_realloc() {
|
||||||
|
@ -1828,6 +2001,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uses our private `alloc` module.
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_read() {
|
fn invalid_read() {
|
||||||
use alloc::Alloc;
|
use alloc::Alloc;
|
||||||
|
|
Loading…
Add table
Reference in a new issue