chiark / gitweb /
Determine starting level
authorSimon Tatham <anakin@pobox.com>
Fri, 11 Apr 2025 17:44:21 +0000 (18:44 +0100)
committerSimon Tatham <anakin@pobox.com>
Fri, 11 Apr 2025 17:44:21 +0000 (18:44 +0100)
src/finitenimber.rs

index d4dcc3348fd5b38cbe205f2e028068c42ee4f24a..9cbda22bd246f65d5f894b0deed41058bced74c1 100644 (file)
@@ -68,6 +68,35 @@ impl<'a> FiniteNimberRef<'a> {
         }
     }
 
+    fn level(self) -> usize {
+        fn word_level(w: Word) -> usize {
+            let log_w: u32 =
+                (Word::BITS - 1).saturating_sub(w.leading_zeros());
+            u32::BITS.saturating_sub(log_w.leading_zeros()) as usize
+        }
+
+        fn usize_level(w: usize) -> usize {
+            let log_w: u32 = (usize::BITS - 1) - w.leading_zeros();
+            u32::BITS.saturating_sub(log_w.leading_zeros()) as usize
+        }
+
+        match self {
+            OneWord(v) => word_level(v),
+            Slice(s) => {
+                match s
+                    .iter()
+                    .enumerate()
+                    .rev()
+                    .find(|(_index, word)| **word != 0)
+                {
+                    None => 0,
+                    Some((0, w)) => word_level(*w),
+                    Some((i, _)) => usize_level(i) + (WORDLEVELS + 1),
+                }
+            }
+        }
+    }
+
     fn split(
         self,
         level: usize,
@@ -352,6 +381,30 @@ mod tests {
         );
     }
 
+    #[test]
+    fn levels() {
+        assert_eq!(FiniteNimber(vec![]).to_ref().level(), 0);
+        assert_eq!(FiniteNimber(vec![0]).to_ref().level(), 0);
+        assert_eq!(FiniteNimber(vec![1]).to_ref().level(), 0);
+        assert_eq!(FiniteNimber(vec![2]).to_ref().level(), 1);
+        assert_eq!(FiniteNimber(vec![3]).to_ref().level(), 1);
+        assert_eq!(FiniteNimber(vec![4]).to_ref().level(), 2);
+        assert_eq!(FiniteNimber(vec![0xf]).to_ref().level(), 2);
+        assert_eq!(FiniteNimber(vec![0x10]).to_ref().level(), 3);
+        assert_eq!(FiniteNimber(vec![0xff]).to_ref().level(), 3);
+        assert_eq!(FiniteNimber(vec![0x0100]).to_ref().level(), 4);
+        assert_eq!(FiniteNimber(vec![0xffff]).to_ref().level(), 4);
+        assert_eq!(FiniteNimber(vec![0x00010000]).to_ref().level(), 5);
+        assert_eq!(FiniteNimber(vec![0xffffffff]).to_ref().level(), 5);
+        assert_eq!(FiniteNimber(vec![0x0000000100000000]).to_ref().level(), 6);
+        assert_eq!(FiniteNimber(vec![0xffffffffffffffff]).to_ref().level(), 6);
+
+        assert_eq!(FiniteNimber(vec![0x55, 0, 0, 0]).to_ref().level(), 3);
+        assert_eq!(FiniteNimber(vec![0x55, 1, 0, 0]).to_ref().level(), 7);
+        assert_eq!(FiniteNimber(vec![0x55, 1, 1, 0]).to_ref().level(), 8);
+        assert_eq!(FiniteNimber(vec![0x55, 1, 1, 1]).to_ref().level(), 8);
+    }
+
     #[test]
     fn addition() {
         let a = FiniteNimber::from(0b1100);