chiark / gitweb /
Restart without the trait system
authorSimon Tatham <anakin@pobox.com>
Fri, 11 Apr 2025 07:51:10 +0000 (08:51 +0100)
committerSimon Tatham <anakin@pobox.com>
Fri, 11 Apr 2025 07:51:10 +0000 (08:51 +0100)
src/finitenimber.rs
src/lib.rs

index 610fa3dfb5ea45068372e0f1a0719bcc350a91d1..51cfc68bbba7ec37b5e47019141d95dff321e24a 100644 (file)
@@ -1,54 +1,15 @@
-use std::fmt::Debug;
-use std::ops::BitXor;
+use std::ops::Add;
 
-pub trait FiniteNimberBase:
-    BitXor<Output = Self::Owned> + Eq + Debug + Sized
-{
-    type Cheap<'a>: FiniteNimberBase where Self: 'a;
-    type Owned: FiniteNimberBase + Clone;
+type Word = u64; // element type of the vectors we use
+const WORDLEVELS: usize = 6; // 2^{2^6} = 64 = size of Word
 
-    fn to_cheap<'a>(&'a self) -> Self::Cheap<'a>;
-    fn to_owned(self) -> Self::Owned;
-}
-
-impl FiniteNimberBase for u64 {
-    type Cheap<'a> = Self where Self: 'a;
-    type Owned = Self;
-
-    fn to_cheap<'a>(&'a self) -> Self::Cheap<'a> {
-        *self
-    }
-
-    fn to_owned(self) -> Self::Owned {
-        self
-    }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct IntVector(pub Vec<u64>);
-
-#[derive(PartialEq, Eq, Debug)]
-pub struct IntSlice<'a>(pub &'a [u64]);
-
-impl BitXor for IntVector {
-    type Output = Self;
-
-    fn bitxor(self, other: Self) -> Self {
-        Self(
-            self.0
-                .into_iter()
-                .zip(other.0.into_iter())
-                .map(|(a, b)| a ^ b)
-                .collect(),
-        )
-    }
-}
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+pub struct FiniteNimber(Vec<Word>);
 
-impl BitXor for IntSlice<'_> {
-    type Output = IntVector;
-
-    fn bitxor(self, other: Self) -> IntVector {
-        IntVector(
+impl Add<&FiniteNimber> for &FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: &FiniteNimber) -> FiniteNimber {
+        FiniteNimber(
             self.0
                 .iter()
                 .zip(other.0.iter())
@@ -58,47 +19,99 @@ impl BitXor for IntSlice<'_> {
     }
 }
 
-impl FiniteNimberBase for IntVector {
-    type Cheap<'a> = IntSlice<'a> where Self: 'a;
-    type Owned = IntVector;
-
-    fn to_cheap<'a>(&'a self) -> Self::Cheap<'a> {
-        IntSlice(&self.0)
+impl Add<&FiniteNimber> for FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: &FiniteNimber) -> FiniteNimber {
+        (&self) + other
     }
+}
 
-    fn to_owned(self) -> Self::Owned {
-        self
+impl Add<FiniteNimber> for &FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: FiniteNimber) -> FiniteNimber {
+        self + (&other)
     }
 }
 
-impl<'a> FiniteNimberBase for IntSlice<'a> {
-    type Cheap<'b> = IntSlice<'b> where Self: 'b;
-    type Owned = IntVector;
-
-    fn to_cheap<'b>(&'b self) -> Self::Cheap<'b> {
-        IntSlice(self.0)
+impl Add<FiniteNimber> for FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: FiniteNimber) -> FiniteNimber {
+        (&self) + (&other)
     }
+}
 
