Skip to main content

osom_lib_arrays/dynamic_array/
dynamic_array.rs

1//! Holds the definition of [`DynamicArray`].
2
3use core::{
4    borrow::{Borrow, BorrowMut},
5    hash::Hash,
6};
7
8use osom_lib_alloc::traits::Allocator;
9use osom_lib_primitives::length::Length;
10use osom_lib_reprc::traits::ReprC;
11use osom_lib_try_clone::TryClone;
12
13use crate::{
14    errors::{ArrayError, ArrayIsEmptyError, ArrayTryCloneError},
15    traits::{ImmutableArray, MutableArray},
16};
17
18use super::internal_array::InternalArray;
19
20/// A `#[repr(C)]` variant of the standard `vec` struct.
21///
22/// Functionally similar, and implements [`ReprC`] for `T: ReprC`. However,
23/// unlike `vec` this struct multiplies capacity by `3/2` when resizing is
24/// needed.
25#[derive(Debug)]
26#[repr(transparent)]
27#[must_use]
28pub struct DynamicArray<T, TAllocator>
29where
30    TAllocator: Allocator,
31{
32    inner: InternalArray<T, TAllocator>,
33}
34
35unsafe impl<T, TAllocator> ReprC for DynamicArray<T, TAllocator>
36where
37    T: ReprC,
38    TAllocator: Allocator,
39{
40    const CHECK: () = const {
41        osom_lib_reprc::hidden::is_reprc::<T>();
42        osom_lib_reprc::hidden::is_reprc::<InternalArray<T, TAllocator>>();
43    };
44}
45
46impl<T, TAllocator> DynamicArray<T, TAllocator>
47where
48    TAllocator: Allocator,
49{
50    /// Creates a new, empty [`DynamicArray`].
51    #[inline(always)]
52    pub fn new() -> Self
53    where
54        TAllocator: Default,
55    {
56        Self::with_allocator(TAllocator::default())
57    }
58
59    /// Creates a new, empty [`DynamicArray`] with an allocator.
60    #[inline(always)]
61    pub const fn with_allocator(allocator: TAllocator) -> Self {
62        Self {
63            inner: InternalArray::new(allocator),
64        }
65    }
66
67    /// Creates a new [`DynamicArray`] with capacity and allocator.
68    /// This allocates memory only when `capacity > 0`.
69    ///
70    /// # Errors
71    ///
72    /// For details see [`ArrayError`].
73    #[inline(always)]
74    pub fn with_capacity_and_allocator(capacity: Length, allocator: TAllocator) -> Result<Self, ArrayError> {
75        let inner = InternalArray::<T, TAllocator>::with_capacity(capacity, allocator)?;
76        Ok(Self { inner })
77    }
78
79    /// Creates a new [`DynamicArray`] with capacity and the default allocator.
80    /// This allocates memory only when `capacity > 0`.
81    ///
82    /// # Errors
83    ///
84    /// For details see [`ArrayError`].
85    #[inline(always)]
86    pub fn with_capacity(capacity: Length) -> Result<Self, ArrayError>
87    where
88        TAllocator: Default,
89    {
90        Self::with_capacity_and_allocator(capacity, TAllocator::default())
91    }
92
93    /// Creates a new [`DynamicArray`] with a given size, generated through a given factory.
94    /// This allocates memory only when `size > 0`.
95    ///
96    /// # Notes
97    ///
98    /// This method is functionally equivalent to initializing an empty vector and running
99    /// factory one by one in a loop, and passing it to
100    /// [`push`][`crate::traits::MutableArray::push`]. This way, however, is more efficient,
101    /// even if you preallocate the vector with capacity. Because this method gives the
102    /// compiler an opportunity to vectorize the construction, unlike sequential
103    /// [`push`][`crate::traits::MutableArray::push`] calls.
104    ///
105    /// # Errors
106    ///
107    /// For details see [`ArrayError`].
108    #[inline(always)]
109    pub fn with_factory<Factory: FnMut(usize) -> T>(size: Length, factory: Factory) -> Result<Self, ArrayError>
110    where
111        TAllocator: Default,
112    {
113        Self::with_factory_and_allocator(size, factory, TAllocator::default())
114    }
115
116    /// Creates a new [`DynamicArray`] with a given size, generated through a given factory,
117    /// with a custom allocator. This allocates memory only when `size > 0`.
118    ///
119    /// # Notes
120    ///
121    /// This method is functionally equivalent to initializing an empty vector and running
122    /// factory one by one in a loop, and passing it to
123    /// [`push`][`crate::traits::MutableArray::push`]. This way, however, is more efficient,
124    /// even if you preallocate the vector with capacity. Because this method gives the
125    /// compiler an opportunity to vectorize the construction, unlike sequential
126    /// [`push`][`crate::traits::MutableArray::push`] calls.
127    ///
128    /// # Errors
129    ///
130    /// For details see [`ArrayError`].
131    pub fn with_factory_and_allocator<Factory: FnMut(usize) -> T>(
132        size: Length,
133        mut factory: Factory,
134        allocator: TAllocator,
135    ) -> Result<Self, ArrayError> {
136        unsafe {
137            let mut array = Self::with_size_and_allocator_uninitialized(size, allocator)?;
138            let slice_mut_ptr = array.as_mut().as_mut_ptr();
139            for idx in 0..size.as_usize() {
140                slice_mut_ptr.add(idx).write(factory(idx));
141            }
142            Ok(array)
143        }
144    }
145
146    /// Creates a new [`DynamicArray`] with a given size, but uninitialized.
147    ///
148    /// # Safety
149    ///
150    /// The underlying array is uninitialized and reading the data is UB, unless
151    /// initialized first.
152    ///
153    /// # Errors
154    ///
155    /// For details see [`ArrayError`].
156    #[inline(always)]
157    pub unsafe fn with_size_uninitialized(size: Length) -> Result<Self, ArrayError>
158    where
159        TAllocator: Default,
160    {
161        unsafe { Self::with_size_and_allocator_uninitialized(size, TAllocator::default()) }
162    }
163
164    /// Creates a new [`DynamicArray`] with a given size and allocator, but uninitialized.
165    ///
166    /// # Safety
167    ///
168    /// The underlying array is uninitialized and reading the data is UB, unless
169    /// initialized first.
170    ///
171    /// # Errors
172    ///
173    /// For details see [`ArrayError`].
174    pub unsafe fn with_size_and_allocator_uninitialized(
175        size: Length,
176        allocator: TAllocator,
177    ) -> Result<Self, ArrayError> {
178        let inner = unsafe { InternalArray::with_size_uninitialized(size, allocator) }?;
179        Ok(Self { inner })
180    }
181}
182
183impl<T, TAllocator> ImmutableArray<T> for DynamicArray<T, TAllocator>
184where
185    TAllocator: Allocator,
186{
187    #[inline(always)]
188    fn length(&self) -> Length {
189        self.inner.length()
190    }
191
192    #[inline(always)]
193    fn capacity(&self) -> Length {
194        self.inner.capacity()
195    }
196
197    #[inline(always)]
198    fn is_empty(&self) -> bool {
199        self.length().as_u32() == 0
200    }
201}
202
203impl<T, TAllocator> MutableArray<T> for DynamicArray<T, TAllocator>
204where
205    TAllocator: Allocator,
206{
207    #[inline(always)]
208    fn try_push_array<const TSIZE: usize>(&mut self, arr: [T; TSIZE]) -> Result<(), ArrayError> {
209        self.inner.try_push_array(arr)
210    }
211
212    #[inline(always)]
213    fn try_push_slice(&mut self, slice: &[T]) -> Result<(), ArrayTryCloneError>
214    where
215        T: TryClone,
216    {
217        self.inner.try_push_slice(slice)
218    }
219
220    #[inline(always)]
221    fn try_pop(&mut self) -> Result<T, ArrayIsEmptyError> {
222        self.inner.try_pop()
223    }
224}
225
226impl<T, TAllocator> Drop for DynamicArray<T, TAllocator>
227where
228    TAllocator: Allocator,
229{
230    fn drop(&mut self) {
231        unsafe { self.inner.deallocate() };
232    }
233}
234
235impl<T, TAllocator> Default for DynamicArray<T, TAllocator>
236where
237    TAllocator: Allocator + Default,
238{
239    fn default() -> Self {
240        Self::new()
241    }
242}
243
244impl<T, TAllocator> Clone for DynamicArray<T, TAllocator>
245where
246    T: TryClone + Clone,
247    TAllocator: Allocator + TryClone + Clone,
248{
249    fn clone(&self) -> Self {
250        self.try_clone().expect("Failed to clone dynamic array")
251    }
252}
253
254impl<T, TAllocator> TryClone for DynamicArray<T, TAllocator>
255where
256    T: TryClone,
257    TAllocator: Allocator + TryClone,
258{
259    type Error = ArrayTryCloneError;
260
261    fn try_clone(&self) -> Result<Self, Self::Error> {
262        let inner = self.inner.try_clone_with_capacity()?;
263        Ok(Self { inner })
264    }
265}
266
267impl<T, TAllocator, Rhs> PartialEq<Rhs> for DynamicArray<T, TAllocator>
268where
269    T: PartialEq,
270    TAllocator: Allocator,
271    Rhs: AsRef<[T]>,
272{
273    fn eq(&self, other: &Rhs) -> bool {
274        self.as_ref() == other.as_ref()
275    }
276}
277
278impl<T, TAllocator> Eq for DynamicArray<T, TAllocator>
279where
280    T: Eq,
281    TAllocator: Allocator,
282{
283}
284
285impl<T, TAllocator> Hash for DynamicArray<T, TAllocator>
286where
287    T: Hash,
288    TAllocator: Allocator,
289{
290    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
291        self.as_ref().hash(state);
292    }
293}
294
295impl<T, TAllocator> AsRef<[T]> for DynamicArray<T, TAllocator>
296where
297    TAllocator: Allocator,
298{
299    fn as_ref(&self) -> &[T] {
300        self.inner.as_slice()
301    }
302}
303
304impl<T, TAllocator> AsMut<[T]> for DynamicArray<T, TAllocator>
305where
306    TAllocator: Allocator,
307{
308    fn as_mut(&mut self) -> &mut [T] {
309        self.inner.as_slice_mut()
310    }
311}
312
313impl<T, TAllocator> Borrow<[T]> for DynamicArray<T, TAllocator>
314where
315    TAllocator: Allocator,
316{
317    #[inline(always)]
318    fn borrow(&self) -> &[T] {
319        self.as_ref()
320    }
321}
322
323impl<T, TAllocator> BorrowMut<[T]> for DynamicArray<T, TAllocator>
324where
325    TAllocator: Allocator,
326{
327    #[inline(always)]
328    fn borrow_mut(&mut self) -> &mut [T] {
329        self.as_mut()
330    }
331}