extern crate std;
use core::cell::Cell;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
use std::thread_local;
thread_local! {
static IN_SCOPE: Cell<bool> = const { Cell::new(false) };
static INIT_COUNT: Cell<usize> = const { Cell::new(0) };
static DROP_COUNT: Cell<usize> = const { Cell::new(0) };
static ADD_COUNT: Cell<usize> = const { Cell::new(0) };
static MUL_COUNT: Cell<usize> = const { Cell::new(0) };
}
#[derive(Debug)]
pub(crate) struct Scope(PhantomData<*const ()>);
#[derive(Debug, PartialEq)]
pub(crate) struct MockZeroSized(());
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct MockL<T>(pub(crate) T);
#[derive(Debug, Clone)]
pub(crate) struct MockR<T>(pub(crate) T);
#[derive(Debug, Clone)]
pub(crate) struct MockT<T>(pub(crate) T);
#[derive(Debug, Default, PartialEq)]
pub(crate) struct MockU<T>(pub(crate) T);
impl Scope {
pub(crate) fn with<F>(f: F)
where
F: FnOnce(&Scope),
{
assert!(!IN_SCOPE.replace(true), "nested scope is not allowed");
f(&Self(PhantomData));
IN_SCOPE.set(false);
INIT_COUNT.set(0);
DROP_COUNT.set(0);
ADD_COUNT.set(0);
MUL_COUNT.set(0);
}
pub(crate) fn init_count(&self) -> usize {
INIT_COUNT.get()
}
pub(crate) fn drop_count(&self) -> usize {
DROP_COUNT.get()
}
pub(crate) fn add_count(&self) -> usize {
ADD_COUNT.get()
}
pub(crate) fn mul_count(&self) -> usize {
MUL_COUNT.get()
}
}
impl MockZeroSized {
pub(crate) fn new() -> Self {
if IN_SCOPE.get() {
INIT_COUNT.with(|cell| cell.update(|count| count + 1));
}
Self(())
}
}
impl Default for MockZeroSized {
fn default() -> Self {
Self::new()
}
}
impl Clone for MockZeroSized {
fn clone(&self) -> Self {
Self::new()
}
}
impl Drop for MockZeroSized {
fn drop(&mut self) {
if IN_SCOPE.try_with(Cell::get) == Ok(true) {
let _ = DROP_COUNT.try_with(|cell| cell.update(|count| count + 1));
}
}
}
impl Add for MockZeroSized {
type Output = Self;
fn add(self, _: Self) -> Self::Output {
if IN_SCOPE.get() {
ADD_COUNT.with(|cell| cell.update(|count| count + 1));
}
Self::new()
}
}
impl Mul for MockZeroSized {
type Output = Self;
fn mul(self, _: Self) -> Self::Output {
if IN_SCOPE.get() {
MUL_COUNT.with(|cell| cell.update(|count| count + 1));
}
Self::new()
}
}
impl<L, R> PartialEq<MockR<R>> for MockL<L>
where
L: PartialEq<R>,
{
fn eq(&self, other: &MockR<R>) -> bool {
self.0 == other.0
}
}
impl<L, R, U> Add<MockR<R>> for MockL<L>
where
L: Add<R, Output = U>,
{
type Output = MockU<U>;
fn add(self, rhs: MockR<R>) -> Self::Output {
MockU(self.0 + rhs.0)
}
}
impl<L, R> AddAssign<MockR<R>> for MockL<L>
where
L: AddAssign<R>,
{
fn add_assign(&mut self, rhs: MockR<R>) {
self.0 += rhs.0;
}
}
impl<L, R, U> Sub<MockR<R>> for MockL<L>
where
L: Sub<R, Output = U>,
{
type Output = MockU<U>;
fn sub(self, rhs: MockR<R>) -> Self::Output {
MockU(self.0 - rhs.0)
}
}
impl<L, R> SubAssign<MockR<R>> for MockL<L>
where
L: SubAssign<R>,
{
fn sub_assign(&mut self, rhs: MockR<R>) {
self.0 -= rhs.0;
}
}
impl<L, R, U> Mul<MockR<R>> for MockL<L>
where
L: Mul<R, Output = U>,
{
type Output = MockU<U>;
fn mul(self, rhs: MockR<R>) -> Self::Output {
MockU(self.0 * rhs.0)
}
}
impl<T> Add for MockU<T>
where
T: Add<Output = T>,
{
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<T, U> Neg for MockT<T>
where
T: Neg<Output = U>,
{
type Output = MockU<U>;
fn neg(self) -> Self::Output {
MockU(-self.0)
}
}
#[macro_export]
macro_rules! dispatch_unary {
{ $block:block } => {{
use $crate::dense::order::{ColMajor, RowMajor};
{
type O = RowMajor;
$block
}
{
type O = ColMajor;
$block
}
}};
}
#[macro_export]
macro_rules! dispatch_binary {
{ $block:block } => {{
use $crate::dense::order::{ColMajor, RowMajor};
{
type O = RowMajor;
type P = RowMajor;
$block
}
{
type O = RowMajor;
type P = ColMajor;
$block
}
{
type O = ColMajor;
type P = RowMajor;
$block
}
{
type O = ColMajor;
type P = ColMajor;
$block
}
}};
}