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}