177 lines
4.3 KiB
Rust
177 lines
4.3 KiB
Rust
#[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)
|
|
}
|
|
}
|
|
|
|
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<Inst> {
|
|
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<_>>(),
|
|
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<_>>(),
|
|
vec![
|
|
Inst::new(4),
|
|
Inst::new(3),
|
|
Inst::new(2),
|
|
Inst::new(1),
|
|
Inst::new(0)
|
|
]
|
|
);
|
|
}
|
|
}
|