diff --git a/crates/oxc_data_structures/src/stack/non_empty.rs b/crates/oxc_data_structures/src/stack/non_empty.rs index bb06165bdccf3..9860758a92a00 100644 --- a/crates/oxc_data_structures/src/stack/non_empty.rs +++ b/crates/oxc_data_structures/src/stack/non_empty.rs @@ -354,6 +354,10 @@ impl NonEmptyStack { } /// Get if stack is empty. Always returns `false`. + /// + /// Probably you want [`is_exhausted`] instead. + /// + /// [`is_exhausted`]: Self::is_exhausted #[expect(clippy::unused_self)] #[inline] pub fn is_empty(&self) -> bool { @@ -362,6 +366,22 @@ impl NonEmptyStack { false } + /// Get if stack is back in its initial state. + /// i.e. Every `push` has been followed by a corresponding `pop`. + /// + /// [`NonEmptyStack`] is never empty, so this is the closest thing to `is_empty` that makes sense. + /// + /// If this method returns `true`, the stack only contains the initial element, + /// and calling [`pop`] will panic. + /// + /// Equivalent to `stack.len() == 1`. + /// + /// [`pop`]: Self::pop + #[inline] + pub fn is_exhausted(&self) -> bool { + self.cursor == self.start + } + /// Get capacity. #[inline] pub fn capacity(&self) -> usize { @@ -460,6 +480,22 @@ mod tests { NonEmptyStack::with_capacity(0, 10u64); } + #[test] + fn is_exhausted() { + let mut stack = NonEmptyStack::new(0u64); + assert!(stack.is_exhausted()); + + stack.push(10); + assert!(!stack.is_exhausted()); + stack.push(20); + assert!(!stack.is_exhausted()); + + stack.pop(); + assert!(!stack.is_exhausted()); + stack.pop(); + assert!(stack.is_exhausted()); + } + #[test] fn push_then_pop() { let mut stack = NonEmptyStack::new(10u64); diff --git a/crates/oxc_data_structures/src/stack/sparse.rs b/crates/oxc_data_structures/src/stack/sparse.rs index 36e0c541574ce..31aacff7a2a31 100644 --- a/crates/oxc_data_structures/src/stack/sparse.rs +++ b/crates/oxc_data_structures/src/stack/sparse.rs @@ -249,6 +249,22 @@ impl SparseStack { self.has_values.len() } + /// Get if stack is back in its initial state. + /// i.e. Every `push` has been followed by a corresponding `pop`. + /// + /// [`SparseStack`] is never empty, so this is the closest thing to `is_empty` that makes sense. + /// + /// If this method returns `true`, the stack only contains the initial element, + /// and calling [`pop`] will panic. + /// + /// Equivalent to `stack.len() == 1`. + /// + /// [`pop`]: Self::pop + #[inline] + pub fn is_exhausted(&self) -> bool { + self.has_values.is_exhausted() + } + /// Get number of filled entries on the stack. #[inline] pub fn filled_len(&self) -> usize { @@ -285,3 +301,32 @@ impl SparseStack { self.values.as_mut_slice() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_exhausted() { + let mut stack = SparseStack::::new(); + assert!(stack.is_exhausted()); + + stack.push(None); + assert!(!stack.is_exhausted()); + stack.push(None); + assert!(!stack.is_exhausted()); + stack.pop(); + assert!(!stack.is_exhausted()); + stack.pop(); + assert!(stack.is_exhausted()); + + stack.push(Some(10)); + assert!(!stack.is_exhausted()); + stack.push(Some(20)); + assert!(!stack.is_exhausted()); + stack.pop(); + assert!(!stack.is_exhausted()); + stack.pop(); + assert!(stack.is_exhausted()); + } +}