From a4471090c4763fc9caf6da6a6bac74ad05004bd9 Mon Sep 17 00:00:00 2001 From: darcy Date: Thu, 19 Dec 2024 19:16:43 +1100 Subject: [PATCH] feat: keep breakpoints sorted --- src/debugger/breakpoint.rs | 40 +++++++++++++++++++++++++++----------- src/debugger/mod.rs | 9 ++++----- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/debugger/breakpoint.rs b/src/debugger/breakpoint.rs index 14b76d9..5a8b0bb 100644 --- a/src/debugger/breakpoint.rs +++ b/src/debugger/breakpoint.rs @@ -1,7 +1,15 @@ -// TODO(feat): Keep sorted! +/// Wrapper for list of [`Breakpoint`]s. +/// +/// Could be another collection, but [`Vec`] was used for simplicity. +/// +/// List must remain sorted, and 2 breakpoints cannot have the same address. #[derive(Debug)] pub struct Breakpoints(Vec); +/// A [`Breakpoint`] is just an address, and a flag for whether it was 'predefined'. +/// +/// Predefined here meaning it was registered in the assembly code, with the `.BREAK` directive, +/// as opposed to being registered with a debugger command (`break add`). #[derive(Clone, Copy, Debug)] pub struct Breakpoint { pub address: u16, @@ -9,6 +17,9 @@ pub struct Breakpoint { } impl Breakpoints { + /// Get the [`Breakpoint`] with the given address. + /// + /// Returns `None` if no breakpoint exists. pub fn get(&self, address: u16) -> Option { for breakpoint in &self.0 { if breakpoint.address == address { @@ -18,22 +29,28 @@ impl Breakpoints { None } - pub fn contains(&self, address: u16) -> bool { - for breakpoint in &self.0 { - if breakpoint.address == address { + /// Insert a new breakpoint, keeping list sorted. + /// + /// Returns `true` if breakpoint already exists with that address (new breakpoint will not be + /// inserted). + pub fn insert(&mut self, breakpoint: Breakpoint) -> bool { + let mut index = self.len(); + for (i, other) in self.iter().enumerate() { + if other.address == breakpoint.address { return true; } + if other.address >= breakpoint.address { + index = i; + break; + } } - false - } - - pub fn insert(&mut self, breakpoint: Breakpoint) { - self.0.push(breakpoint); + self.0.insert(index, breakpoint); + return false; } - /// Removes every breakpoint with given address + /// Removes every breakpoint with given address, keeping list sorted. /// - /// Returns whether any breakpoint was found with given address + /// Returns whether any breakpoint was found with given address. pub fn remove(&mut self, address: u16) -> bool { let initial_len = self.0.len(); self.0.retain(|breakpoint| breakpoint.address != address); @@ -62,6 +79,7 @@ impl From> for Breakpoints { impl<'a> IntoIterator for &'a Breakpoints { type Item = &'a Breakpoint; type IntoIter = std::slice::Iter<'a, Breakpoint>; + fn into_iter(self) -> Self::IntoIter { self.0.iter() } diff --git a/src/debugger/mod.rs b/src/debugger/mod.rs index fee9ee2..4f61c87 100644 --- a/src/debugger/mod.rs +++ b/src/debugger/mod.rs @@ -330,7 +330,10 @@ impl Debugger { Command::BreakAdd { location } => { let address = self.resolve_location_address(state, &location)?; - if self.breakpoints.contains(address) { + if self.breakpoints.insert(Breakpoint { + address, + is_predefined: false, + }) { dprintln!( Always, Error, @@ -338,10 +341,6 @@ impl Debugger { address ); } else { - self.breakpoints.insert(Breakpoint { - address, - is_predefined: false, - }); dprintln!(Always, Warning, "Added breakpoint at 0x{:04x}.", address); } }