use std::ops::Range;
use std::slice::Iter;
use std::usize;
use std::borrow::Cow;
use {
Mnemonic,BasicBlock,Names,Strings,
Result,
Statement,Bitcode,BitcodeIter,Segments
};
pub enum StatementsIter<'a> {
Bitcode(BitcodeIter<'a>),
Vector(Iter<'a,Statement>),
}
impl<'a> Iterator for StatementsIter<'a> {
type Item = Cow<'a,Statement>;
fn next(&mut self) -> Option<Cow<'a,Statement>> {
match self {
&mut StatementsIter::Bitcode(ref mut bt) => bt.next().map(|x| Cow::Owned(x)),
&mut StatementsIter::Vector(ref mut v) => v.next().map(|x| Cow::Borrowed(x)),
}
}
}
pub enum RewriteControl {
Continue,
Break,
}
#[derive(Clone, Debug)]
pub enum Statements {
Bitcode(Bitcode),
Vector(Vec<Statement>),
}
impl Default for Statements {
fn default() -> Statements {
Statements::Vector(Vec::new())
}
}
impl Statements {
pub fn iter_range<'a>(&'a self, rgn: Range<usize>) -> StatementsIter<'a> {
match self {
&Statements::Bitcode(ref bt) => StatementsIter::Bitcode(bt.iter_range(rgn)),
&Statements::Vector(ref v) => StatementsIter::Vector(v[rgn].iter()),
}
}
pub fn rewrite<F: FnMut(&mut Statement, &mut Names, &mut Strings, &mut Segments) -> Result<RewriteControl> + Sized>(&mut self, rgn: Range<usize>, names: &mut Names, strings: &mut Strings, segments: &mut Segments, mut f: F) -> Result<Range<usize>> {
match self {
&mut Statements::Bitcode(ref mut bt) => bt.rewrite(rgn,names,strings,segments,f),
&mut Statements::Vector(ref mut v) => {
for stmt in v[rgn.clone()].iter_mut() {
match f(stmt,names,strings,segments)? {
RewriteControl::Break => { break; }
RewriteControl::Continue => { continue; }
}
}
Ok(rgn)
}
}
}
pub fn insert(&mut self, pos: usize, stmts: Vec<Statement>) -> Result<Range<usize>> {
match self {
&mut Statements::Bitcode(ref mut bt) => bt.insert(pos,stmts),
&mut Statements::Vector(ref mut v) => {
let rgn = pos..(pos + stmts.len());
for (i,stmt) in stmts.into_iter().enumerate() {
v.insert(i + pos,stmt);
}
Ok(rgn)
}
}
}
pub fn remove(&mut self, rgn: Range<usize>) {
match self {
&mut Statements::Bitcode(ref mut bt) => bt.remove(rgn),
&mut Statements::Vector(ref mut v) => { v.drain(rgn); }
}
}
pub fn append<I: IntoIterator<Item=Statement> + Sized>(&mut self, i: I) -> Result<Range<usize>> {
match self {
&mut Statements::Bitcode(ref mut bt) => bt.append(i),
&mut Statements::Vector(ref mut v) => {
let fst = v.len();
v.extend(i);
Ok(fst..v.len())
}
}
}
pub fn len(&self) -> usize {
match self {
&Statements::Bitcode(ref bt) => bt.num_bytes(),
&Statements::Vector(ref v) => v.len(),
}
}
pub fn pack(&mut self, basic_blocks: &mut Vec<BasicBlock>, mnemonics: &mut Vec<Mnemonic>) -> Result<()> {
*self = match self {
&mut Statements::Bitcode(_) => { return Ok(()); },
&mut Statements::Vector(ref mut vec) => {
let mut bc = Bitcode::with_capacity(vec.len() * 15);
for bb in basic_blocks.iter_mut() {
let mut old_idx = bb.statements.start;
let mut new_idx = bc.num_bytes();
let new_start = new_idx;
let mne_rgn = bb.mnemonics.start.index()..bb.mnemonics.end.index();
for mne in mnemonics[mne_rgn].iter_mut() {
let old_rgn = old_idx..(old_idx + mne.statement_count);
let new_rgn = bc.append(vec[old_rgn].iter().cloned())?;
old_idx += mne.statement_count;
mne.statement_count = new_rgn.end - new_rgn.start;
new_idx += mne.statement_count;
}
assert_eq!(bb.statements.end, old_idx);
bb.statements = new_start..new_idx;
}
Statements::Bitcode(bc)
}
};
Ok(())
}
pub fn unpack(&mut self, basic_blocks: &mut Vec<BasicBlock>, mnemonics: &mut Vec<Mnemonic>) -> Result<()> {
*self = match self {
&mut Statements::Vector(_) => { return Ok(()); }
&mut Statements::Bitcode(ref bc) => {
let mut vec = Vec::with_capacity(bc.num_bytes() / 15);
for bb in basic_blocks.iter_mut() {
let mut old_idx = bb.statements.start;
let mut new_idx = vec.len();
let new_start = new_idx;
let mne_rgn = bb.mnemonics.start.index()..bb.mnemonics.end.index();
for mne in mnemonics[mne_rgn].iter_mut() {
let old_rgn = old_idx..(old_idx + mne.statement_count);
vec.extend(bc.iter_range(old_rgn));
old_idx += mne.statement_count;
mne.statement_count = vec.len() - new_idx;
new_idx += mne.statement_count;
}
assert_eq!(bb.statements.end, old_idx);
bb.statements = new_start..new_idx;
}
Statements::Vector(vec)
}
};
Ok(())
}
}