use std::ops::Mul;
// Imports used solely for doc tests
#[allow(unused_imports)]
use crate::{Row, RowBuf, Stage};
/// Data type representing the parity of a [`Row`]. To generate these, you probably want to use
/// [`Row::parity`]. Note that [`Row::parity`] always performs a heap allocation and is
/// linear-time in the [`Stage`] of the [`Row`]. If you are using `Parity`s as optimisations
/// within hot code I would recommend computing them upfront on your input [`Row`]s and then
/// tracking them by hand, probably using the [`*` operator](Parity::mul).
///
/// Note that it would be quite cheap for [`Row`]s to track their [`Parity`] all the time, but that
/// would result in less-than ideal data layouts and doesn't fit with the 'only pay for what you
/// use' design goal of this library.
#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Parity {
/// A given [`Row`] requires an **even** number of [`swap`](Row::swap)s to return to
/// [`rounds`](RowBuf::rounds). This is also often called _in course_ or _positive_. The
/// parity of [`rounds`](RowBuf::rounds) on every [`Stage`].
Even = 0,
/// A given [`Row`] requires an **odd** number of [`swap`](Row::swap)s to return to
/// [`rounds`](RowBuf::rounds). This is also often called _out of course_ or _negative_.
Odd = 1,
}
impl Parity {
/// Maps `true` to [`Parity::Even`] and `false` to [`Parity::Odd`]. On most machines, this
/// will not actually do anything and be removed by the compiler.
#[inline(always)]
pub fn from_is_odd(v: bool) -> Self {
match v {
false => Parity::Even,
true => Parity::Odd,
}
}
/// Returns the `Parity` of a given number.
#[inline(always)]
pub fn from_number(v: usize) -> Parity {
Self::from_is_odd(v % 2 != 0)
}
/// Returns the `Parity` of a given number.
#[inline(always)]
pub fn zero_or_one(self) -> u8 {
match self {
Parity::Even => 0,
Parity::Odd => 1,
}
}
/// Returns the `Parity` of a given number.
#[inline(always)]
pub fn plus_or_minus(self) -> char {
match self {
Parity::Even => '+',
Parity::Odd => '-',
}
}
}
impl Mul for Parity {
type Output = Self;
/// 'Multiply' two [`Parity`]s together (this corresponds to xor/uncarried addition where
/// `Even` is `0` and `Odd` is `1`). Also, if you have a [`Row`] `r1` with [`Parity`] `p1` and
/// another [`Row`] `r2` with [`Parity`] `p2` then `(r1 * r2).parity()` will always equal `p1 *
/// p2`. Thus, this can be used to convert calls to [`Row::parity`] into an extremely
/// cheap (likely single-cycle) update function.
#[inline(always)]
fn mul(self, rhs: Self) -> Self::Output {
Self::from_is_odd(self != rhs)
}
}
#[cfg(test)]
mod tests {
use crate::{RowBuf, Stage};
// In general, it's a bad idea to import enum variants directly, but in this case it makes our
// tests much terser
use super::Parity::{Even, Odd};
use super::*;
#[test]
fn mul() {
assert_eq!(Even * Even, Even);
assert_eq!(Even * Odd, Odd);
assert_eq!(Odd * Even, Odd);
assert_eq!(Odd * Odd, Even);
}
#[test]
fn from_number() {
assert_eq!(Parity::from_number(0), Even);
assert_eq!(Parity::from_number(1000), Even);
assert_eq!(Parity::from_number(1), Odd);
assert_eq!(Parity::from_number(47), Odd);
}
#[test]
fn row_parity() {
assert_eq!(RowBuf::rounds(Stage::TWO).parity(), Even);
assert_eq!(RowBuf::rounds(Stage::MAJOR).parity(), Even);
assert_eq!(RowBuf::parse("13245").unwrap().parity(), Odd);
assert_eq!(RowBuf::parse("231546").unwrap().parity(), Odd);
assert_eq!(RowBuf::parse("231564").unwrap().parity(), Even);
}
}