Struct ConcurrentSlice

Source
pub struct ConcurrentSlice<'a, T, P = SplitVec<ConcurrentElement<T>, Doubling>>{ /* 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>

Source

pub fn map<F, U>(&'a self, f: F) -> impl Iterator<Item = U> + 'a
where F: FnMut(&T) -> 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]);
Source

pub fn filter<F>( &self, f: F, ) -> impl Iterator<Item = &ConcurrentElement<T>> + '_
where F: FnMut(&T) -> bool + 'a,

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);
Source

pub fn fold<F, U>(&self, init: U, f: F) -> U
where F: FnMut(U, &T) -> 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);
Source

pub fn reduce<F>(&self, f: F) -> Option<T>
where T: Clone, F: FnMut(&T, &T) -> 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>

Source

pub fn swap(&self, i: usize, j: usize) -> bool

Swaps two elements in the slice.

Returns:

  • true of both i and j 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]);
Source

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]);
Source

pub fn fill_with<F>(&self, value: F)
where F: FnMut(usize) -> T,

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>

Source

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);
Source

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>

Source

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);
Source

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);
Source

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]);
Source

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]);
Source

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);
Source

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);
Source

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]);
Source

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>

Source

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]);
Source

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, []);
Source

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, []);
Source

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>

Source

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>

Source

pub fn get_raw(&self, i: usize) -> Option<*const T>

Returns:

  • a raw *const T pointer to the underlying data if element at the i-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 replaced or set or updated 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.
Source

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 replaced or set or updated 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);
Source

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 or update 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);
Source

pub fn get_raw_mut(&self, i: usize) -> Option<*mut T>

Returns:

  • a raw *mut T pointer to the underlying data if element at the i-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 replaced or set or updated 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.

Source

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 replaced or set or updated concurrently by another thread.
  • And it maybe read by safe access methods such as map or cloned.
  • 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']);
Source

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>

Source§

fn clone(&self) -> ConcurrentSlice<'a, T, P>

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T, P> Debug for ConcurrentSlice<'_, T, P>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<P, T> Index<usize> for ConcurrentSlice<'_, T, P>

Source§

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.

Source§

type Output = ConcurrentElement<T>

The returned type after indexing.
Source§

impl<T: PartialEq> PartialEq<[T]> for ConcurrentSlice<'_, T>

Source§

fn eq(&self, other: &[T]) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<const N: usize, T: PartialEq> PartialEq<[T; N]> for ConcurrentSlice<'_, T>

Source§

fn eq(&self, other: &[T; N]) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: PartialEq> PartialEq<ConcurrentSlice<'_, T>> for ConcurrentVec<T>

Source§

fn eq(&self, other: &ConcurrentSlice<'_, T>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: PartialEq> PartialEq<ConcurrentVec<T>> for ConcurrentSlice<'_, T>

Source§

fn eq(&self, other: &ConcurrentVec<T>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: PartialEq> PartialEq for ConcurrentSlice<'_, T>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<'a, T: Copy, P> Copy for ConcurrentSlice<'a, T, P>

Auto Trait Implementations§

§

impl<'a, T, P> Freeze for ConcurrentSlice<'a, T, P>

§

impl<'a, T, P = SplitVec<ConcurrentElement<T>>> !RefUnwindSafe for ConcurrentSlice<'a, T, P>

§

impl<'a, T, P> Send for ConcurrentSlice<'a, T, P>
where T: Sync,

§

impl<'a, T, P> Sync for ConcurrentSlice<'a, T, P>
where T: Sync,

§

impl<'a, T, P> Unpin for ConcurrentSlice<'a, T, P>

§

impl<'a, T, P = SplitVec<ConcurrentElement<T>>> !UnwindSafe for ConcurrentSlice<'a, T, P>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> SoM<T> for T

Source§

fn get_ref(&self) -> &T

Returns a reference to self.
Source§

fn get_mut(&mut self) -> &mut T

Returns a mutable reference to self.
Source§

impl<T> SoR<T> for T

Source§

fn get_ref(&self) -> &T

Returns a reference to self.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
OSZAR »