14.challenges.1
change loktmpwmxwnmlwymquppsxtzmslsmrox
commit 4ac44f6c0010fa89f6b2dc781584099797d8d3d9
author Alpha Chen <alpha@kejadlen.dev>
date
parent ysvywzvx
diff --git a/rust/justfile b/rust/justfile
index cdac729..7868a1a 100644
--- a/rust/justfile
+++ b/rust/justfile
@@ -1,2 +1,3 @@
 test-watch:
-  while true; do fd .*.rs | entr -d cargo test; done
+  # while true; do fd .*.rs | entr -d cargo test; done
+  fd .*.rs | entr -d cargo test
diff --git a/rust/src/chunk.rs b/rust/src/chunk.rs
index 881c768..41ddbe5 100644
--- a/rust/src/chunk.rs
+++ b/rust/src/chunk.rs
@@ -10,24 +10,58 @@ pub enum OpCode {
 
 type Value = f32;
 
+#[derive(Default)]
 pub struct Chunk {
     code: Vec<u8>,
     constants: Vec<Value>,
-    lines: Vec<usize>,
+    lines: Lines,
 }
 
-impl Chunk {
-    pub fn new() -> Self {
-        Chunk {
-            code: Vec::new(),
-            constants: Vec::new(),
-            lines: Vec::new(),
+// Lines are stored using run-length encoding, where the first element is the line and the second
+// element the number of instructions that are associated with that line
+#[derive(Default, Debug)]
+struct Lines(std::vec::Vec<(usize, usize)>);
+
+impl Lines {
+    fn add(&mut self, line: usize) {
+        if let Some(last) = self.0.last_mut() {
+            last.1 += 1;
+        } else {
+            self.0.push((line, 1));
         }
     }
 
+    fn get(&self, offset: usize) -> (usize, bool) {
+        let mut offset = offset;
+        for (line, run) in self.0.iter() {
+            if offset == 0 {
+                return (*line, true);
+            }
+
+            if offset < *run {
+                return (*line, false);
+            }
+
+            offset -= run;
+        }
+
+        unreachable!()
+    }
+}
+
+#[test]
+fn test_get_line() {
+    let lines = Lines(vec![(1_usize, 2_usize), (2_usize, 2_usize)]);
+    assert_eq!(lines.get(0), (1, true));
+    assert_eq!(lines.get(1), (1, false));
+    assert_eq!(lines.get(2), (2, true));
+    assert_eq!(lines.get(3), (2, false));
+}
+
+impl Chunk {
     pub fn write(&mut self, byte: u8, line: usize) {
         self.code.push(byte);
-        self.lines.push(line);
+        self.lines.add(line);
     }
 
     pub fn add_constant(&mut self, value: Value) -> u8 {
@@ -50,10 +84,11 @@ impl Chunk {
     fn disassemble_instruction(&self, offset: usize) -> usize {
         print!("{:04} ", offset);
 
-        if offset > 0 && self.lines[offset] == self.lines[offset - 1] {
-            print!("   | ");
+        let (line, is_first) = self.lines.get(offset);
+        if is_first {
+            print!("{:>4} ", line);
         } else {
-            print!("{:>4} ", self.lines[offset]);
+            print!("   | ");
         }
 
         match self.code[offset] {
@@ -75,9 +110,3 @@ impl Chunk {
         offset + 2
     }
 }
-
-impl Default for Chunk {
-    fn default() -> Self {
-        Self::new()
-    }
-}