forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a subset of the Rust standard library `alloc` crate, version 1.62.0, licensed under "Apache-2.0 OR MIT", from: https://github.com/rust-lang/rust/tree/1.62.0/library/alloc/src The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers). For copyright details, please see: https://github.com/rust-lang/rust/blob/1.62.0/COPYRIGHT The next patch modifies these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced. Vendoring `alloc`, at least for the moment, allows us to have fallible allocations support (i.e. the `try_*` versions of methods which return a `Result` instead of panicking) early on. It also gives a bit more freedom to experiment with new interfaces and to iterate quickly. Eventually, the goal is to have everything the kernel needs in upstream `alloc` and drop it from the kernel tree. For a summary of work on `alloc` happening upstream, please see: Rust-for-Linux#408 Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com> Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Showing
13 changed files
with
9,037 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
//! Collection types. | ||
#![stable(feature = "rust1", since = "1.0.0")] | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
pub mod binary_heap; | ||
#[cfg(not(no_global_oom_handling))] | ||
mod btree; | ||
#[cfg(not(no_global_oom_handling))] | ||
pub mod linked_list; | ||
#[cfg(not(no_global_oom_handling))] | ||
pub mod vec_deque; | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
pub mod btree_map { | ||
//! An ordered map based on a B-Tree. | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
pub use super::btree::map::*; | ||
} | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
pub mod btree_set { | ||
//! An ordered set based on a B-Tree. | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
pub use super::btree::set::*; | ||
} | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[doc(no_inline)] | ||
pub use binary_heap::BinaryHeap; | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[doc(no_inline)] | ||
pub use btree_map::BTreeMap; | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[doc(no_inline)] | ||
pub use btree_set::BTreeSet; | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[doc(no_inline)] | ||
pub use linked_list::LinkedList; | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[doc(no_inline)] | ||
pub use vec_deque::VecDeque; | ||
|
||
use crate::alloc::{Layout, LayoutError}; | ||
use core::fmt::Display; | ||
|
||
/// The error type for `try_reserve` methods. | ||
#[derive(Clone, PartialEq, Eq, Debug)] | ||
#[stable(feature = "try_reserve", since = "1.57.0")] | ||
pub struct TryReserveError { | ||
kind: TryReserveErrorKind, | ||
} | ||
|
||
impl TryReserveError { | ||
/// Details about the allocation that caused the error | ||
#[inline] | ||
#[must_use] | ||
#[unstable( | ||
feature = "try_reserve_kind", | ||
reason = "Uncertain how much info should be exposed", | ||
issue = "48043" | ||
)] | ||
pub fn kind(&self) -> TryReserveErrorKind { | ||
self.kind.clone() | ||
} | ||
} | ||
|
||
/// Details of the allocation that caused a `TryReserveError` | ||
#[derive(Clone, PartialEq, Eq, Debug)] | ||
#[unstable( | ||
feature = "try_reserve_kind", | ||
reason = "Uncertain how much info should be exposed", | ||
issue = "48043" | ||
)] | ||
pub enum TryReserveErrorKind { | ||
/// Error due to the computed capacity exceeding the collection's maximum | ||
/// (usually `isize::MAX` bytes). | ||
CapacityOverflow, | ||
|
||
/// The memory allocator returned an error | ||
AllocError { | ||
/// The layout of allocation request that failed | ||
layout: Layout, | ||
|
||
#[doc(hidden)] | ||
#[unstable( | ||
feature = "container_error_extra", | ||
issue = "none", | ||
reason = "\ | ||
Enable exposing the allocator’s custom error value \ | ||
if an associated type is added in the future: \ | ||
https://github.com/rust-lang/wg-allocators/issues/23" | ||
)] | ||
non_exhaustive: (), | ||
}, | ||
} | ||
|
||
#[unstable( | ||
feature = "try_reserve_kind", | ||
reason = "Uncertain how much info should be exposed", | ||
issue = "48043" | ||
)] | ||
impl From<TryReserveErrorKind> for TryReserveError { | ||
#[inline] | ||
fn from(kind: TryReserveErrorKind) -> Self { | ||
Self { kind } | ||
} | ||
} | ||
|
||
#[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] | ||
impl From<LayoutError> for TryReserveErrorKind { | ||
/// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. | ||
#[inline] | ||
fn from(_: LayoutError) -> Self { | ||
TryReserveErrorKind::CapacityOverflow | ||
} | ||
} | ||
|
||
#[stable(feature = "try_reserve", since = "1.57.0")] | ||
impl Display for TryReserveError { | ||
fn fmt( | ||
&self, | ||
fmt: &mut core::fmt::Formatter<'_>, | ||
) -> core::result::Result<(), core::fmt::Error> { | ||
fmt.write_str("memory allocation failed")?; | ||
let reason = match self.kind { | ||
TryReserveErrorKind::CapacityOverflow => { | ||
" because the computed capacity exceeded the collection's maximum" | ||
} | ||
TryReserveErrorKind::AllocError { .. } => { | ||
" because the memory allocator returned a error" | ||
} | ||
}; | ||
fmt.write_str(reason) | ||
} | ||
} | ||
|
||
/// An intermediate trait for specialization of `Extend`. | ||
#[doc(hidden)] | ||
trait SpecExtend<I: IntoIterator> { | ||
/// Extends `self` with the contents of the given iterator. | ||
fn spec_extend(&mut self, iter: I); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
//! # The Rust core allocation and collections library | ||
//! | ||
//! This library provides smart pointers and collections for managing | ||
//! heap-allocated values. | ||
//! | ||
//! This library, like libcore, normally doesn’t need to be used directly | ||
//! since its contents are re-exported in the [`std` crate](../std/index.html). | ||
//! Crates that use the `#![no_std]` attribute however will typically | ||
//! not depend on `std`, so they’d use this crate instead. | ||
//! | ||
//! ## Boxed values | ||
//! | ||
//! The [`Box`] type is a smart pointer type. There can only be one owner of a | ||
//! [`Box`], and the owner can decide to mutate the contents, which live on the | ||
//! heap. | ||
//! | ||
//! This type can be sent among threads efficiently as the size of a `Box` value | ||
//! is the same as that of a pointer. Tree-like data structures are often built | ||
//! with boxes because each node often has only one owner, the parent. | ||
//! | ||
//! ## Reference counted pointers | ||
//! | ||
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended | ||
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and | ||
//! only allows access to `&T`, a shared reference. | ||
//! | ||
//! This type is useful when inherited mutability (such as using [`Box`]) is too | ||
//! constraining for an application, and is often paired with the [`Cell`] or | ||
//! [`RefCell`] types in order to allow mutation. | ||
//! | ||
//! ## Atomically reference counted pointers | ||
//! | ||
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It | ||
//! provides all the same functionality of [`Rc`], except it requires that the | ||
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself | ||
//! sendable while [`Rc<T>`][`Rc`] is not. | ||
//! | ||
//! This type allows for shared access to the contained data, and is often | ||
//! paired with synchronization primitives such as mutexes to allow mutation of | ||
//! shared resources. | ||
//! | ||
//! ## Collections | ||
//! | ||
//! Implementations of the most common general purpose data structures are | ||
//! defined in this library. They are re-exported through the | ||
//! [standard collections library](../std/collections/index.html). | ||
//! | ||
//! ## Heap interfaces | ||
//! | ||
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the | ||
//! default global allocator. It is not compatible with the libc allocator API. | ||
//! | ||
//! [`Arc`]: sync | ||
//! [`Box`]: boxed | ||
//! [`Cell`]: core::cell | ||
//! [`Rc`]: rc | ||
//! [`RefCell`]: core::cell | ||
// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be | ||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. | ||
// rustc itself never sets the feature, so this line has no affect there. | ||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] | ||
#![allow(unused_attributes)] | ||
#![stable(feature = "alloc", since = "1.36.0")] | ||
#![doc( | ||
html_playground_url = "https://play.rust-lang.org/", | ||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", | ||
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) | ||
)] | ||
#![doc(cfg_hide( | ||
not(test), | ||
not(any(test, bootstrap)), | ||
any(not(feature = "miri-test-libstd"), test, doctest), | ||
no_global_oom_handling, | ||
not(no_global_oom_handling), | ||
target_has_atomic = "ptr" | ||
))] | ||
#![no_std] | ||
#![needs_allocator] | ||
// | ||
// Lints: | ||
#![deny(unsafe_op_in_unsafe_fn)] | ||
#![warn(deprecated_in_future)] | ||
#![warn(missing_debug_implementations)] | ||
#![warn(missing_docs)] | ||
#![allow(explicit_outlives_requirements)] | ||
// | ||
// Library features: | ||
#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))] | ||
#![feature(alloc_layout_extra)] | ||
#![feature(allocator_api)] | ||
#![feature(array_chunks)] | ||
#![feature(array_methods)] | ||
#![feature(array_windows)] | ||
#![feature(assert_matches)] | ||
#![feature(async_iterator)] | ||
#![feature(coerce_unsized)] | ||
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] | ||
#![feature(const_box)] | ||
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] | ||
#![feature(const_cow_is_borrowed)] | ||
#![feature(const_convert)] | ||
#![feature(const_size_of_val)] | ||
#![feature(const_align_of_val)] | ||
#![feature(const_ptr_read)] | ||
#![feature(const_maybe_uninit_write)] | ||
#![feature(const_maybe_uninit_as_mut_ptr)] | ||
#![feature(const_refs_to_cell)] | ||
#![feature(core_c_str)] | ||
#![feature(core_intrinsics)] | ||
#![feature(core_ffi_c)] | ||
#![feature(const_eval_select)] | ||
#![feature(const_pin)] | ||
#![feature(cstr_from_bytes_until_nul)] | ||
#![feature(dispatch_from_dyn)] | ||
#![feature(exact_size_is_empty)] | ||
#![feature(extend_one)] | ||
#![feature(fmt_internals)] | ||
#![feature(fn_traits)] | ||
#![feature(hasher_prefixfree_extras)] | ||
#![feature(inplace_iteration)] | ||
#![feature(iter_advance_by)] | ||
#![feature(layout_for_ptr)] | ||
#![feature(maybe_uninit_slice)] | ||
#![cfg_attr(test, feature(new_uninit))] | ||
#![feature(nonnull_slice_from_raw_parts)] | ||
#![feature(pattern)] | ||
#![feature(ptr_internals)] | ||
#![feature(ptr_metadata)] | ||
#![feature(ptr_sub_ptr)] | ||
#![feature(receiver_trait)] | ||
#![feature(set_ptr_value)] | ||
#![feature(slice_group_by)] | ||
#![feature(slice_ptr_get)] | ||
#![feature(slice_ptr_len)] | ||
#![feature(slice_range)] | ||
#![feature(str_internals)] | ||
#![feature(strict_provenance)] | ||
#![feature(trusted_len)] | ||
#![feature(trusted_random_access)] | ||
#![feature(try_trait_v2)] | ||
#![feature(unchecked_math)] | ||
#![feature(unicode_internals)] | ||
#![feature(unsize)] | ||
// | ||
// Language features: | ||
#![feature(allocator_internals)] | ||
#![feature(allow_internal_unstable)] | ||
#![feature(associated_type_bounds)] | ||
#![feature(box_syntax)] | ||
#![feature(cfg_sanitize)] | ||
#![feature(const_deref)] | ||
#![feature(const_mut_refs)] | ||
#![feature(const_ptr_write)] | ||
#![feature(const_precise_live_drops)] | ||
#![feature(const_trait_impl)] | ||
#![feature(const_try)] | ||
#![feature(dropck_eyepatch)] | ||
#![feature(exclusive_range_pattern)] | ||
#![feature(fundamental)] | ||
#![cfg_attr(not(test), feature(generator_trait))] | ||
#![feature(hashmap_internals)] | ||
#![feature(lang_items)] | ||
#![feature(let_else)] | ||
#![feature(min_specialization)] | ||
#![feature(negative_impls)] | ||
#![feature(never_type)] | ||
#![feature(nll)] // Not necessary, but here to test the `nll` feature. | ||
#![feature(rustc_allow_const_fn_unstable)] | ||
#![feature(rustc_attrs)] | ||
#![feature(slice_internals)] | ||
#![feature(staged_api)] | ||
#![cfg_attr(test, feature(test))] | ||
#![feature(unboxed_closures)] | ||
#![feature(unsized_fn_params)] | ||
#![feature(c_unwind)] | ||
// | ||
// Rustdoc features: | ||
#![feature(doc_cfg)] | ||
#![feature(doc_cfg_hide)] | ||
// Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]` | ||
// blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad | ||
// that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs | ||
// from other crates, but since this can only appear for lang items, it doesn't seem worth fixing. | ||
#![feature(intra_doc_pointers)] | ||
|
||
// Allow testing this library | ||
#[cfg(test)] | ||
#[macro_use] | ||
extern crate std; | ||
#[cfg(test)] | ||
extern crate test; | ||
|
||
// Module with internal macros used by other modules (needs to be included before other modules). | ||
#[macro_use] | ||
mod macros; | ||
|
||
mod raw_vec; | ||
|
||
// Heaps provided for low-level allocation strategies | ||
|
||
pub mod alloc; | ||
|
||
// Primitive types using the heaps above | ||
|
||
// Need to conditionally define the mod from `boxed.rs` to avoid | ||
// duplicating the lang-items when building in test cfg; but also need | ||
// to allow code to have `use boxed::Box;` declarations. | ||
#[cfg(not(test))] | ||
pub mod boxed; | ||
#[cfg(test)] | ||
mod boxed { | ||
pub use std::boxed::Box; | ||
} | ||
pub mod borrow; | ||
pub mod collections; | ||
#[cfg(not(no_global_oom_handling))] | ||
pub mod ffi; | ||
pub mod fmt; | ||
pub mod rc; | ||
pub mod slice; | ||
pub mod str; | ||
pub mod string; | ||
#[cfg(target_has_atomic = "ptr")] | ||
pub mod sync; | ||
#[cfg(all(not(no_global_oom_handling), target_has_atomic = "ptr"))] | ||
pub mod task; | ||
#[cfg(test)] | ||
mod tests; | ||
pub mod vec; | ||
|
||
#[doc(hidden)] | ||
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] | ||
pub mod __export { | ||
pub use core::format_args; | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
use crate::alloc::{Allocator, Global}; | ||
use core::fmt; | ||
use core::iter::{FusedIterator, TrustedLen}; | ||
use core::mem; | ||
use core::ptr::{self, NonNull}; | ||
use core::slice::{self}; | ||
|
||
use super::Vec; | ||
|
||
/// A draining iterator for `Vec<T>`. | ||
/// | ||
/// This `struct` is created by [`Vec::drain`]. | ||
/// See its documentation for more. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// let mut v = vec![0, 1, 2]; | ||
/// let iter: std::vec::Drain<_> = v.drain(..); | ||
/// ``` | ||
#[stable(feature = "drain", since = "1.6.0")] | ||
pub struct Drain< | ||
'a, | ||
T: 'a, | ||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, | ||
> { | ||
/// Index of tail to preserve | ||
pub(super) tail_start: usize, | ||
/// Length of tail | ||
pub(super) tail_len: usize, | ||
/// Current remaining range to remove | ||
pub(super) iter: slice::Iter<'a, T>, | ||
pub(super) vec: NonNull<Vec<T, A>>, | ||
} | ||
|
||
#[stable(feature = "collection_debug", since = "1.17.0")] | ||
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() | ||
} | ||
} | ||
|
||
impl<'a, T, A: Allocator> Drain<'a, T, A> { | ||
/// Returns the remaining items of this iterator as a slice. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// let mut vec = vec!['a', 'b', 'c']; | ||
/// let mut drain = vec.drain(..); | ||
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); | ||
/// let _ = drain.next().unwrap(); | ||
/// assert_eq!(drain.as_slice(), &['b', 'c']); | ||
/// ``` | ||
#[must_use] | ||
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")] | ||
pub fn as_slice(&self) -> &[T] { | ||
self.iter.as_slice() | ||
} | ||
|
||
/// Returns a reference to the underlying allocator. | ||
#[unstable(feature = "allocator_api", issue = "32838")] | ||
#[must_use] | ||
#[inline] | ||
pub fn allocator(&self) -> &A { | ||
unsafe { self.vec.as_ref().allocator() } | ||
} | ||
} | ||
|
||
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")] | ||
impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { | ||
fn as_ref(&self) -> &[T] { | ||
self.as_slice() | ||
} | ||
} | ||
|
||
#[stable(feature = "drain", since = "1.6.0")] | ||
unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {} | ||
#[stable(feature = "drain", since = "1.6.0")] | ||
unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {} | ||
|
||
#[stable(feature = "drain", since = "1.6.0")] | ||
impl<T, A: Allocator> Iterator for Drain<'_, T, A> { | ||
type Item = T; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<T> { | ||
self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) }) | ||
} | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
self.iter.size_hint() | ||
} | ||
} | ||
|
||
#[stable(feature = "drain", since = "1.6.0")] | ||
impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> { | ||
#[inline] | ||
fn next_back(&mut self) -> Option<T> { | ||
self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) | ||
} | ||
} | ||
|
||
#[stable(feature = "drain", since = "1.6.0")] | ||
impl<T, A: Allocator> Drop for Drain<'_, T, A> { | ||
fn drop(&mut self) { | ||
/// Moves back the un-`Drain`ed elements to restore the original `Vec`. | ||
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); | ||
|
||
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { | ||
fn drop(&mut self) { | ||
if self.0.tail_len > 0 { | ||
unsafe { | ||
let source_vec = self.0.vec.as_mut(); | ||
// memmove back untouched tail, update to new length | ||
let start = source_vec.len(); | ||
let tail = self.0.tail_start; | ||
if tail != start { | ||
let src = source_vec.as_ptr().add(tail); | ||
let dst = source_vec.as_mut_ptr().add(start); | ||
ptr::copy(src, dst, self.0.tail_len); | ||
} | ||
source_vec.set_len(start + self.0.tail_len); | ||
} | ||
} | ||
} | ||
} | ||
|
||
let iter = mem::replace(&mut self.iter, (&mut []).iter()); | ||
let drop_len = iter.len(); | ||
|
||
let mut vec = self.vec; | ||
|
||
if mem::size_of::<T>() == 0 { | ||
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. | ||
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`. | ||
unsafe { | ||
let vec = vec.as_mut(); | ||
let old_len = vec.len(); | ||
vec.set_len(old_len + drop_len + self.tail_len); | ||
vec.truncate(old_len + self.tail_len); | ||
} | ||
|
||
return; | ||
} | ||
|
||
// ensure elements are moved back into their appropriate places, even when drop_in_place panics | ||
let _guard = DropGuard(self); | ||
|
||
if drop_len == 0 { | ||
return; | ||
} | ||
|
||
// as_slice() must only be called when iter.len() is > 0 because | ||
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate | ||
// the iterator's internal pointers. Creating a reference to deallocated memory | ||
// is invalid even when it is zero-length | ||
let drop_ptr = iter.as_slice().as_ptr(); | ||
|
||
unsafe { | ||
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place | ||
// a pointer with mutable provenance is necessary. Therefore we must reconstruct | ||
// it from the original vec but also avoid creating a &mut to the front since that could | ||
// invalidate raw pointers to it which some unsafe code might rely on. | ||
let vec_ptr = vec.as_mut().as_mut_ptr(); | ||
let drop_offset = drop_ptr.sub_ptr(vec_ptr); | ||
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); | ||
ptr::drop_in_place(to_drop); | ||
} | ||
} | ||
} | ||
|
||
#[stable(feature = "drain", since = "1.6.0")] | ||
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> { | ||
fn is_empty(&self) -> bool { | ||
self.iter.is_empty() | ||
} | ||
} | ||
|
||
#[unstable(feature = "trusted_len", issue = "37572")] | ||
unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {} | ||
|
||
#[stable(feature = "fused", since = "1.26.0")] | ||
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
use crate::alloc::{Allocator, Global}; | ||
use core::ptr::{self}; | ||
use core::slice::{self}; | ||
|
||
use super::Vec; | ||
|
||
/// An iterator which uses a closure to determine if an element should be removed. | ||
/// | ||
/// This struct is created by [`Vec::drain_filter`]. | ||
/// See its documentation for more. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// #![feature(drain_filter)] | ||
/// | ||
/// let mut v = vec![0, 1, 2]; | ||
/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0); | ||
/// ``` | ||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] | ||
#[derive(Debug)] | ||
pub struct DrainFilter< | ||
'a, | ||
T, | ||
F, | ||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, | ||
> where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
pub(super) vec: &'a mut Vec<T, A>, | ||
/// The index of the item that will be inspected by the next call to `next`. | ||
pub(super) idx: usize, | ||
/// The number of items that have been drained (removed) thus far. | ||
pub(super) del: usize, | ||
/// The original length of `vec` prior to draining. | ||
pub(super) old_len: usize, | ||
/// The filter test predicate. | ||
pub(super) pred: F, | ||
/// A flag that indicates a panic has occurred in the filter test predicate. | ||
/// This is used as a hint in the drop implementation to prevent consumption | ||
/// of the remainder of the `DrainFilter`. Any unprocessed items will be | ||
/// backshifted in the `vec`, but no further items will be dropped or | ||
/// tested by the filter predicate. | ||
pub(super) panic_flag: bool, | ||
} | ||
|
||
impl<T, F, A: Allocator> DrainFilter<'_, T, F, A> | ||
where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
/// Returns a reference to the underlying allocator. | ||
#[unstable(feature = "allocator_api", issue = "32838")] | ||
#[inline] | ||
pub fn allocator(&self) -> &A { | ||
self.vec.allocator() | ||
} | ||
} | ||
|
||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] | ||
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A> | ||
where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
type Item = T; | ||
|
||
fn next(&mut self) -> Option<T> { | ||
unsafe { | ||
while self.idx < self.old_len { | ||
let i = self.idx; | ||
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); | ||
self.panic_flag = true; | ||
let drained = (self.pred)(&mut v[i]); | ||
self.panic_flag = false; | ||
// Update the index *after* the predicate is called. If the index | ||
// is updated prior and the predicate panics, the element at this | ||
// index would be leaked. | ||
self.idx += 1; | ||
if drained { | ||
self.del += 1; | ||
return Some(ptr::read(&v[i])); | ||
} else if self.del > 0 { | ||
let del = self.del; | ||
let src: *const T = &v[i]; | ||
let dst: *mut T = &mut v[i - del]; | ||
ptr::copy_nonoverlapping(src, dst, 1); | ||
} | ||
} | ||
None | ||
} | ||
} | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
(0, Some(self.old_len - self.idx)) | ||
} | ||
} | ||
|
||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] | ||
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A> | ||
where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
fn drop(&mut self) { | ||
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> | ||
where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
drain: &'b mut DrainFilter<'a, T, F, A>, | ||
} | ||
|
||
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> | ||
where | ||
F: FnMut(&mut T) -> bool, | ||
{ | ||
fn drop(&mut self) { | ||
unsafe { | ||
if self.drain.idx < self.drain.old_len && self.drain.del > 0 { | ||
// This is a pretty messed up state, and there isn't really an | ||
// obviously right thing to do. We don't want to keep trying | ||
// to execute `pred`, so we just backshift all the unprocessed | ||
// elements and tell the vec that they still exist. The backshift | ||
// is required to prevent a double-drop of the last successfully | ||
// drained item prior to a panic in the predicate. | ||
let ptr = self.drain.vec.as_mut_ptr(); | ||
let src = ptr.add(self.drain.idx); | ||
let dst = src.sub(self.drain.del); | ||
let tail_len = self.drain.old_len - self.drain.idx; | ||
src.copy_to(dst, tail_len); | ||
} | ||
self.drain.vec.set_len(self.drain.old_len - self.drain.del); | ||
} | ||
} | ||
} | ||
|
||
let backshift = BackshiftOnDrop { drain: self }; | ||
|
||
// Attempt to consume any remaining elements if the filter predicate | ||
// has not yet panicked. We'll backshift any remaining elements | ||
// whether we've already panicked or if the consumption here panics. | ||
if !backshift.drain.panic_flag { | ||
backshift.drain.for_each(drop); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,362 @@ | ||
#[cfg(not(no_global_oom_handling))] | ||
use super::AsVecIntoIter; | ||
use crate::alloc::{Allocator, Global}; | ||
use crate::raw_vec::RawVec; | ||
use core::fmt; | ||
use core::intrinsics::arith_offset; | ||
use core::iter::{ | ||
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, | ||
}; | ||
use core::marker::PhantomData; | ||
use core::mem::{self, ManuallyDrop}; | ||
use core::ops::Deref; | ||
use core::ptr::{self, NonNull}; | ||
use core::slice::{self}; | ||
|
||
/// An iterator that moves out of a vector. | ||
/// | ||
/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec) | ||
/// (provided by the [`IntoIterator`] trait). | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// let v = vec![0, 1, 2]; | ||
/// let iter: std::vec::IntoIter<_> = v.into_iter(); | ||
/// ``` | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
#[rustc_insignificant_dtor] | ||
pub struct IntoIter< | ||
T, | ||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, | ||
> { | ||
pub(super) buf: NonNull<T>, | ||
pub(super) phantom: PhantomData<T>, | ||
pub(super) cap: usize, | ||
// the drop impl reconstructs a RawVec from buf, cap and alloc | ||
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop | ||
pub(super) alloc: ManuallyDrop<A>, | ||
pub(super) ptr: *const T, | ||
pub(super) end: *const T, | ||
} | ||
|
||
#[stable(feature = "vec_intoiter_debug", since = "1.13.0")] | ||
impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_tuple("IntoIter").field(&self.as_slice()).finish() | ||
} | ||
} | ||
|
||
impl<T, A: Allocator> IntoIter<T, A> { | ||
/// Returns the remaining items of this iterator as a slice. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// let vec = vec!['a', 'b', 'c']; | ||
/// let mut into_iter = vec.into_iter(); | ||
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); | ||
/// let _ = into_iter.next().unwrap(); | ||
/// assert_eq!(into_iter.as_slice(), &['b', 'c']); | ||
/// ``` | ||
#[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] | ||
pub fn as_slice(&self) -> &[T] { | ||
unsafe { slice::from_raw_parts(self.ptr, self.len()) } | ||
} | ||
|
||
/// Returns the remaining items of this iterator as a mutable slice. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// let vec = vec!['a', 'b', 'c']; | ||
/// let mut into_iter = vec.into_iter(); | ||
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); | ||
/// into_iter.as_mut_slice()[2] = 'z'; | ||
/// assert_eq!(into_iter.next().unwrap(), 'a'); | ||
/// assert_eq!(into_iter.next().unwrap(), 'b'); | ||
/// assert_eq!(into_iter.next().unwrap(), 'z'); | ||
/// ``` | ||
#[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] | ||
pub fn as_mut_slice(&mut self) -> &mut [T] { | ||
unsafe { &mut *self.as_raw_mut_slice() } | ||
} | ||
|
||
/// Returns a reference to the underlying allocator. | ||
#[unstable(feature = "allocator_api", issue = "32838")] | ||
#[inline] | ||
pub fn allocator(&self) -> &A { | ||
&self.alloc | ||
} | ||
|
||
fn as_raw_mut_slice(&mut self) -> *mut [T] { | ||
ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) | ||
} | ||
|
||
/// Drops remaining elements and relinquishes the backing allocation. | ||
/// | ||
/// This is roughly equivalent to the following, but more efficient | ||
/// | ||
/// ``` | ||
/// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter(); | ||
/// (&mut into_iter).for_each(core::mem::drop); | ||
/// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); } | ||
/// ``` | ||
/// | ||
/// This method is used by in-place iteration, refer to the vec::in_place_collect | ||
/// documentation for an overview. | ||
#[cfg(not(no_global_oom_handling))] | ||
pub(super) fn forget_allocation_drop_remaining(&mut self) { | ||
let remaining = self.as_raw_mut_slice(); | ||
|
||
// overwrite the individual fields instead of creating a new | ||
// struct and then overwriting &mut self. | ||
// this creates less assembly | ||
self.cap = 0; | ||
self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; | ||
self.ptr = self.buf.as_ptr(); | ||
self.end = self.buf.as_ptr(); | ||
|
||
unsafe { | ||
ptr::drop_in_place(remaining); | ||
} | ||
} | ||
|
||
/// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed. | ||
pub(crate) fn forget_remaining_elements(&mut self) { | ||
self.ptr = self.end; | ||
} | ||
} | ||
|
||
#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] | ||
impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> { | ||
fn as_ref(&self) -> &[T] { | ||
self.as_slice() | ||
} | ||
} | ||
|
||
#[stable(feature = "rust1", since = "1.0.0")] | ||
unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {} | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {} | ||
|
||
#[stable(feature = "rust1", since = "1.0.0")] | ||
impl<T, A: Allocator> Iterator for IntoIter<T, A> { | ||
type Item = T; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<T> { | ||
if self.ptr as *const _ == self.end { | ||
None | ||
} else if mem::size_of::<T>() == 0 { | ||
// purposefully don't use 'ptr.offset' because for | ||
// vectors with 0-size elements this would return the | ||
// same pointer. | ||
self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; | ||
|
||
// Make up a value of this ZST. | ||
Some(unsafe { mem::zeroed() }) | ||
} else { | ||
let old = self.ptr; | ||
self.ptr = unsafe { self.ptr.offset(1) }; | ||
|
||
Some(unsafe { ptr::read(old) }) | ||
} | ||
} | ||
|
||
#[inline] | ||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let exact = if mem::size_of::<T>() == 0 { | ||
self.end.addr().wrapping_sub(self.ptr.addr()) | ||
} else { | ||
unsafe { self.end.sub_ptr(self.ptr) } | ||
}; | ||
(exact, Some(exact)) | ||
} | ||
|
||
#[inline] | ||
fn advance_by(&mut self, n: usize) -> Result<(), usize> { | ||
let step_size = self.len().min(n); | ||
let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); | ||
if mem::size_of::<T>() == 0 { | ||
// SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound | ||
// effectively results in unsigned pointers representing positions 0..usize::MAX, | ||
// which is valid for ZSTs. | ||
self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T } | ||
} else { | ||
// SAFETY: the min() above ensures that step_size is in bounds | ||
self.ptr = unsafe { self.ptr.add(step_size) }; | ||
} | ||
// SAFETY: the min() above ensures that step_size is in bounds | ||
unsafe { | ||
ptr::drop_in_place(to_drop); | ||
} | ||
if step_size < n { | ||
return Err(step_size); | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[inline] | ||
fn count(self) -> usize { | ||
self.len() | ||
} | ||
|
||
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item | ||
where | ||
Self: TrustedRandomAccessNoCoerce, | ||
{ | ||
// SAFETY: the caller must guarantee that `i` is in bounds of the | ||
// `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` | ||
// is guaranteed to pointer to an element of the `Vec<T>` and | ||
// thus guaranteed to be valid to dereference. | ||
// | ||
// Also note the implementation of `Self: TrustedRandomAccess` requires | ||
// that `T: Copy` so reading elements from the buffer doesn't invalidate | ||
// them for `Drop`. | ||
unsafe { | ||
if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } | ||
} | ||
} | ||
} | ||
|
||
#[stable(feature = "rust1", since = "1.0.0")] | ||
impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { | ||
#[inline] | ||
fn next_back(&mut self) -> Option<T> { | ||
if self.end == self.ptr { | ||
None | ||
} else if mem::size_of::<T>() == 0 { | ||
// See above for why 'ptr.offset' isn't used | ||
self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; | ||
|
||
// Make up a value of this ZST. | ||
Some(unsafe { mem::zeroed() }) | ||
} else { | ||
self.end = unsafe { self.end.offset(-1) }; | ||
|
||
Some(unsafe { ptr::read(self.end) }) | ||
} | ||
} | ||
|
||
#[inline] | ||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { | ||
let step_size = self.len().min(n); | ||
if mem::size_of::<T>() == 0 { | ||
// SAFETY: same as for advance_by() | ||
self.end = unsafe { | ||
arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T | ||
} | ||
} else { | ||
// SAFETY: same as for advance_by() | ||
self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) }; | ||
} | ||
let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); | ||
// SAFETY: same as for advance_by() | ||
unsafe { | ||
ptr::drop_in_place(to_drop); | ||
} | ||
if step_size < n { | ||
return Err(step_size); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[stable(feature = "rust1", since = "1.0.0")] | ||
impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> { | ||
fn is_empty(&self) -> bool { | ||
self.ptr == self.end | ||
} | ||
} | ||
|
||
#[stable(feature = "fused", since = "1.26.0")] | ||
impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} | ||
|
||
#[unstable(feature = "trusted_len", issue = "37572")] | ||
unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {} | ||
|
||
#[doc(hidden)] | ||
#[unstable(issue = "none", feature = "std_internals")] | ||
#[rustc_unsafe_specialization_marker] | ||
pub trait NonDrop {} | ||
|
||
// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr | ||
// and thus we can't implement drop-handling | ||
#[unstable(issue = "none", feature = "std_internals")] | ||
impl<T: Copy> NonDrop for T {} | ||
|
||
#[doc(hidden)] | ||
#[unstable(issue = "none", feature = "std_internals")] | ||
// TrustedRandomAccess (without NoCoerce) must not be implemented because | ||
// subtypes/supertypes of `T` might not be `NonDrop` | ||
unsafe impl<T, A: Allocator> TrustedRandomAccessNoCoerce for IntoIter<T, A> | ||
where | ||
T: NonDrop, | ||
{ | ||
const MAY_HAVE_SIDE_EFFECT: bool = false; | ||
} | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")] | ||
impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> { | ||
#[cfg(not(test))] | ||
fn clone(&self) -> Self { | ||
self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter() | ||
} | ||
#[cfg(test)] | ||
fn clone(&self) -> Self { | ||
crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter() | ||
} | ||
} | ||
|
||
#[stable(feature = "rust1", since = "1.0.0")] | ||
unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> { | ||
fn drop(&mut self) { | ||
struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>); | ||
|
||
impl<T, A: Allocator> Drop for DropGuard<'_, T, A> { | ||
fn drop(&mut self) { | ||
unsafe { | ||
// `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec | ||
let alloc = ManuallyDrop::take(&mut self.0.alloc); | ||
// RawVec handles deallocation | ||
let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); | ||
} | ||
} | ||
} | ||
|
||
let guard = DropGuard(self); | ||
// destroy the remaining elements | ||
unsafe { | ||
ptr::drop_in_place(guard.0.as_raw_mut_slice()); | ||
} | ||
// now `guard` will be dropped and do the rest | ||
} | ||
} | ||
|
||
// In addition to the SAFETY invariants of the following three unsafe traits | ||
// also refer to the vec::in_place_collect module documentation to get an overview | ||
#[unstable(issue = "none", feature = "inplace_iteration")] | ||
#[doc(hidden)] | ||
unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {} | ||
|
||
#[unstable(issue = "none", feature = "inplace_iteration")] | ||
#[doc(hidden)] | ||
unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> { | ||
type Source = Self; | ||
|
||
#[inline] | ||
unsafe fn as_inner(&mut self) -> &mut Self::Source { | ||
self | ||
} | ||
} | ||
|
||
#[cfg(not(no_global_oom_handling))] | ||
unsafe impl<T> AsVecIntoIter for IntoIter<T> { | ||
type Item = T; | ||
|
||
fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> { | ||
self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
use crate::boxed::Box; | ||
|
||
#[rustc_specialization_trait] | ||
pub(super) unsafe trait IsZero { | ||
/// Whether this value's representation is all zeros | ||
fn is_zero(&self) -> bool; | ||
} | ||
|
||
macro_rules! impl_is_zero { | ||
($t:ty, $is_zero:expr) => { | ||
unsafe impl IsZero for $t { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
$is_zero(*self) | ||
} | ||
} | ||
}; | ||
} | ||
|
||
impl_is_zero!(i16, |x| x == 0); | ||
impl_is_zero!(i32, |x| x == 0); | ||
impl_is_zero!(i64, |x| x == 0); | ||
impl_is_zero!(i128, |x| x == 0); | ||
impl_is_zero!(isize, |x| x == 0); | ||
|
||
impl_is_zero!(u16, |x| x == 0); | ||
impl_is_zero!(u32, |x| x == 0); | ||
impl_is_zero!(u64, |x| x == 0); | ||
impl_is_zero!(u128, |x| x == 0); | ||
impl_is_zero!(usize, |x| x == 0); | ||
|
||
impl_is_zero!(bool, |x| x == false); | ||
impl_is_zero!(char, |x| x == '\0'); | ||
|
||
impl_is_zero!(f32, |x: f32| x.to_bits() == 0); | ||
impl_is_zero!(f64, |x: f64| x.to_bits() == 0); | ||
|
||
unsafe impl<T> IsZero for *const T { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
(*self).is_null() | ||
} | ||
} | ||
|
||
unsafe impl<T> IsZero for *mut T { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
(*self).is_null() | ||
} | ||
} | ||
|
||
unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
// Because this is generated as a runtime check, it's not obvious that | ||
// it's worth doing if the array is really long. The threshold here | ||
// is largely arbitrary, but was picked because as of 2022-05-01 LLVM | ||
// can const-fold the check in `vec![[0; 32]; n]` but not in | ||
// `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b | ||
// Feel free to tweak if you have better evidence. | ||
|
||
N <= 32 && self.iter().all(IsZero::is_zero) | ||
} | ||
} | ||
|
||
// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null. | ||
// For fat pointers, the bytes that would be the pointer metadata in the `Some` | ||
// variant are padding in the `None` variant, so ignoring them and | ||
// zero-initializing instead is ok. | ||
// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of | ||
// `SpecFromElem`. | ||
|
||
unsafe impl<T: ?Sized> IsZero for Option<&T> { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
self.is_none() | ||
} | ||
} | ||
|
||
unsafe impl<T: ?Sized> IsZero for Option<Box<T>> { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
self.is_none() | ||
} | ||
} | ||
|
||
// `Option<num::NonZeroU32>` and similar have a representation guarantee that | ||
// they're the same size as the corresponding `u32` type, as well as a guarantee | ||
// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works. | ||
// While the documentation officially makes it UB to transmute from `None`, | ||
// we're the standard library so we can make extra inferences, and we know that | ||
// the only niche available to represent `None` is the one that's all zeros. | ||
|
||
macro_rules! impl_is_zero_option_of_nonzero { | ||
($($t:ident,)+) => {$( | ||
unsafe impl IsZero for Option<core::num::$t> { | ||
#[inline] | ||
fn is_zero(&self) -> bool { | ||
self.is_none() | ||
} | ||
} | ||
)+}; | ||
} | ||
|
||
impl_is_zero_option_of_nonzero!( | ||
NonZeroU8, | ||
NonZeroU16, | ||
NonZeroU32, | ||
NonZeroU64, | ||
NonZeroU128, | ||
NonZeroI8, | ||
NonZeroI16, | ||
NonZeroI32, | ||
NonZeroI64, | ||
NonZeroI128, | ||
NonZeroUsize, | ||
NonZeroIsize, | ||
); |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use crate::alloc::Allocator; | ||
#[cfg(not(no_global_oom_handling))] | ||
use crate::borrow::Cow; | ||
|
||
use super::Vec; | ||
|
||
macro_rules! __impl_slice_eq1 { | ||
([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => { | ||
#[$stability] | ||
impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs | ||
where | ||
T: PartialEq<U>, | ||
$($ty: $bound)? | ||
{ | ||
#[inline] | ||
fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } | ||
#[inline] | ||
fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] } | ||
} | ||
} | ||
} | ||
|
||
__impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2>, #[stable(feature = "rust1", since = "1.0.0")] } | ||
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U], #[stable(feature = "rust1", since = "1.0.0")] } | ||
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } | ||
__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } | ||
__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } | ||
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } | ||
__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } | ||
#[cfg(not(no_global_oom_handling))] | ||
__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } | ||
#[cfg(not(no_global_oom_handling))] | ||
__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } | ||
#[cfg(not(no_global_oom_handling))] | ||
__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } | ||
__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } | ||
__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } | ||
|
||
// NOTE: some less important impls are omitted to reduce code bloat | ||
// FIXME(Centril): Reconsider this? | ||
//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], } | ||
//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, } | ||
//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, } | ||
//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, } | ||
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], } | ||
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], } | ||
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], } |