|
| 1 | +//! This module works around limitations of the Rust programming language, and provides missing |
| 2 | +//! functionalities that we may expect the Rust programming language and its standard libraries |
| 3 | +//! to provide. |
| 4 | +
|
1 | 5 | /// Const function for min value of two usize numbers.
|
2 | 6 | pub const fn min_of_usize(a: usize, b: usize) -> usize {
|
3 | 7 | if a > b {
|
@@ -123,3 +127,53 @@ mod initialize_once_tests {
|
123 | 127 | assert_eq!(INITIALIZE_COUNT.load(Ordering::SeqCst), 1);
|
124 | 128 | }
|
125 | 129 | }
|
| 130 | + |
| 131 | +/// This module is for allocating large arrays or vectors with initial zero values. |
| 132 | +/// |
| 133 | +/// Note: The standard library uses the `IsZero` trait to specialize the intialization of `Vec<T>` |
| 134 | +/// if the initial element values are zero. Primitive type, such as `i8`, `usize`, `f32`, as well |
| 135 | +/// as types with known representations such as `Option<NonZeroUsize>` implement the `IsZero` |
| 136 | +/// trait. However, it has several limitations. |
| 137 | +/// |
| 138 | +/// 1. Composite types, such as `SpaceDescriptor(usize)`, doesn't implement the `IsZero` trait, |
| 139 | +/// even if it has the `#[repr(transparent)]` annotation. |
| 140 | +/// 2. The `IsZero` trait is private to the `std` module, and we cannot use it. |
| 141 | +/// |
| 142 | +/// Therefore, `vec![0usize; 33554432]` takes only 4 **microseconds**, while |
| 143 | +/// `vec![SpaceDescriptor(0); 33554432]` will take 22 **milliseconds** to execute on some machine. |
| 144 | +/// If such an allocation happens during start-up, the delay will be noticeable to light-weight |
| 145 | +/// scripting languages, such as Ruby. |
| 146 | +/// |
| 147 | +/// We implement our own fast allocation of large zeroed vectors in this module. If one day Rust |
| 148 | +/// provides a standard way to optimize for zeroed allocation of vectors of composite types, we |
| 149 | +/// can switch to the standard mechanism. |
| 150 | +pub mod zeroed_alloc { |
| 151 | + |
| 152 | + use std::alloc::{alloc_zeroed, Layout}; |
| 153 | + |
| 154 | + /// Allocate a `Vec<T>` of all-zero values. |
| 155 | + /// |
| 156 | + /// This intends to be a faster alternative to `vec![T(0), size]`. It will allocate pre-zeroed |
| 157 | + /// buffer, and not store zero values to its elements as part of initialization. |
| 158 | + /// |
| 159 | + /// It is useful when creating large (hundreds of megabytes) Vecs when the execution time is |
| 160 | + /// critical (such as during start-up, where a 100ms delay is obvious to small applications.) |
| 161 | + /// However, because of its unsafe nature, it should only be used when necessary. |
| 162 | + /// |
| 163 | + /// Arguments: |
| 164 | + /// |
| 165 | + /// - `T`: The element type. |
| 166 | + /// - `size`: The length and capacity of the created vector. |
| 167 | + /// |
| 168 | + /// Returns the created vector. |
| 169 | + /// |
| 170 | + /// # Unsafe |
| 171 | + /// |
| 172 | + /// This function is unsafe. It will not call any constructor of `T`. The user must ensure |
| 173 | + /// that a value with all bits being zero is meaningful for type `T`. |
| 174 | + pub(crate) unsafe fn new_zeroed_vec<T>(size: usize) -> Vec<T> { |
| 175 | + let layout = Layout::array::<T>(size).unwrap(); |
| 176 | + let ptr = alloc_zeroed(layout) as *mut T; |
| 177 | + Vec::from_raw_parts(ptr, size, size) |
| 178 | + } |
| 179 | +} |
0 commit comments