use std::fmt::{self, Display};
use crate::bytecode_tape::{BtapeThreadLocal, CustomOpHandle, CONSTANT};
use crate::float::Float;
#[cfg(debug_assertions)]
pub(crate) const TAPE_ID_UNTRACKED: u64 = 0;
#[derive(Clone, Copy, Debug)]
pub struct BReverse<F: Float> {
pub(crate) value: F,
pub(crate) index: u32,
#[cfg(debug_assertions)]
pub(crate) tape_id: u64,
}
impl<F: Float> BReverse<F> {
#[inline]
pub fn constant(value: F) -> Self {
BReverse {
value,
index: CONSTANT,
#[cfg(debug_assertions)]
tape_id: TAPE_ID_UNTRACKED,
}
}
#[inline]
pub fn from_tape(value: F, index: u32) -> Self {
BReverse {
value,
index,
#[cfg(debug_assertions)]
tape_id: TAPE_ID_UNTRACKED,
}
}
#[inline]
pub(crate) fn from_tape_of(
tape: &crate::bytecode_tape::BytecodeTape<F>,
value: F,
index: u32,
) -> Self {
#[cfg(not(debug_assertions))]
let _ = tape;
BReverse {
value,
index,
#[cfg(debug_assertions)]
tape_id: tape.tape_id,
}
}
#[inline]
pub(crate) fn from_active_recording(value: F, index: u32) -> Self
where
F: BtapeThreadLocal,
{
BReverse {
value,
index,
#[cfg(debug_assertions)]
tape_id: crate::bytecode_tape::active_btape_id::<F>(),
}
}
#[cfg(debug_assertions)]
#[inline]
pub(crate) fn debug_assert_same_tape(&self, tape: &crate::bytecode_tape::BytecodeTape<F>) {
if self.index != CONSTANT && self.tape_id != TAPE_ID_UNTRACKED {
assert_eq!(
self.tape_id, tape.tape_id,
"BReverse value from another recording used on the active tape: values must \
not cross record() boundaries, nested recordings, or threads"
);
}
}
#[inline]
pub fn index(&self) -> u32 {
self.index
}
pub fn custom_unary(self, handle: CustomOpHandle, value: F) -> Self
where
F: BtapeThreadLocal,
{
let index = crate::bytecode_tape::with_active_btape(|t| {
#[cfg(debug_assertions)]
self.debug_assert_same_tape(t);
let xi = if self.index == CONSTANT {
t.push_const(self.value)
} else {
self.index
};
t.push_custom_unary(xi, handle, value)
});
BReverse::from_active_recording(value, index)
}
pub fn custom_binary(self, other: Self, handle: CustomOpHandle, value: F) -> Self
where
F: BtapeThreadLocal,
{
let index = crate::bytecode_tape::with_active_btape(|t| {
#[cfg(debug_assertions)]
{
self.debug_assert_same_tape(t);
other.debug_assert_same_tape(t);
}
let li = if self.index == CONSTANT {
t.push_const(self.value)
} else {
self.index
};
let ri = if other.index == CONSTANT {
t.push_const(other.value)
} else {
other.index
};
t.push_custom_binary(li, ri, handle, value)
});
BReverse::from_active_recording(value, index)
}
}
impl<F: Float> Display for BReverse<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
}
}
impl<F: Float> Default for BReverse<F> {
fn default() -> Self {
BReverse::constant(F::zero())
}
}