1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
//! This module is for allocating large arrays or vectors with initial zero values.
//!
//! Note: The standard library uses the `IsZero` trait to specialize the intialization of `Vec<T>`
//! if the initial element values are zero. Primitive type, such as `i8`, `usize`, `f32`, as well
//! as types with known representations such as `Option<NonZeroUsize>` implement the `IsZero`
//! trait. However, it has several limitations.
//!
//! 1. Composite types, such as `SpaceDescriptor(usize)`, doesn't implement the `IsZero` trait,
//! even if it has the `#[repr(transparent)]` annotation.
//! 2. The `IsZero` trait is private to the `std` module, and we cannot use it.
//!
//! Therefore, `vec![0usize; 33554432]` takes only 4 **microseconds**, while
//! `vec![SpaceDescriptor(0); 33554432]` will take 22 **milliseconds** to execute on some machine.
//! If such an allocation happens during start-up, the delay will be noticeable to light-weight
//! scripting languages, such as Ruby.
//!
//! *(Note: We no longer allocate such large vecs at start-up. We keep this module in case we need
//! to allocate large vectors in the future.)*
//!
//! We implement our own fast allocation of large zeroed vectors in this module. If one day Rust
//! provides a standard way to optimize for zeroed allocation of vectors of composite types, we
//! can switch to the standard mechanism.
use std::alloc::{alloc_zeroed, Layout};
/// Allocate a `Vec<T>` of all-zero values.
///
/// This intends to be a faster alternative to `vec![T(0), size]`. It will allocate pre-zeroed
/// buffer, and not store zero values to its elements as part of initialization.
///
/// It is useful when creating large (hundreds of megabytes) Vecs when the execution time is
/// critical (such as during start-up, where a 100ms delay is obvious to small applications.)
/// However, because of its unsafe nature, it should only be used when necessary.
///
/// Arguments:
///
/// - `T`: The element type.
/// - `size`: The length and capacity of the created vector.
///
/// Returns the created vector.
///
/// # Unsafe
///
/// This function is unsafe. It will not call any constructor of `T`. The user must ensure
/// that a value with all bits being zero is meaningful for type `T`.
pub(crate) unsafe fn new_zeroed_vec<T>(size: usize) -> Vec<T> {
let layout = Layout::array::<T>(size).unwrap();
let ptr = alloc_zeroed(layout) as *mut T;
Vec::from_raw_parts(ptr, size, size)
}