Skip to main content

unchecked_std/
lib.rs

1//! Fast, unchecked variants of common std methods.
2
3#![no_std]
4
5extern crate alloc;
6use self::{generic_string::GenericString, generic_vec::GenericVec};
7use alloc::vec::Vec;
8
9mod generic_string;
10mod generic_vec;
11
12/// A trait for `push` without the capacity check.
13pub trait PushUnchecked<T> {
14    /// Appends an element to the back of a collection without the capacity check.
15    ///
16    /// # Safety
17    ///
18    /// The capacity of the collection must be sufficient for the new item.
19    unsafe fn push_unchecked(&mut self, value: T);
20}
21
22impl<T> PushUnchecked<T> for Vec<T> {
23    /// [`Self::push`] without the capacity check.
24    ///
25    /// # Safety
26    ///
27    /// `self.len()` must be `< self.capacity()`.
28    #[inline]
29    unsafe fn push_unchecked(&mut self, value: T) {
30        debug_assert!(self.len() < self.capacity());
31        if self.len() >= self.capacity() {
32            core::hint::unreachable_unchecked();
33        }
34
35        core::ptr::write(self.as_mut_ptr().add(self.len()), value);
36        self.set_len(self.len() + 1);
37    }
38}
39
40impl<S: GenericString> PushUnchecked<char> for S {
41    /// `push` without the capacity check.
42    ///
43    /// # Safety
44    ///
45    /// `self.len() + ch.len_utf8()` must be `<= self.capacity()`.
46    #[inline]
47    unsafe fn push_unchecked(&mut self, ch: char) {
48        let len = self.len();
49        let ch_len = ch.len_utf8();
50        debug_assert!(len + ch_len <= self.capacity());
51        let ptr = self.as_mut_vec().as_mut_ptr().add(len);
52        match ch_len {
53            1 => {
54                *ptr = ch as u8;
55            }
56            2 => {
57                *ptr = (ch as u32 >> 6 & 0x1F) as u8 | 0b1100_0000;
58                *ptr.add(1) = (ch as u32 & 0x3F) as u8 | 0b1000_0000;
59            }
60            3 => {
61                *ptr = (ch as u32 >> 12 & 0x0F) as u8 | 0b1110_0000;
62                *ptr.add(1) = (ch as u32 >> 6 & 0x3F) as u8 | 0b1000_0000;
63                *ptr.add(2) = (ch as u32 & 0x3F) as u8 | 0b1000_0000;
64            }
65            4 => {
66                *ptr = (ch as u32 >> 18 & 0x07) as u8 | 0b1111_0000;
67                *ptr.add(1) = (ch as u32 >> 12 & 0x3F) as u8 | 0b1000_0000;
68                *ptr.add(2) = (ch as u32 >> 6 & 0x3F) as u8 | 0b1000_0000;
69                *ptr.add(3) = (ch as u32 & 0x3F) as u8 | 0b1000_0000;
70            }
71            _ => core::hint::unreachable_unchecked(),
72        }
73        self.as_mut_vec().set_len(len + ch_len);
74    }
75}
76
77/// A trait for `extend` without the capacity check.
78pub trait ExtendUnchecked<T> {
79    /// Extends a collection with the contents of an iterator without the
80    /// capacity check.
81    ///
82    /// # Safety
83    ///
84    /// The capacity of the collection must be sufficient for the new items.
85    unsafe fn extend_unchecked<I: IntoIterator<Item = T>>(&mut self, iter: I);
86}
87
88impl<S: GenericString> ExtendUnchecked<char> for S {
89    /// [`Extend::extend`] without the capacity check.
90    ///
91    /// # Safety
92    ///
93    /// `self.len() + iter.into_iter().count()` must be `<= self.capacity()`.
94    #[inline]
95    unsafe fn extend_unchecked<I: IntoIterator<Item = char>>(&mut self, iter: I) {
96        for ch in iter {
97            self.push_unchecked(ch);
98        }
99    }
100}
101
102impl<'a, S: GenericString> ExtendUnchecked<&'a char> for S {
103    /// [`Extend::extend`] without the capacity check.
104    ///
105    /// # Safety
106    ///
107    /// `self.len() + iter.into_iter().count()` must be `<= self.capacity()`.
108    #[inline]
109    unsafe fn extend_unchecked<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
110        for &ch in iter {
111            self.push_unchecked(ch);
112        }
113    }
114}
115
116/// A trait for `extend_from_slice` without the capacity check.
117pub trait ExtendFromSliceUnchecked<T> {
118    /// Clones and appends all elements in a slice to the collection.
119    ///
120    /// # Safety
121    ///
122    /// The capacity of the collection must be sufficient for the new items.
123    unsafe fn extend_from_slice_unchecked(&mut self, other: &[T]);
124}
125
126impl<T: Clone> ExtendFromSliceUnchecked<T> for Vec<T> {
127    /// [`Self::extend_from_slice`] without the capacity check.
128    ///
129    /// # Safety
130    ///
131    /// `other.len()` must be `<= self.capacity() - self.len()`.
132    #[inline]
133    unsafe fn extend_from_slice_unchecked(&mut self, other: &[T]) {
134        debug_assert!(other.len() <= self.capacity() - self.len());
135        if other.len() > self.capacity() - self.len() {
136            core::hint::unreachable_unchecked();
137        }
138        self.extend_from_slice(other);
139    }
140}
141
142#[cfg(feature = "heapless")]
143impl<T: Copy, const N: usize> ExtendFromSliceUnchecked<T> for heapless::Vec<T, N> {
144    /// [`Self::extend_from_slice`] without the capacity check.
145    ///
146    /// # Safety
147    ///
148    /// `other.len()` must be `<= self.capacity() - self.len()`.
149    #[inline]
150    unsafe fn extend_from_slice_unchecked(&mut self, other: &[T]) {
151        let len = self.len();
152        let count = other.len();
153        debug_assert!(count <= self.capacity() - len);
154        core::ptr::copy_nonoverlapping(other.as_ptr(), self.as_mut_ptr().add(len), count);
155        self.set_len(len + count);
156    }
157}
158
159/// A trait for `extend_from_within` without the capacity and bounds checks.
160pub trait ExtendFromWithinUnchecked {
161    /// Copies elements from `src` range to the end of the collection
162    /// without the capacity check and the bounds check for the range.
163    ///
164    /// # Safety
165    ///
166    /// `src` must be a valid index for the collection.
167    /// The capacity of the collection must be sufficient for the new items.
168    unsafe fn extend_from_within_unchecked<R>(&mut self, src: R)
169    where
170        R: core::ops::RangeBounds<usize>;
171}
172
173impl<T: Copy, V: GenericVec<Item = T>> ExtendFromWithinUnchecked for V {
174    /// `extend_from_within` without the capacity check
175    /// and the bounds check for the range.
176    ///
177    /// # Safety
178    ///
179    /// - `src` must be a valid index for `self`
180    /// - capacity of `self` must be sufficient for the new items
181    #[inline]
182    unsafe fn extend_from_within_unchecked<R>(&mut self, src: R)
183    where
184        R: core::ops::RangeBounds<usize>,
185    {
186        let start = match src.start_bound() {
187            core::ops::Bound::Included(&start) => start,
188            core::ops::Bound::Excluded(&start) => {
189                debug_assert!(start != usize::MAX);
190                start + 1
191            }
192            core::ops::Bound::Unbounded => 0,
193        };
194        let end = match src.end_bound() {
195            core::ops::Bound::Included(&end) => {
196                debug_assert!(end != usize::MAX);
197                end + 1
198            }
199            core::ops::Bound::Excluded(&end) => end,
200            core::ops::Bound::Unbounded => self.len(),
201        };
202        debug_assert!(start <= end && end <= self.len());
203
204        let count = end - start;
205        debug_assert!(self.capacity() - self.len() >= count);
206
207        // NOTE: miri accepts this memcpy with Vec, but not with heapless::Vec,
208        // unless -Zmiri-tree-borrows is used
209        core::ptr::copy_nonoverlapping(
210            self.as_ptr().add(start),
211            self.as_mut_ptr().add(self.len()),
212            count,
213        );
214        self.set_len(self.len() + count);
215    }
216}
217
218/// A trait for `push_str` without the capacity check.
219pub trait PushStrUnchecked {
220    /// Appends a given string slice onto the end of this collection without
221    /// the capacity check.
222    ///
223    /// # Safety
224    ///
225    /// The capacity of the collection must be sufficient for the appended string.
226    unsafe fn push_str_unchecked(&mut self, string: &str);
227}
228
229impl<S: GenericString> PushStrUnchecked for S {
230    /// `push_str` without the capacity check.
231    ///
232    /// # Safety
233    ///
234    /// `self.len() + string.len()` must be `<= self.capacity()`.
235    #[inline]
236    unsafe fn push_str_unchecked(&mut self, string: &str) {
237        self.as_mut_vec()
238            .extend_from_slice_unchecked(string.as_bytes());
239    }
240}
241
242/// A trait for `copy_from_slice` without the length check.
243pub trait CopyFromSliceUnchecked<T> {
244    /// Copies all elements from `src` into `self` without the length check.
245    ///
246    /// # Safety
247    ///
248    /// The length of `self` must be equal to the length of `src`.
249    unsafe fn copy_from_slice_unchecked(&mut self, src: &[T]);
250}
251
252impl<T: Copy> CopyFromSliceUnchecked<T> for [T] {
253    /// [`Self::copy_from_slice`] without the length check.
254    ///
255    /// # Safety
256    ///
257    /// `self.len()` must be `== src.len()`.
258    #[inline]
259    unsafe fn copy_from_slice_unchecked(&mut self, src: &[T]) {
260        debug_assert!(self.len() == src.len());
261        unsafe {
262            core::ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
263        }
264    }
265}
266
267/// A trait to `push` many times without the capacity check.
268pub trait PushManyUnchecked<T> {
269    /// Appends an element `count` times to the back of a collection without
270    /// the capacity check.
271    ///
272    /// # Safety
273    ///
274    /// The capacity of the collection must be sufficient for the new items.
275    unsafe fn push_many_unchecked(&mut self, value: T, count: usize);
276}
277
278impl<V: GenericVec<Item = u8>> PushManyUnchecked<u8> for V {
279    /// Appends a `byte` `count` times to the back of the vector without the
280    /// capacity check.
281    ///
282    /// # Safety
283    ///
284    /// The capacity of the vector must be sufficient for the new bytes.
285    #[inline]
286    unsafe fn push_many_unchecked(&mut self, byte: u8, count: usize) {
287        debug_assert!(self.capacity() - self.len() >= count);
288
289        core::ptr::write_bytes(self.as_mut_ptr().add(self.len()), byte, count);
290        self.set_len(self.len() + count);
291    }
292}
293
294impl<V: GenericVec<Item = i8>> PushManyUnchecked<i8> for V {
295    /// Appends a `byte` `count` times to the back of the vector without the
296    /// capacity check.
297    ///
298    /// # Safety
299    ///
300    /// The capacity of the vector must be sufficient for the new bytes.
301    #[inline]
302    unsafe fn push_many_unchecked(&mut self, byte: i8, count: usize) {
303        debug_assert!(self.capacity() - self.len() >= count);
304
305        core::ptr::write_bytes(
306            self.as_mut_ptr().add(self.len()),
307            byte.cast_unsigned(),
308            count,
309        );
310        self.set_len(self.len() + count);
311    }
312}
313
314/// Duplicate exports in `prelude` to comply with `clippy::wildcard_imports`.
315pub mod prelude {
316    pub use super::*;
317}