pub struct LVec<T: Clone + Send + Sync + 'static> { /* private fields */ }Expand description
A parallelized vector container with deferred execution.
LVec is the main data structure in Leopard. It represents a vector that
supports parallel operations through deferred execution. Operations on LVec
are recorded when called between LQueue::start and LQueue::end, and
executed in bulk when end() is called.
§Creating LVec
LVec instances must be created through an LQueue:
use leopard::{LQueue, LVec};
let q = LQueue::new();
let vec: LVec<f64> = q.lvec_with_capacity(1000);§Operations
All operations must be called between q.start() and q.end():
- Initialization:
fill,fill_with - Transformation:
map,map_where - Arithmetic:
+,-,*,/operators - Masking:
blend,masked_apply,masked_fill
§Retrieving Results
After q.end(), use materialize to get the computed data:
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<f64> = q.lvec_with_capacity(10);
q.start();
let x = x.fill_with(|i| i as f64);
q.end();
let data = x.materialize().unwrap();
println!("{:?}", &data[..]);§Pending State
After an operation is recorded, the resulting LVec is in a “pending” state.
The actual data is not available until after q.end() is called and
materialize is used to retrieve it.
Implementations§
Source§impl<T: Clone + Send + Sync + 'static> LVec<T>
impl<T: Clone + Send + Sync + 'static> LVec<T>
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the length of the vector.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let vec: LVec<f64> = q.lvec_with_capacity(100);
assert_eq!(vec.len(), 100);Sourcepub fn is_pending(&self) -> bool
pub fn is_pending(&self) -> bool
Returns true if this vector has a pending operation.
A pending vector’s data is not yet available. Call materialize
after LQueue::end to retrieve the computed data.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<f64> = q.lvec_with_capacity(10);
assert!(!x.is_pending());
q.start();
let y = x.fill(1.0);
assert!(y.is_pending());
q.end();Sourcepub fn materialize(&self) -> Option<Arc<Vec<T>>>
pub fn materialize(&self) -> Option<Arc<Vec<T>>>
Retrieves the computed data after LQueue::end has been called.
For pending vectors (those created by operations), this returns the computed result. For non-pending vectors, this returns the original data.
§Returns
Some(Arc<Vec<T>>)if the data is availableNoneif the vector is pending andq.end()hasn’t been called
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<f64> = q.lvec_with_capacity(5);
q.start();
let x = x.fill_with(|i| i as f64 * 2.0);
q.end();
let data = x.materialize().unwrap();
assert_eq!(&data[..], &[0.0, 2.0, 4.0, 6.0, 8.0]);Sourcepub fn as_slice(&self) -> &[T]
pub fn as_slice(&self) -> &[T]
Returns the data as a slice.
§Warning
For pending vectors, this returns an empty or default-initialized slice,
not the computed result. Use materialize after
LQueue::end to get the actual computed data.
Sourcepub fn fill_with<F>(&self, f: F) -> Self
pub fn fill_with<F>(&self, f: F) -> Self
Fills the vector using a closure that takes an index.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
f- A closure that takes an indexusizeand returns the valueT
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<f64> = q.lvec_with_capacity(5);
q.start();
let x = x.fill_with(|i| i as f64 * 10.0);
q.end();
let data = x.materialize().unwrap();
assert_eq!(&data[..], &[0.0, 10.0, 20.0, 30.0, 40.0]);Sourcepub fn fill(&self, value: T) -> Self
pub fn fill(&self, value: T) -> Self
Fills the vector with a constant value.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
value- The value to fill the vector with
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<i32> = q.lvec_with_capacity(5);
q.start();
let x = x.fill(42);
q.end();
let data = x.materialize().unwrap();
assert_eq!(&data[..], &[42, 42, 42, 42, 42]);Sourcepub fn map<F>(&self, f: F) -> Self
pub fn map<F>(&self, f: F) -> Self
Transforms each element using a closure.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
f- A closure that takes an index and a reference to the element, and returns the transformed value
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<f64> = q.lvec_with_capacity(5);
q.start();
let x = x.fill_with(|i| i as f64);
let y = x.map(|_, v| v * v); // Square each element
q.end();
let data = y.materialize().unwrap();
assert_eq!(&data[..], &[0.0, 1.0, 4.0, 9.0, 16.0]);Sourcepub fn map_where<C, TF, FF>(
&self,
condition: C,
if_true: TF,
if_false: FF,
) -> Self
pub fn map_where<C, TF, FF>( &self, condition: C, if_true: TF, if_false: FF, ) -> Self
Applies different transformations based on a condition.
For each element, if the condition returns true, if_true is applied;
otherwise, if_false is applied. This is SIMD-style branchless conditional
execution.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
condition- A closure that returnstrueorfalsefor each elementif_true- Transformation to apply when condition istrueif_false- Transformation to apply when condition isfalse
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<i32> = q.lvec_with_capacity(6);
q.start();
let x = x.fill_with(|i| i as i32 + 1);
let y = x.map_where(
|_, v| *v % 2 == 0, // Is even?
|_, v| v * 10, // If even: multiply by 10
|_, v| v + 1000, // If odd: add 1000
);
q.end();
let data = y.materialize().unwrap();
// [1, 2, 3, 4, 5, 6] -> [1001, 20, 1003, 40, 1005, 60]Sourcepub fn mask<F>(&self, predicate: F) -> LMask
pub fn mask<F>(&self, predicate: F) -> LMask
Creates a mask from a predicate applied to each element.
Unlike other operations, this executes immediately (not recorded) because masks are needed to define subsequent masking operations.
§Arguments
predicate- A closure that returnstrueorfalsefor each element
§Warning
This only works on non-pending vectors. For pending vectors, use
LMask::from_fn with the appropriate pattern.
§Examples
use leopard::{LQueue, LVec};
let q = LQueue::new();
let x: LVec<i32> = q.lvec_with_capacity(10);
// Note: mask() works on the initial (non-pending) vector
let mask = x.mask(|i, _| i >= 5);Sourcepub fn blend(&self, other: &Self, mask: &LMask) -> Self
pub fn blend(&self, other: &Self, mask: &LMask) -> Self
Blends two vectors using a mask (SIMD-style select).
For each element, if the mask is true, the value from other is used;
otherwise, the value from self is used.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
other- The vector to blend withmask- The mask determining which vector to select from
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec, LMask};
let q = LQueue::new();
let a: LVec<i32> = q.lvec_with_capacity(5);
let b: LVec<i32> = q.lvec_with_capacity(5);
let mask = LMask::from_fn(5, |i| i >= 3);
q.start();
let a = a.fill(1);
let b = b.fill(100);
let c = a.blend(&b, &mask);
q.end();
let data = c.materialize().unwrap();
// mask: [false, false, false, true, true]
// result: [1, 1, 1, 100, 100]Sourcepub fn select(mask: &LMask, if_true: &Self, if_false: &Self) -> Self
pub fn select(mask: &LMask, if_true: &Self, if_false: &Self) -> Self
Selects between two vectors based on a mask.
This is equivalent to if_false.blend(if_true, mask).
§Arguments
mask- The mask determining which vector to select fromif_true- Values to use where mask istrueif_false- Values to use where mask isfalse
§Panics
Panics if called outside of a start()/end() block.
Sourcepub fn masked_apply<F>(&self, mask: &LMask, f: F) -> Self
pub fn masked_apply<F>(&self, mask: &LMask, f: F) -> Self
Applies a function only where the mask is true.
Elements where the mask is false retain their original values.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
mask- The mask determining where to apply the functionf- The function to apply
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec, LMask};
let q = LQueue::new();
let x: LVec<i32> = q.lvec_with_capacity(5);
let mask = LMask::from_fn(5, |i| i >= 3);
q.start();
let x = x.fill_with(|i| i as i32);
let y = x.masked_apply(&mask, |_, v| v * 100);
q.end();
let data = y.materialize().unwrap();
// [0, 1, 2, 3, 4] with mask [F, F, F, T, T]
// result: [0, 1, 2, 300, 400]Sourcepub fn masked_fill(&self, mask: &LMask, value: T) -> Selfwhere
T: 'static,
pub fn masked_fill(&self, mask: &LMask, value: T) -> Selfwhere
T: 'static,
Fills with a constant value only where the mask is true.
Elements where the mask is false retain their original values.
This is a recorded operation that must be called between LQueue::start
and LQueue::end.
§Arguments
mask- The mask determining where to fillvalue- The value to fill with
§Panics
Panics if called outside of a start()/end() block.
§Examples
use leopard::{LQueue, LVec, LMask};
let q = LQueue::new();
let x: LVec<i32> = q.lvec_with_capacity(5);
let mask = LMask::from_fn(5, |i| i >= 3);
q.start();
let x = x.fill_with(|i| i as i32);
let y = x.masked_fill(&mask, 999);
q.end();
let data = y.materialize().unwrap();
// [0, 1, 2, 3, 4] with mask [F, F, F, T, T]
// result: [0, 1, 2, 999, 999]Trait Implementations§
Source§impl<T: Clone + Send + Sync + 'static> Index<usize> for LVec<T>
impl<T: Clone + Send + Sync + 'static> Index<usize> for LVec<T>
Source§fn index(&self, index: usize) -> &Self::Output
fn index(&self, index: usize) -> &Self::Output
Accesses the element at the given index.
§Warning
For pending vectors, this accesses the original (uncomputed) data,
not the result of the pending operation. Use materialize
after LQueue::end to get the computed data.
§Panics
Panics if index >= self.len().
Auto Trait Implementations§
impl<T> Freeze for LVec<T>
impl<T> !RefUnwindSafe for LVec<T>
impl<T> !Send for LVec<T>
impl<T> !Sync for LVec<T>
impl<T> Unpin for LVec<T>
impl<T> !UnwindSafe for LVec<T>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more