use std::fmt::{self, Display};
use crate::bytecode_tape::{BtapeThreadLocal, BytecodeTape, CustomOpHandle, CONSTANT};
use crate::float::Float;
#[cfg(debug_assertions)]
pub(crate) const TAPE_ID_UNTRACKED: u64 = 0;
#[inline]
pub(crate) fn ensure_on_tape<F: Float>(x: &BReverse<F>, tape: &mut BytecodeTape<F>) -> u32 {
#[cfg(debug_assertions)]
x.debug_assert_same_tape(tape);
if x.index == CONSTANT {
tape.push_const(x.value)
} else {
x.index
}
}
impl<F: Float> BytecodeTape<F> {
pub(crate) fn new_inputs(&mut self, x: &[F]) -> Vec<BReverse<F>> {
x.iter()
.map(|&val| {
let idx = self.new_input(val);
BReverse::from_tape_of(self, val, idx)
})
.collect()
}
}
#[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> From<F> for BReverse<F> {
#[inline]
fn from(val: F) -> Self {
BReverse::constant(val)
}
}
impl<F: Float> BReverse<F> {
#[inline]
#[must_use]
pub fn constant(value: F) -> Self {
BReverse {
value,
index: CONSTANT,
#[cfg(debug_assertions)]
tape_id: TAPE_ID_UNTRACKED,
}
}
#[inline]
#[must_use]
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| {
let xi = ensure_on_tape(&self, t);
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| {
let li = ensure_on_tape(&self, t);
let ri = ensure_on_tape(&other, t);
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())
}
}