pub struct ConcurrentSlice<'a, T, P = SplitVec<ConcurrentElement<T>, Doubling>>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,{ /* private fields */ }
Expand description
A slice of a ConcurrentVec
.
It can be created from a ConcurrentVec by ConcurrentVec::slice
or from another slice by ConcurrentSlice::slice
.
Implementations§
Source§impl<'a, T, P> ConcurrentSlice<'a, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<'a, T, P> ConcurrentSlice<'a, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Sourcepub fn map<F, U>(&'a self, f: F) -> impl Iterator<Item = U> + 'a
pub fn map<F, U>(&'a self, f: F) -> impl Iterator<Item = U> + 'a
Returns an iterator to values obtained by mapping elements of the vec by f
.
Note that vec.map(f)
is a shorthand for vec.iter().map(move |elem| elem.map(|x: &T| f(x)))
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter(0..4);
let doubles: Vec<_> = vec.map(|x| x * 2).collect();
assert_eq!(doubles, [0, 2, 4, 6]);
Sourcepub fn filter<F>(
&self,
f: F,
) -> impl Iterator<Item = &ConcurrentElement<T>> + '_
pub fn filter<F>( &self, f: F, ) -> impl Iterator<Item = &ConcurrentElement<T>> + '_
Returns an iterator to elements filtered by using the predicate f
on the values.
Note that vec.filter(f)
is a shorthand for vec.iter().filter(move |elem| elem.map(|x: &T| f(x)))
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter(0..4);
let mut evens = vec.filter(|x| x % 2 == 0);
assert_eq!(evens.next().unwrap(), &0);
assert_eq!(evens.next().unwrap(), &2);
assert_eq!(evens.next(), None);
Sourcepub fn fold<F, U>(&self, init: U, f: F) -> U
pub fn fold<F, U>(&self, init: U, f: F) -> U
Folds the values of the vec starting from the init
using the fold function f
.
Note that vec.fold(f)
is a shorthand for vec.iter().fold(init, |agg, elem| elem.map(|x| f(agg, x)))
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter(0..4);
let sum = vec.fold(0, |sum, x| sum + x);
assert_eq!(sum, 6);
Sourcepub fn reduce<F>(&self, f: F) -> Option<T>
pub fn reduce<F>(&self, f: F) -> Option<T>
Reduces the values of the slice using the reduction f
; returns None if the vec is empty.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
let sum = vec.reduce(|a, b| a + b);
assert_eq!(sum, None);
vec.push(42);
let sum = vec.reduce(|a, b| a + b);
assert_eq!(sum, Some(42));
vec.extend([6, 2]);
let sum = vec.reduce(|a, b| a + b);
assert_eq!(sum, Some(50));
Source§impl<T, P> ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<T, P> ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Sourcepub fn swap(&self, i: usize, j: usize) -> bool
pub fn swap(&self, i: usize, j: usize) -> bool
Swaps two elements in the slice.
Returns:
- true of both
i
andj
are in bounds and values are swapped, - false if at least one of the indices is out of bounds.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend([0, 1, 2, 3, 4, 5]);
let slice = vec.slice(1..5);
let swapped = slice.swap(0, 2);
assert_eq!(swapped, true);
assert_eq!(&slice, &[3, 2, 1, 4]);
let swapped = slice.swap(0, 4); // out-of-bounds
assert_eq!(swapped, false);
assert_eq!(&slice, &[3, 2, 1, 4]);
assert_eq!(&vec, &[0, 3, 2, 1, 4, 5]);
Sourcepub fn fill(&self, value: T)where
T: Clone,
pub fn fill(&self, value: T)where
T: Clone,
Fills all positions of the slice with the given value
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter([0, 1, 2, 3]);
vec.slice(2..).fill(42);
assert_eq!(&vec, &[0, 1, 42, 42]);
Sourcepub fn fill_with<F>(&self, value: F)
pub fn fill_with<F>(&self, value: F)
Fills all positions of the slice with the the values
created by successively calling value(i)
for each position.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend([0, 1, 2, 3, 4, 5, 6]);
let slice = vec.slice(0..=3);
let mut current = 0;
slice.fill_with(|i| {
current += i as i32;
current
});
assert_eq!(&slice, &[0, 1, 3, 6]);
assert_eq!(&vec, &[0, 1, 3, 6, 4, 5, 6]);
Source§impl<T, P> ConcurrentSlice<'_, T, P>
impl<T, P> ConcurrentSlice<'_, T, P>
Sourcepub fn index_of(&self, value: &T) -> Option<usize>
pub fn index_of(&self, value: &T) -> Option<usize>
Returns the index of the first element equal to the given value
.
Returns None if the value is absent.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend(['a', 'b', 'c', 'd', 'e']);
let slice = vec.slice(0..3);
assert_eq!(slice.index_of(&'c'), Some(2));
assert_eq!(slice.index_of(&'d'), None);
Sourcepub fn contains(&self, value: &T) -> bool
pub fn contains(&self, value: &T) -> bool
Returns whether an element equal to the given value
exists or not.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend(['a', 'b', 'c', 'd', 'e']);
let slice = vec.slice(0..3);
assert_eq!(slice.contains(&'c'), true);
assert_eq!(slice.contains(&'d'), false);
Source§impl<'a, T, P> ConcurrentSlice<'a, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<'a, T, P> ConcurrentSlice<'a, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the length of the slice.
§Example
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter([0, 1, 2, 3, 4]);
assert_eq!(vec.slice(0..3).len(), 3);
assert_eq!(vec.slice(1..=2).len(), 2);
assert_eq!(vec.slice(5..).len(), 0);
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns whether the slice is empty or not.
§Example
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter([0, 1, 2, 3, 4]);
assert_eq!(vec.slice(0..3).is_empty(), false);
assert_eq!(vec.slice(1..=2).is_empty(), false);
assert_eq!(vec.slice(5..).is_empty(), true);
Sourcepub fn slice<R: RangeBounds<usize>>(
&self,
range: R,
) -> ConcurrentSlice<'_, T, P>
pub fn slice<R: RangeBounds<usize>>( &self, range: R, ) -> ConcurrentSlice<'_, T, P>
Creates and returns a slice of a ConcurrentVec
or another ConcurrentSlice
.
Concurrent counterpart of a slice for a standard vec or an array.
A ConcurrentSlice
provides a focused / restricted view on a slice of the vector.
It provides all methods of the concurrent vector except for the ones which
grow the size of the vector.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter([0, 1, 2, 3, 4]);
let slice = vec.slice(1..);
assert_eq!(&slice, &[1, 2, 3, 4]);
let slice = vec.slice(1..4);
assert_eq!(&slice, &[1, 2, 3]);
let slice = vec.slice(..3);
assert_eq!(&slice, &[0, 1, 2]);
let slice = vec.slice(3..10);
assert_eq!(&slice, &[3, 4]);
let slice = vec.slice(7..9);
assert_eq!(&slice, &[]);
// slices can also be sliced
let slice = vec.slice(1..=4);
assert_eq!(&slice, &[1, 2, 3, 4]);
let sub_slice = slice.slice(1..3);
assert_eq!(&sub_slice, &[2, 3]);
Sourcepub fn get(&self, i: usize) -> Option<&ConcurrentElement<T>>
pub fn get(&self, i: usize) -> Option<&ConcurrentElement<T>>
Returns the element at the i
-th position;
returns None if the index is out of bounds.
The safe api of the ConcurrentVec
never gives out &T
or &mut T
references.
Instead, returns a ConcurrentElement
which provides thread safe concurrent read and write
methods on the element.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend([0, 1, 2, 3, 4, 5, 6]);
let slice = vec.slice(1..5);
assert_eq!(&slice, &[1, 2, 3, 4]);
assert!(slice.get(4).is_none());
let cloned = slice.get(2).map(|elem| elem.cloned());
assert_eq!(cloned, Some(3));
let double = slice.get(2).map(|elem| elem.map(|x| x * 2));
assert_eq!(double, Some(6));
let elem = slice.get(2).unwrap();
assert_eq!(elem, &3);
elem.set(42);
assert_eq!(elem, &42);
elem.update(|x| *x = *x / 2);
assert_eq!(elem, &21);
let old = elem.replace(7);
assert_eq!(old, 21);
assert_eq!(elem, &7);
assert_eq!(&slice, &[1, 2, 7, 4]);
assert_eq!(&vec, &[0, 1, 2, 7, 4, 5, 6]);
Sourcepub fn get_cloned(&self, i: usize) -> Option<T>where
T: Clone,
pub fn get_cloned(&self, i: usize) -> Option<T>where
T: Clone,
Returns the cloned value of element at the i
-th position;
returns None if the index is out of bounds.
Note that slice.get_cloned(i)
is short-hand for slice.get(i).map(|elem| elem.cloned())
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend([10, 0, 1, 2, 3, 14, 15]);
let slice = vec.slice(1..5);
assert_eq!(slice.get_cloned(2), Some(2));
assert_eq!(slice.get_cloned(4), None);
Sourcepub fn get_copied(&self, i: usize) -> Option<T>where
T: Copy,
pub fn get_copied(&self, i: usize) -> Option<T>where
T: Copy,
Returns the copied value of element at the i
-th position;
returns None if the index is out of bounds.
Note that slice.get_copied(i)
is short-hand for slice.get(i).map(|elem| elem.copied())
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter([0, 1, 2, 3]);
assert_eq!(vec.get_copied(2), Some(2));
assert_eq!(vec.get_copied(4), None);
Sourcepub fn iter(&self) -> impl Iterator<Item = &ConcurrentElement<T>>
pub fn iter(&self) -> impl Iterator<Item = &ConcurrentElement<T>>
Returns an iterator to the elements of the slice.
The safe api of the ConcurrentSlice
never gives out &T
or &mut T
references.
Instead, the iterator yields ConcurrentElement
which provides thread safe concurrent read and write
methods on the element.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend([10, 0, 1, 2, 3, 14, 15]);
let slice = vec.slice(1..5);
// read - map
let doubles: Vec<_> = slice.iter().map(|elem| elem.map(|x| x * 2)).collect();
assert_eq!(doubles, [0, 2, 4, 6]);
// read - reduce
let sum: i32 = slice.iter().map(|elem| elem.cloned()).sum();
assert_eq!(sum, 6);
// mutate
for (i, elem) in slice.iter().enumerate() {
match i {
2 => elem.set(42),
_ => elem.update(|x| *x *= 2),
}
}
assert_eq!(&slice, &[0, 2, 42, 6]);
let old_vals: Vec<_> = slice.iter().map(|elem| elem.replace(7)).collect();
assert_eq!(&old_vals, &[0, 2, 42, 6]);
assert_eq!(&slice, &[7, 7, 7, 7]);
assert_eq!(&vec, &[10, 7, 7, 7, 7, 14, 15]);
Sourcepub fn iter_cloned(&self) -> impl Iterator<Item = T> + '_where
T: Clone,
pub fn iter_cloned(&self) -> impl Iterator<Item = T> + '_where
T: Clone,
Returns an iterator to cloned values of the elements of the slice.
Note that slice.iter_cloned()
is short-hand for slice.iter().map(|elem| elem.cloned())
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend([0, 42, 7, 3]);
let slice = vec.slice(1..=2);
let mut iter = slice.iter_cloned();
assert_eq!(iter.next(), Some(42));
assert_eq!(iter.next(), Some(7));
assert_eq!(iter.next(), None);
let sum: i32 = slice.iter_cloned().sum();
assert_eq!(sum, 49);
Source§impl<'a, T, P> ConcurrentSlice<'a, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<'a, T, P> ConcurrentSlice<'a, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Sourcepub fn split_at(
&'a self,
mid: usize,
) -> (ConcurrentSlice<'a, T, P>, ConcurrentSlice<'a, T, P>)
pub fn split_at( &'a self, mid: usize, ) -> (ConcurrentSlice<'a, T, P>, ConcurrentSlice<'a, T, P>)
Divides one slice into two at an index:
- the first will contain elements in positions
[0, mid)
, - the second will contain elements in positions
[mid, self.len())
.
§Panics
Panics if mid > self.len()
.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter(0..8);
let slice = vec.as_slice();
let (a, b) = slice.split_at(3);
assert_eq!(a, [0, 1, 2]);
assert_eq!(b, [3, 4, 5, 6, 7]);
Sourcepub fn split_first(
&self,
) -> Option<(&ConcurrentElement<T>, ConcurrentSlice<'_, T, P>)>
pub fn split_first( &self, ) -> Option<(&ConcurrentElement<T>, ConcurrentSlice<'_, T, P>)>
Returns the first and all the rest of the elements of the slice, or None if it is empty.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter(0..4);
let slice = vec.as_slice();
let (a, b) = slice.split_first().unwrap();
assert_eq!(a, &0);
assert_eq!(b, [1, 2, 3]);
// empty
let slice = vec.slice(0..0);
assert!(slice.split_first().is_none());
// single element
let slice = vec.slice(2..3);
let (a, b) = slice.split_first().unwrap();
assert_eq!(a, &2);
assert_eq!(b, []);
Sourcepub fn split_last(
&self,
) -> Option<(&ConcurrentElement<T>, ConcurrentSlice<'_, T, P>)>
pub fn split_last( &self, ) -> Option<(&ConcurrentElement<T>, ConcurrentSlice<'_, T, P>)>
Returns the last and all the rest of the elements of the slice, or None if it is empty.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter(0..4);
let slice = vec.as_slice();
let (a, b) = slice.split_last().unwrap();
assert_eq!(a, &3);
assert_eq!(b, [0, 1, 2]);
// empty
let slice = vec.slice(0..0);
assert!(slice.split_last().is_none());
// single element
let slice = vec.slice(2..3);
let (a, b) = slice.split_last().unwrap();
assert_eq!(a, &2);
assert_eq!(b, []);
Sourcepub fn chunks(
&'a self,
chunk_size: usize,
) -> impl ExactSizeIterator<Item = ConcurrentSlice<'a, T, P>>
pub fn chunks( &'a self, chunk_size: usize, ) -> impl ExactSizeIterator<Item = ConcurrentSlice<'a, T, P>>
Returns an iterator over chunk_size
elements of the slice at a time, starting at the beginning of the slice.
The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last chunk will not have length chunk_size.
§Panics
Panics if chunk_size is 0.
§Examples
use orx_concurrent_vec::*;
let vec: ConcurrentVec<_> = ['l', 'o', 'r', 'e', 'm'].into_iter().collect();
let slice = vec.as_slice();
let mut iter = slice.chunks(2);
assert_eq!(iter.next().unwrap(), ['l', 'o']);
assert_eq!(iter.next().unwrap(), ['r', 'e']);
assert_eq!(iter.next().unwrap(), ['m']);
assert!(iter.next().is_none());
Source§impl<T, P> ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<T, P> ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Sourcepub fn clone_to_vec(&self) -> Vec<T>where
T: Clone,
pub fn clone_to_vec(&self) -> Vec<T>where
T: Clone,
Clones the values of elements of the slice into a regular vector.
Source§impl<T, P> ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<T, P> ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Sourcepub fn get_raw(&self, i: usize) -> Option<*const T>
pub fn get_raw(&self, i: usize) -> Option<*const T>
Returns:
- a raw
*const T
pointer to the underlying data if element at thei
-th position is pushed, None
otherwise.
§Safety
Please see below the safety guarantees and potential safety risks using the pointer obtained by this method.
§Safety Guarantees
Pointer obtained by this method will be valid:
ConcurrentVec
prevents access to elements which are not added yet.ConcurrentOption
wrapper prevents access during initialization, and hence, prevents data race during initialization.PinnedVec
storage makes sure that memory location of the elements never change.
Therefore, the caller can hold on the obtained pointer throughout the lifetime of the vec. It is guaranteed that it will be valid pointing to the correct position with initialized data.
§Unsafe Bits
However, this method still leaks out a pointer, using which can cause data races as follows:
- The value of the position can be
replace
d orset
orupdate
d concurrently by another thread. - If at the same instant, we attempt to read using this pointer, we would end up with a data-race.
§Safe Usage
This method can be safely used as long as the caller is able to guarantee that the position will not be being mutated while using the pointer to directly access the data.
A common use case to this is the grow-only scenarios where added elements are not mutated:
- elements can be added to the vector by multiple threads,
- while already pushed elements can safely be accessed by other threads using
get_raw
.
Sourcepub unsafe fn get_ref(&self, i: usize) -> Option<&T>
pub unsafe fn get_ref(&self, i: usize) -> Option<&T>
Returns a reference to the element at the i
-th position of the vec.
It returns None
if index is out of bounds.
§Safety
All methods that return &T
or &mut T
references are marked as unsafe.
Please see the reason and possible scenarios to use it safely below.
§Safety Guarantees
Reference obtained by this method will be valid:
ConcurrentVec
prevents access to elements which are not added yet.ConcurrentOption
wrapper prevents access during initialization, and hence, prevents data race during initialization.PinnedVec
storage makes sure that memory location of the elements never change.
Therefore, the caller can hold on the obtained reference throughout the lifetime of the vec. It is guaranteed that the reference will be valid pointing to the correct position.
§Unsafe Bits
However, this method still leaks out a reference, which can cause data races as follows:
- The value of the position can be
replace
d orset
orupdate
d concurrently by another thread. - If at the same instant, we attempt to read using this reference, we would end up with a data-race.
§Safe Usage
This method can be safely used as long as the caller is able to guarantee that the position will not be being mutated while using the reference to directly access the data.
A common use case to this is the grow-only scenarios where added elements are not mutated:
- elements can be added to the vector by multiple threads,
- while already pushed elements can safely be accessed by other threads using
get
.
§Examples
As explained above, the following constructs a safe usage example of the unsafe get method.
use orx_concurrent_vec::*;
use std::time::Duration;
#[derive(Debug, Default)]
struct Metric {
sum: i32,
count: i32,
}
impl Metric {
fn aggregate(self, value: &i32) -> Self {
Self {
sum: self.sum + value,
count: self.count + 1,
}
}
}
// record measurements in random intervals, roughly every 2ms
let measurements = ConcurrentVec::new();
// collect metrics every 100 milliseconds
let metrics = ConcurrentVec::new();
std::thread::scope(|s| {
// thread to store measurements as they arrive
s.spawn(|| {
for i in 0..100 {
std::thread::sleep(Duration::from_millis(i % 5));
// collect measurements and push to measurements vec
measurements.push(i as i32);
}
});
// thread to collect metrics every 100 milliseconds
s.spawn(|| {
for _ in 0..10 {
// safely read from measurements vec to compute the metric
// since pushed elements are not being mutated
let len = measurements.len();
let mut metric = Metric::default();
for i in 0..len {
if let Some(value) = unsafe { measurements.get_ref(i) } {
metric = metric.aggregate(value);
}
}
// push result to metrics
metrics.push(metric);
std::thread::sleep(Duration::from_millis(100));
}
});
});
let measurements: Vec<_> = measurements.to_vec();
let averages: Vec<_> = metrics.to_vec();
assert_eq!(measurements.len(), 100);
assert_eq!(averages.len(), 10);
Sourcepub unsafe fn iter_ref(&self) -> impl Iterator<Item = &T>
pub unsafe fn iter_ref(&self) -> impl Iterator<Item = &T>
Returns an iterator to references of elements of the vec.
See also iter
and iter_cloned
for thread-safe alternatives of concurrent access to elements.
§Safety
All methods that return &T
or &mut T
references are marked as unsafe.
Please see the reason and possible scenarios to use it safely below.
§Safety Guarantees
References obtained by this method will be valid:
ConcurrentVec
prevents access to elements which are not added yet.ConcurrentOption
wrapper prevents access during initialization, and hence, prevents data race during initialization.PinnedVec
storage makes sure that memory location of the elements never change.
Therefore, the caller can hold on the obtained references throughout the lifetime of the vec. It is guaranteed that the references will be valid pointing to the correct positions.
§Unsafe Bits
However, this method still leaks out references that can cause data races as follows:
- Values of elements in the vector can be concurrently mutated by methods such as
replace
orupdate
by other threads. - If at the same instant, we attempt to read using these references, we would end up with a data-race.
§Safe Usage
This method can be safely used as long as the caller is able to guarantee that the position will not be being mutated while using these references to directly access the data.
A common use case to this is the grow-only scenarios where added elements are not mutated:
- elements can be added to the vector by multiple threads,
- while already pushed elements can safely be accessed by other threads using
iter
.
§Examples
As explained above, the following constructs a safe usage example of the unsafe iter method.
use orx_concurrent_vec::*;
use std::time::Duration;
#[derive(Debug, Default)]
struct Metric {
sum: i32,
count: i32,
}
impl Metric {
fn aggregate(self, value: &i32) -> Self {
Self {
sum: self.sum + value,
count: self.count + 1,
}
}
}
// record measurements in random intervals, roughly every 2ms
let measurements = ConcurrentVec::new();
// collect metrics every 100 milliseconds
let metrics = ConcurrentVec::new();
std::thread::scope(|s| {
// thread to store measurements as they arrive
s.spawn(|| {
for i in 0..100 {
std::thread::sleep(Duration::from_millis(i % 5));
// collect measurements and push to measurements vec
measurements.push(i as i32);
}
});
// thread to collect metrics every 100 milliseconds
s.spawn(|| {
for _ in 0..10 {
// safely read from measurements vec to compute the metric
// since pushed elements are never mutated
let metric = unsafe {
measurements
.iter_ref()
.fold(Metric::default(), |x, value| x.aggregate(value))
};
// push result to metrics
metrics.push(metric);
std::thread::sleep(Duration::from_millis(100));
}
});
});
let measurements: Vec<_> = measurements.to_vec();
let averages: Vec<_> = metrics.to_vec();
assert_eq!(measurements.len(), 100);
assert_eq!(averages.len(), 10);
Sourcepub fn get_raw_mut(&self, i: usize) -> Option<*mut T>
pub fn get_raw_mut(&self, i: usize) -> Option<*mut T>
Returns:
- a raw
*mut T
pointer to the underlying data if element at thei
-th position is pushed, None
otherwise.
§Safety
Please see below the safety guarantees and potential safety risks using the pointer obtained by this method.
§Safety Guarantees
Pointer obtained by this method will be valid:
ConcurrentVec
prevents access to elements which are not added yet.ConcurrentOption
wrapper prevents access during initialization, and hence, prevents data race during initialization.PinnedVec
storage makes sure that memory location of the elements never change.
Therefore, the caller can hold on the obtained pointer throughout the lifetime of the vec. It is guaranteed that it will be valid pointing to the correct position with initialized data.
§Unsafe Bits
However, this method still leaks out a pointer, using which can cause data races as follows:
- The value of the position can be
replace
d orset
orupdate
d concurrently by another thread. - If at the same instant, we attempt to read using this pointer, we would end up with a data-race.
§Safe Usage
This method can be safely used as long as the caller is able to guarantee that the position will not be being read or written by another thread while using the pointer to directly access the data.
Sourcepub unsafe fn get_mut(&self, i: usize) -> Option<&mut T>
pub unsafe fn get_mut(&self, i: usize) -> Option<&mut T>
Returns a mutable reference to the element at the i
-th position of the vec.
It returns None
if index is out of bounds.
See also get
and swap
for thread-safe alternatives of concurrent mutation of elements.
§Safety
All methods that leak out &T
or &mut T
references are marked as unsafe.
Please see the reason and possible scenarios to use it safely below.
§Safety Guarantees
Reference obtained by this method will be valid:
ConcurrentVec
prevents access to elements which are not added yet.ConcurrentOption
wrapper prevents access during initialization, and hence, prevents data race during initialization.PinnedVec
storage makes sure that memory location of the elements never change.
Therefore, the caller can hold on the obtained reference throughout the lifetime of the vec. It is guaranteed that the reference will be valid pointing to the correct position.
§Unsafe Bits
However, this method still leaks out a reference, which can cause data races as follows:
- The value of the position can be
replace
d orset
orupdate
d concurrently by another thread. - And it maybe read by safe access methods such as
map
orcloned
. - If at the same instant, we attempt to read or write using this reference, we would end up with a data-race.
§Safe Usage
This method can be safely used as long as the caller is able to guarantee that the position will not be being read or written by another thread while using the reference to directly access the data.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::new();
vec.extend(['a', 'b', 'c', 'd']);
assert_eq!(unsafe { vec.get_mut(4) }, None);
*unsafe { vec.get_mut(1).unwrap() } = 'x';
assert_eq!(unsafe { vec.get_ref(1) }, Some(&'x'));
assert_eq!(&vec, &['a', 'x', 'c', 'd']);
Sourcepub unsafe fn iter_mut(&self) -> impl Iterator<Item = &mut T>
pub unsafe fn iter_mut(&self) -> impl Iterator<Item = &mut T>
Returns an iterator to mutable references of elements of the vec.
See also iter
, fill
and fill_with
for thread-safe alternatives of concurrent mutation of elements.
§Safety
All methods that leak out &T
or &mut T
references are marked as unsafe.
Please see the reason and possible scenarios to use it safely below.
§Safety Guarantees
References obtained by this method will be valid:
ConcurrentVec
prevents access to elements which are not added yet.ConcurrentOption
wrapper prevents access during initialization, and hence, prevents data race during initialization.PinnedVec
storage makes sure that memory location of the elements never change.
Therefore, the caller can hold on the obtained references throughout the lifetime of the vec. It is guaranteed that the references will be valid pointing to the correct position.
§Unsafe Bits
However, this method still leaks out references, which can cause data races as follows:
- Values of elements can be concurrently read by other threads.
- Likewise, they can be concurrently mutated by thread-safe mutation methods.
- If at the same instant, we attempt to read or write using these references, we would end up with a data-race.
§Safe Usage
This method can be safely used as long as the caller is able to guarantee that the elements will not be being read or written by another thread while using the reference to directly access the data.
§Examples
use orx_concurrent_vec::*;
let vec = ConcurrentVec::from_iter([0, 1, 2, 3]);
let iter = unsafe { vec.iter_mut() };
for x in iter {
*x *= 2;
}
assert_eq!(&vec, &[0, 2, 4, 6]);
Trait Implementations§
Source§impl<'a, T: Clone, P> Clone for ConcurrentSlice<'a, T, P>
impl<'a, T: Clone, P> Clone for ConcurrentSlice<'a, T, P>
Source§fn clone(&self) -> ConcurrentSlice<'a, T, P>
fn clone(&self) -> ConcurrentSlice<'a, T, P>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl<T, P> Debug for ConcurrentSlice<'_, T, P>
impl<T, P> Debug for ConcurrentSlice<'_, T, P>
Source§impl<P, T> Index<usize> for ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
impl<P, T> Index<usize> for ConcurrentSlice<'_, T, P>where
P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
Source§fn index(&self, i: usize) -> &Self::Output
fn index(&self, i: usize) -> &Self::Output
Returns a reference to the concurrent element at the i-th position of the slice.
Note that slice[i]
is a shorthand for slice.get(i).unwrap()
.
§Panics
Panics if i is out of bounds.