Derive Macro lamellar_impl::ArrayOps
source · #[derive(ArrayOps)]
{
// Attributes available to this derive:
#[array_ops]
}
Expand description
This derive macro is intended to be used with the AmData attribute macro to enable a user defined type to be used in ActiveMessages.
§Examples
// this import includes everything we need
use lamellar::array::prelude::*;
#[lamellar::AmData(
// Lamellar traits
ArrayOps(Arithmetic,CompExEps,Shift), // needed to derive various LamellarArray Op traits (provided as a list)
Default, // needed to be able to initialize a LamellarArray
// Notice we use `lamellar::AmData` instead of `derive`
// for common traits, e.g. Debug, Clone.
PartialEq, // needed for CompareExchangeEpsilonOps
PartialOrd, // needed for CompareExchangeEpsilonOps
Debug, // any addition traits you want derived
Clone,
)]
struct Custom {
int: usize,
float: f32,
}
// We need to impl various arithmetic ops if we want to be able to
// perform remote arithmetic operations with this type
impl std::ops::AddAssign for Custom {
fn add_assign(&mut self, other: Self) {
*self = Self {
int: self.int + other.int,
float: self.float + other.float,
}
}
}
impl std::ops::SubAssign for Custom {
fn sub_assign(&mut self, other: Self) {
*self = Self {
int: self.int - other.int,
float: self.float - other.float,
}
}
}
impl std::ops::Sub for Custom {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
int: self.int - other.int,
float: self.float - other.float,
}
}
}
impl std::ops::MulAssign for Custom {
fn mul_assign(&mut self, other: Self) {
*self = Self {
int: self.int * other.int,
float: self.float * other.float,
}
}
}
impl std::ops::DivAssign for Custom {
fn div_assign(&mut self, other: Self) {
*self = Self {
int: self.int / other.int,
float: self.float / other.float,
}
}
}
impl std::ops::ShlAssign for Custom {
fn shl_assign(&mut self,other: Custom){
self.int <<= other.int;
}
}
impl std::ops::ShrAssign for Custom {
fn shr_assign(&mut self,other: Custom){
self.int >>= other.int;
}
}
fn main(){
// initialize
// -----------
let world = LamellarWorldBuilder::new().build(); // the world
let array = // the atomic distributed array
AtomicArray::<Custom>::new(&world,3,Distribution::Block);
println!();
println!("initialize a length-3 array:\n"); // print the entries
array.dist_iter()
.enumerate()
.for_each(|(i,entry)| println!("entry {:?}: {:?}", i, entry ) );
array.wait_all();
// call various operations on the array!
// -------------------------------------
world.block_on( async move { // we will just use the world as our future driver so we dont have to deal with cloneing array
println!();
println!("add (1, 0.01) to the first entry:\n");
let val = Custom{int: 1, float: 0.01};
array.add(0, val ).await;
array.dist_iter().enumerate().for_each(|(i,entry)| println!("entry {:?}: {:?}", i, entry ) );
array.wait_all();
println!();
println!("batch compare/exchange:");
let indices = vec![0,1,2,];
let current = val;
let new = Custom{int: 1, float: 0.0};
let epsilon = Custom{int: 0, float: 0.01};
let _results = array.batch_compare_exchange_epsilon(indices,current,new,epsilon).await;
println!();
println!("(1) the updatd array");
array.dist_iter().enumerate().for_each(|(i,entry)| println!("entry {:?}: {:?}", i, entry ) );
array.wait_all();
println!();
println!("(2) the return values");
for (i, entry) in _results.iter().enumerate() { println!("entry {:?}: {:?}", i, entry ) }
});
// inspect the results
// -------------------------------------
// NB: because thewe're working with multithreaded async
// environments, entries may be printed out of order
//
// initialize a length-3 array:
//
// entry 1: Custom { int: 0, float: 0.0 }
// entry 0: Custom { int: 0, float: 0.0 }
// entry 2: Custom { int: 0, float: 0.0 }
//
// add (1, 0.01) to the first entry:
//
// entry 0: Custom { int: 1, float: 0.01 }
// entry 2: Custom { int: 0, float: 0.0 }
// entry 1: Custom { int: 0, float: 0.0 }
//
// batch compare/exchange:
//
// (1) the updatd array
// entry 0: Custom { int: 1, float: 0.0 }
// entry 1: Custom { int: 0, float: 0.0 }
// entry 2: Custom { int: 0, float: 0.0 }
//
// (2) the return values
// entry 0: Ok(Custom { int: 1, float: 0.01 })
// entry 1: Err(Custom { int: 0, float: 0.0 })
// entry 2: Err(Custom { int: 0, float: 0.0 })
}