use super::{bool_tweak, read_binary, read_unary, tweak, write_u32};
macro_rules! arith_mut {
($name:ident, $good:expr) => {
#[inline]
pub(crate) fn $name<const P: u32, const M: u8>(input: &[u8]) -> Vec<u8> {
let (a, b) = read_binary(input);
let good = $good(a, b);
if a == P {
write_u32(tweak(good, M))
} else {
write_u32(good)
}
}
};
}
arith_mut!(add_arith_mut, |a: u32, b: u32| a.wrapping_add(b));
arith_mut!(sub_arith_mut, |a: u32, b: u32| a.wrapping_sub(b));
arith_mut!(mul_arith_mut, |a: u32, b: u32| a.wrapping_mul(b));
arith_mut!(div_arith_mut, |a: u32, b: u32| if b == 0 {
0
} else {
a / b
});
arith_mut!(mod_arith_mut, |a: u32, b: u32| if b == 0 {
0
} else {
a % b
});
macro_rules! bit_mut_binary {
($name:ident, $good:expr) => {
#[inline]
pub(crate) fn $name<const P: u32, const M: u8>(input: &[u8]) -> Vec<u8> {
let (a, b) = read_binary(input);
let good = $good(a, b);
if a == P {
write_u32(tweak(good, M))
} else {
write_u32(good)
}
}
};
}
bit_mut_binary!(and_bit_mut, |a: u32, b: u32| a & b);
bit_mut_binary!(or_bit_mut, |a: u32, b: u32| a | b);
bit_mut_binary!(xor_bit_mut, |a: u32, b: u32| a ^ b);
bit_mut_binary!(shl_bit_mut, |a: u32, b: u32| if b >= 32 {
0
} else {
a << b
});
bit_mut_binary!(shr_bit_mut, |a: u32, b: u32| if b >= 32 {
0
} else {
a >> b
});
#[inline]
pub(crate) fn not_bit_mut<const P: u32, const M: u8>(input: &[u8]) -> Vec<u8> {
let a = read_unary(input);
let good = !a;
if a == P {
write_u32(tweak(good, M))
} else {
write_u32(good)
}
}
macro_rules! cmp_mut {
($name:ident, $good:expr) => {
#[inline]
pub(crate) fn $name<const A: u32, const B: u32, const M: u8>(input: &[u8]) -> Vec<u8> {
let (a, b) = read_binary(input);
let good: u32 = u32::from($good(a, b));
if a == A && b == B {
write_u32(bool_tweak(good, M))
} else {
write_u32(good)
}
}
};
}
cmp_mut!(eq_cmp_mut, |a: u32, b: u32| a == b);
cmp_mut!(ne_cmp_mut, |a: u32, b: u32| a != b);
cmp_mut!(lt_cmp_mut, |a: u32, b: u32| a < b);
cmp_mut!(gt_cmp_mut, |a: u32, b: u32| a > b);
cmp_mut!(le_cmp_mut, |a: u32, b: u32| a <= b);
cmp_mut!(ge_cmp_mut, |a: u32, b: u32| a >= b);
macro_rules! law_mut_binary {
($name:ident, $good:expr) => {
#[inline]
pub(crate) fn $name<const A: u32, const B: u32, const M: u8>(input: &[u8]) -> Vec<u8> {
let (a, b) = read_binary(input);
let good = $good(a, b);
if a == A && b == B {
write_u32(tweak(good, M))
} else {
write_u32(good)
}
}
};
}
macro_rules! law_mut_unary {
($name:ident, $good:expr) => {
#[inline]
pub(crate) fn $name<const A: u32, const _B: u32, const M: u8>(input: &[u8]) -> Vec<u8> {
let a = read_unary(input);
let good = $good(a);
if a == A {
write_u32(tweak(good, M))
} else {
write_u32(good)
}
}
};
}
law_mut_binary!(xor_law_mut, |a: u32, b: u32| a ^ b);
law_mut_binary!(or_law_mut, |a: u32, b: u32| a | b);
law_mut_binary!(and_law_mut, |a: u32, b: u32| a & b);
law_mut_binary!(shl_law_mut, |a: u32, b: u32| if b >= 32 {
0
} else {
a << b
});
law_mut_binary!(shr_law_mut, |a: u32, b: u32| if b >= 32 {
0
} else {
a >> b
});
law_mut_binary!(rotl_law_mut, |a: u32, b: u32| a.rotate_left(b & 31));
law_mut_binary!(rotr_law_mut, |a: u32, b: u32| a.rotate_right(b & 31));
law_mut_binary!(extract_bits_law_mut, |a: u32, b: u32| {
let offset = b & 0x1F;
let count = (b >> 5) & 0x1F;
if count == 0 {
0
} else {
(a >> offset) & ((1u32 << count.min(31)) - 1)
}
});
law_mut_binary!(insert_bits_law_mut, |a: u32, b: u32| {
let offset = a & 0x1F;
let count = (a >> 5) & 0x1F;
let newbits = a >> 10;
if count == 0 {
b
} else {
let clamped_count = count.min(32 - offset);
let mask = if clamped_count >= 32 {
u32::MAX
} else {
(1u32 << clamped_count) - 1
};
(b & !(mask << offset)) | ((newbits & mask) << offset)
}
});
law_mut_binary!(add_law_mut, |a: u32, b: u32| a.wrapping_add(b));
law_mut_binary!(sub_law_mut, |a: u32, b: u32| a.wrapping_sub(b));
law_mut_binary!(mul_law_mut, |a: u32, b: u32| a.wrapping_mul(b));
law_mut_binary!(div_law_mut, |a: u32, b: u32| if b == 0 { 0 } else { a / b });
law_mut_binary!(mod_law_mut, |a: u32, b: u32| if b == 0 { 0 } else { a % b });
law_mut_binary!(min_law_mut, |a: u32, b: u32| a.min(b));
law_mut_binary!(max_law_mut, |a: u32, b: u32| a.max(b));
law_mut_binary!(clamp_law_mut, |a: u32, b: u32| {
let low = b & 0xFFFF;
let high = (b >> 16) | low;
a.clamp(low, high)
});
law_mut_binary!(eq_law_mut, |a: u32, b: u32| u32::from(a == b));
law_mut_binary!(ne_law_mut, |a: u32, b: u32| u32::from(a != b));
law_mut_binary!(lt_law_mut, |a: u32, b: u32| u32::from(a < b));
law_mut_binary!(gt_law_mut, |a: u32, b: u32| u32::from(a > b));
law_mut_binary!(le_law_mut, |a: u32, b: u32| u32::from(a <= b));
law_mut_binary!(ge_law_mut, |a: u32, b: u32| u32::from(a >= b));
law_mut_binary!(select_law_mut, |a: u32, b: u32| if b == 0 { 0 } else { a });
law_mut_unary!(not_law_mut, |a: u32| !a);
law_mut_unary!(popcount_law_mut, |a: u32| a.count_ones());
law_mut_unary!(popcount_sw_law_mut, |a: u32| a.count_ones());
law_mut_unary!(clz_law_mut, |a: u32| a.leading_zeros());
law_mut_unary!(ctz_law_mut, |a: u32| a.trailing_zeros());
law_mut_unary!(reverse_bits_law_mut, |a: u32| a.reverse_bits());
law_mut_unary!(abs_law_mut, |a: u32| (a as i32).wrapping_abs() as u32);
law_mut_unary!(negate_law_mut, |a: u32| a.wrapping_neg());