orx_pinned_vec/
concurrent_pinned_vec.rs

1use crate::{PinnedVec, PinnedVecGrowthError};
2use core::ops::{Range, RangeBounds};
3
4/// A wrapper for a pinned vector which provides additional guarantees for concurrent programs.
5///
6/// Note that a concurrent pinned vec inherits pinned memory location guarantees.
7///
8/// The struct encapsulates many methods of the pinned vector which are not suitable for concurrent programs.
9/// Further, it exposes new and mostly unsafe methods for allowing performant concurrent collections.
10/// It is designed to be a core structure for concurrent collections with a safe api.
11pub trait ConcurrentPinnedVec<T> {
12    /// Type of the wrapped pinned vector.
13    type P: PinnedVec<T>;
14
15    /// Iterator yielding slices corresponding to a range of indices, returned by the `slice` method.
16    type SliceIter<'a>: IntoIterator<Item = &'a [T]> + Default
17    where
18        T: 'a,
19        Self: 'a;
20
21    /// Iterator yielding mutable slices corresponding to a range of indices, returned by the `slice_mut` and `slice_mut_unchecked` methods.
22    type SliceMutIter<'a>: IntoIterator<Item = &'a mut [T]> + Default
23    where
24        T: 'a,
25        Self: 'a;
26
27    /// Iterator yielding pointers to elements of the vector.
28    type PtrIter<'a>: ExactSizeIterator<Item = *mut T>
29    where
30        Self: 'a;
31
32    /// Iterator that the pinned vector is converted into, which moves out elements.
33    type IntoIter: ExactSizeIterator<Item = T>;
34
35    /// Converts back to the underlying pinned vector with the given length.
36    ///
37    /// # Safety
38    ///
39    /// This method is unsafe due to the following.
40    /// The concurrent pinned vector is the core data structure for different concurrent collections
41    /// which allow writing to the vector in different ways.
42    /// The wrapper is responsible to deal with the gaps.
43    ///
44    /// This method can safely be called if entries in all positions `0..len` are written.
45    unsafe fn into_inner(self, len: usize) -> Self::P;
46
47    /// Clones the concurrent pinned vector with for the first `len` elements.
48    /// The created concurrent vector will have the same capacity and maximum capacity as this collection;
49    /// however, only the values within 0..len will be cloned to the target.
50    ///
51    /// # Safety
52    ///
53    /// This method is unsafe due to the following.
54    /// The concurrent pinned vector is the core data structure for different concurrent collections
55    /// which allow writing to the vector in different ways.
56    /// The wrapper is responsible to deal with the gaps.
57    ///
58    /// This method can safely be called if entries in all positions `0..len` are written.
59    unsafe fn clone_with_len(&self, len: usize) -> Self
60    where
61        T: Clone;
62
63    // &self get
64
65    /// Returns an iterator over positions `0..len` of the vector.
66    ///
67    /// # Safety
68    ///
69    /// This method is unsafe since the concurrent pinned vector might contain gaps.
70    ///
71    /// This method can safely be called if entries in all positions `0..len` are written.
72    unsafe fn iter<'a>(&'a self, len: usize) -> impl Iterator<Item = &'a T> + 'a
73    where
74        T: 'a;
75
76    /// Returns an iterator over positions `range` of the vector.
77    ///
78    /// # Safety
79    ///
80    /// This method is unsafe since the concurrent pinned vector might contain gaps.
81    ///
82    /// This method can safely be called if entries in all positions `range` are written.
83    unsafe fn iter_over_range<'a, R: RangeBounds<usize>>(
84        &'a self,
85        range: R,
86    ) -> impl Iterator<Item = &'a T> + 'a
87    where
88        T: 'a;
89
90    /// Returns a reference to the element at the `index`-th position.
91    ///
92    /// # Safety
93    ///
94    /// This method is unsafe since the concurrent pinned vector might contain gaps.
95    ///
96    /// This method can safely be called if the entry at position `index` is written.
97    unsafe fn get(&self, index: usize) -> Option<&T>;
98
99    /// Returns a mutable reference to the element at the `index`-th position.
100    ///
101    /// # Safety
102    ///
103    /// This method is used to write to the vector.
104    /// Therefore, its position will initially be uninitialized; hence, reading the pointer might result in UB.
105    unsafe fn get_ptr_mut(&self, index: usize) -> *mut T;
106
107    /// Returns an iterator of mutable slices to the elements extending over positions `range` of the vector.
108    ///
109    /// # Safety
110    ///
111    /// This method is used to write to the vector.
112    /// Therefore, the positions will initially be uninitialized; hence, reading from the slices might result in UB.
113    unsafe fn slices_mut<R: RangeBounds<usize>>(&self, range: R) -> Self::SliceMutIter<'_>;
114
115    /// Returns an iterator of slices to the elements extending over positions `range` of the vector.
116    fn slices<R: RangeBounds<usize>>(&self, range: R) -> Self::SliceIter<'_>;
117
118    // capacity
119
120    /// Returns the maximum possible capacity that the vector can concurrently grow to without requiring a `&mut self` reference.
121    ///
122    /// In order to grow beyond this capacity, `reserve_maximum_concurrent_capacity` method can be used.
123    fn max_capacity(&self) -> usize;
124
125    /// Returns the current capacity of the vector, which is actually allocated.
126    fn capacity(&self) -> usize;
127
128    /// Tries to concurrently grow the capacity of the vector to at least `new_capacity`. Returns:
129    /// * Ok of the new capacity if succeeds
130    /// * Err otherwise.
131    ///
132    /// Behavior of this method is deterministic.
133    /// The method always succeeds (fails) if `new_capacity <= self.max_capacity()` (otherwise).
134    ///
135    /// If the method returns an error, `reserve_maximum_concurrent_capacity` method can be used; however, with a `&mut self` reference.
136    /// Then, `grow_to` will succeed.
137    fn grow_to(&self, new_capacity: usize) -> Result<usize, PinnedVecGrowthError>;
138
139    /// Tries to concurrently grow the capacity of the vector to at least `new_capacity`. Returns:
140    /// * Ok of the new capacity if succeeds
141    /// * Err otherwise.
142    ///
143    /// Behavior of this method is deterministic.
144    /// The method always succeeds (fails) if `new_capacity <= self.max_capacity()` (otherwise).
145    ///
146    /// If the method returns an error, `reserve_maximum_concurrent_capacity` method can be used;
147    /// however, with a `&mut self` reference.
148    /// Then, `grow_to` will succeed.
149    ///
150    /// During growth:
151    ///
152    /// * length of the vector is increased to its new capacity;
153    /// * the elements in the range `len..capacity` are filled with the values
154    ///   obtained by repeatedly calling the function `fill_with`.
155    fn grow_to_and_fill_with<F>(
156        &self,
157        new_capacity: usize,
158        fill_with: F,
159    ) -> Result<usize, PinnedVecGrowthError>
160    where
161        F: Fn() -> T;
162
163    /// Fills the provided `range` with elements created by successively calling the `fill_with` function.
164    fn fill_with<F>(&self, range: Range<usize>, fill_with: F)
165    where
166        F: Fn() -> T;
167
168    /// Increases the `maximum_capacity` to the `new_maximum_capacity`.
169    ///
170    /// # Safety
171    ///
172    /// This method is unsafe since the concurrent pinned vector might contain gaps.
173    /// The vector must be gap-free while increasing the maximum capacity.
174    ///
175    /// This method can safely be called if entries in all positions `0..len` are written.
176    unsafe fn reserve_maximum_concurrent_capacity(
177        &mut self,
178        len: usize,
179        new_maximum_capacity: usize,
180    ) -> usize;
181
182    /// Increases the `maximum_capacity` to the `new_maximum_capacity`.
183    /// If capacity extension leads to allocation, allocated memory is filled with the given function.
184    ///
185    /// # Safety
186    ///
187    /// This method is unsafe since the concurrent pinned vector might contain gaps.
188    /// The vector must be gap-free while increasing the maximum capacity.
189    ///
190    /// This method can safely be called if entries in all positions `0..len` are written.
191    unsafe fn reserve_maximum_concurrent_capacity_fill_with<F>(
192        &mut self,
193        len: usize,
194        new_maximum_capacity: usize,
195        fill_with: F,
196    ) -> usize
197    where
198        F: Fn() -> T;
199
200    // &mut self
201
202    /// Sets the length of the underlying pinned vector to the given `len`.
203    ///
204    /// # Safety
205    ///
206    /// This method is unsafe since the concurrent pinned vector might contain gaps.
207    ///
208    /// This method can safely be called if entries in all positions `0..len` are written.
209    unsafe fn set_pinned_vec_len(&mut self, len: usize);
210
211    /// Returns a mutable iterator over positions `0..len` of the vector.
212    ///
213    /// # Safety
214    ///
215    /// This method is unsafe since the concurrent pinned vector might contain gaps.
216    ///
217    /// This method can safely be called if entries in all positions `0..len` are written.
218    unsafe fn iter_mut<'a>(&'a mut self, len: usize) -> impl Iterator<Item = &'a mut T> + 'a
219    where
220        T: 'a;
221
222    /// Returns a reference to the element at the `index`-th position.
223    ///
224    /// # Safety
225    ///
226    /// This method is unsafe since the concurrent pinned vector might contain gaps.
227    ///
228    /// This method can safely be called if the entry at position `index` is written.
229    unsafe fn get_mut(&mut self, index: usize) -> Option<&mut T>;
230
231    /// Clears the concurrent pinned vector.
232    ///
233    /// # Safety
234    ///
235    /// This method is unsafe since the concurrent pinned vector might contain gaps.
236    ///
237    /// This method can safely be called if entries in all positions `0..len` are written.
238    unsafe fn clear(&mut self, len: usize);
239
240    /// Returns an iterator yielding pointers to elements within the given `range`.
241    ///
242    /// # SAFETY
243    ///
244    /// The method is marked unsafe due to the possibility of `range` being out of bounds.
245    /// This method does not perform a bounds check and it leads to UB if the range is
246    /// out of bounds.
247    ///
248    /// Returned iterator is created from a shared reference to the vec.
249    /// Therefore, the vec, cannot be mutated while using the iterator.
250    ///
251    /// Further, since the iterator is created using a shared reference to the vec,
252    /// it cannot outlive the vec.
253    ///
254    /// These guarantee that all pointers that the iterator yields will be valid.
255    ///
256    /// In brief, it is safe to use this method provided that the caller guarantees
257    /// that the range is in bounds.
258    unsafe fn ptr_iter_unchecked(&self, range: Range<usize>) -> Self::PtrIter<'_>;
259
260    /// Converts the concurrent pinned vector into an exact sized iterator.
261    ///
262    /// # SAFETY
263    ///
264    /// This method is to be called when only `range` contains valid elements of the vector
265    /// while elements in other positions are already dropped, if they need to be dropped.
266    ///
267    /// The iterator is then responsible for yielding the valid elements within this `range`,
268    /// or dropping them if the iterator is not fully consumed. Furthermore, once the iterator
269    /// is dropped, all the allocations of the concurrent pinned vector will also be dropped.
270    unsafe fn into_iter(self, range: Range<usize>) -> Self::IntoIter;
271}