#![cfg_attr(all(feature = "nightly", test), feature(test))]
#[cfg(all(feature = "nightly", test))]
extern crate test;
extern crate core;
pub mod bindings;
pub mod contracts;
pub mod expressions;
pub mod math;
pub mod shape_argument;
pub use bindings::StackEnvironment;
pub use contracts::{DimMatcher, ShapeContract};
pub use expressions::DimExpr;
pub use shape_argument::ShapeArgument;
#[macro_export]
macro_rules! run_every_nth {
($code:expr) => {
run_every_nth!(@internal 100, $code)
};
($lock:block) => {
run_every_nth!(@internal 100, $block)
};
($period:literal, $code:expr) => {
run_every_nth!(@internal $period, $code)
};
($period:literal, $lock:block) => {
run_every_nth!(@internal $period, $block)
};
(@internal $period:literal, $($tt:tt)*) => {{
static PERIOD: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(1);
static COUNTER: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
let target_period: usize = $period;
let period = PERIOD.load(std::sync::atomic::Ordering::Relaxed);
let count = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let test_val = count % period;
if test_val == 0 {
{ $($tt)* }
if period < target_period {
let new_period = (period * 2).clamp(1, target_period);
PERIOD.store(new_period, std::sync::atomic::Ordering::Relaxed);
}
if count > target_period * 1000 {
COUNTER.store(0, std::sync::atomic::Ordering::Relaxed);
}
}
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_run_every_nth_block() {
let mut results = Vec::new();
for i in 0..350 {
run_every_nth!({
results.push(i);
});
}
assert_eq!(results, vec![0, 2, 4, 8, 16, 32, 64, 100, 200, 300]);
}
#[test]
fn test_run_every_nth_expr() {
let mut results = Vec::new();
for i in 0..350 {
run_every_nth!(results.push(i));
}
assert_eq!(results, vec![0, 2, 4, 8, 16, 32, 64, 100, 200, 300]);
}
}