#[macro_export] macro_rules! define_index { ($ix:ident) => { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $ix(pub u32); impl $ix { #[inline(always)] pub fn new(i: usize) -> Self { Self(i as u32) } #[inline(always)] pub fn index(self) -> usize { assert!(self.is_valid()); self.0 as usize } #[inline(always)] pub fn invalid() -> Self { Self(u32::MAX) } #[inline(always)] pub fn is_invalid(self) -> bool { self == Self::invalid() } #[inline(always)] pub fn is_valid(self) -> bool { self != Self::invalid() } #[inline(always)] pub fn next(self) -> $ix { assert!(self.is_valid()); Self(self.0 + 1) } #[inline(always)] pub fn prev(self) -> $ix { assert!(self.is_valid()); Self(self.0 - 1) } #[inline(always)] pub fn raw_u32(self) -> u32 { self.0 } } impl crate::index::ContainerIndex for $ix {} }; } pub trait ContainerIndex: Clone + Copy + std::fmt::Debug + PartialEq + Eq {} pub trait ContainerComparator { type Ix: ContainerIndex; fn compare(&self, a: Self::Ix, b: Self::Ix) -> std::cmp::Ordering; } define_index!(Inst); define_index!(Block); #[derive(Clone, Copy, Debug)] pub struct InstRange(Inst, Inst, bool); impl InstRange { #[inline(always)] pub fn forward(from: Inst, to: Inst) -> Self { assert!(from.index() <= to.index()); InstRange(from, to, true) } #[inline(always)] pub fn backward(from: Inst, to: Inst) -> Self { assert!(from.index() >= to.index()); InstRange(to, from, false) } #[inline(always)] pub fn first(self) -> Inst { assert!(self.len() > 0); if self.is_forward() { self.0 } else { self.1.prev() } } #[inline(always)] pub fn last(self) -> Inst { assert!(self.len() > 0); if self.is_forward() { self.1.prev() } else { self.0 } } #[inline(always)] pub fn rest(self) -> InstRange { assert!(self.len() > 0); if self.is_forward() { InstRange::forward(self.0.next(), self.1) } else { InstRange::backward(self.1.prev(), self.0) } } #[inline(always)] pub fn len(self) -> usize { self.1.index() - self.0.index() } #[inline(always)] pub fn is_forward(self) -> bool { self.2 } #[inline(always)] pub fn rev(self) -> Self { Self(self.0, self.1, !self.2) } #[inline(always)] pub fn iter(self) -> InstRangeIter { InstRangeIter(self) } } #[derive(Clone, Copy, Debug)] pub struct InstRangeIter(InstRange); impl Iterator for InstRangeIter { type Item = Inst; #[inline(always)] fn next(&mut self) -> Option { if self.0.len() == 0 { None } else { let ret = self.0.first(); self.0 = self.0.rest(); Some(ret) } } } #[cfg(test)] mod test { use super::*; #[test] fn test_inst_range() { let range = InstRange::forward(Inst::new(0), Inst::new(0)); assert_eq!(range.len(), 0); let range = InstRange::forward(Inst::new(0), Inst::new(5)); assert_eq!(range.first().index(), 0); assert_eq!(range.last().index(), 4); assert_eq!(range.len(), 5); assert_eq!( range.iter().collect::>(), vec![ Inst::new(0), Inst::new(1), Inst::new(2), Inst::new(3), Inst::new(4) ] ); let range = range.rev(); assert_eq!(range.first().index(), 4); assert_eq!(range.last().index(), 0); assert_eq!(range.len(), 5); assert_eq!( range.iter().collect::>(), vec![ Inst::new(4), Inst::new(3), Inst::new(2), Inst::new(1), Inst::new(0) ] ); } }