-    fn to_owned(self) -> Self::Owned {
-        IntVector(self.0.into())
+impl From<Word> for FiniteNimber {
+    fn from(val: Word) -> FiniteNimber {
+        FiniteNimber(vec![val])
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct FiniteNimber<T: FiniteNimberBase> {
-    n: T,
+#[derive(Clone, Copy, Debug)]
+pub enum FiniteNimberRef<'a> {
+    OneWord(Word),
+    Slice(&'a [Word]),
 }
+use FiniteNimberRef::*;
 
-impl<T: FiniteNimberBase> FiniteNimber<T> {
-    pub fn new(n: T) -> Self {
-        Self { n }
+impl<'a> FiniteNimberRef<'a> {
+    fn zero() -> Self {
+        OneWord(0)
     }
-}
 
-impl<T: FiniteNimberBase> std::ops::Add<FiniteNimber<T>> for FiniteNimber<T> {
-    type Output = FiniteNimber<T::Owned>;
+    fn low_word(self) -> Word {
+        match self {
+            OneWord(v) => v,
+            Slice(s) => {
+                *(s.first().expect("FiniteNimberRef::Slice is never empty"))
+            }
+        }
+    }
+
+    fn as_slice<'b, 'c>(&'b self) -> &'c [Word]
+    where
+        'a: 'c,
+        'b: 'c,
+    {
+        match self {
+            OneWord(v) => std::slice::from_ref(v),
+            Slice(s) => s,
+        }
+    }
 
-    fn add(self, other: Self) -> Self::Output {
-        Self::Output::new(self.n ^ other.n)
+    fn split(
+        self,
+        level: usize,
+    ) -> (FiniteNimberRef<'a>, FiniteNimberRef<'a>) {
+        match level.checked_sub(WORDLEVELS) {
+            None => {
+                // If level < WORDLEVELS then we can cast to Word any old way
+                let bits = 1 << (level as Word);
+                let mask = bits - 1;
+                let v = self.low_word();
+                return (OneWord(v & mask), OneWord((v >> bits) & mask));
+            }
+            Some(wordlevel) => match self {
+                OneWord(v) => (OneWord(v), Self::zero()),
+                Slice(s) => {
+                    match wordlevel
+                        .try_into()
+                        .ok()
+                        .and_then(|w| 1usize.checked_shl(w))
+                    {
+                        Some(words) => {
+                            let mut iter = s.chunks(words);
+                            let lo = iter.next().expect(
+                                "FiniteNimberRef::Slice is never empty",
+                            );
+                            match iter.next() {
+                                Some(hi) => (Slice(lo), Slice(hi)),
+                                None => (Slice(lo), Self::zero()),
+                            }
+                        }
+                        None => (self.clone(), Self::zero()),
+                    }
+                }
+            },
+        }
     }
 }
index d40eed06ef89e57fc16cb43e422f2662b040ea6d..4f79e4fdef35fbe59f54addc76f19636658ab874 100644 (file)
@@ -1,8 +1,6 @@
 mod finitenimber;
 
 pub use finitenimber::FiniteNimber;
-pub use finitenimber::IntSlice;
-pub use finitenimber::IntVector;
 
 #[cfg(test)]
 mod tests {
@@ -10,16 +8,8 @@ mod tests {
 
     #[test]
     fn addition() {
-        let a = FiniteNimber::new(0b1100u64);
-        let b = FiniteNimber::new(0b1010u64);
-        assert_eq!(a + b, FiniteNimber::new(0b0110u64));
-
-        let a = FiniteNimber::new(IntVector(vec![1, 1, 0, 0]));
-        let b = FiniteNimber::new(IntVector(vec![1, 0, 1, 0]));
-        assert_eq!(a + b, FiniteNimber::new(IntVector(vec![0, 1, 1, 0])));
-
-        let a = FiniteNimber::new(IntSlice(&[1, 1, 0, 0]));
-        let b = FiniteNimber::new(IntSlice(&[1, 0, 1, 0]));
-        assert_eq!(a + b, FiniteNimber::new(IntVector(vec![0, 1, 1, 0])));
+        let a = FiniteNimber::from(0b1100);
+        let b = FiniteNimber::from(0b1010);
+        assert_eq!(a + b, FiniteNimber::from(0b0110));
     }
 }