Add iter() and values() functions to PrimaryMap and EntityMap.

`iter()` iterates over both keys and values, while `values()` iterates over
just values. Also add `_mut()` versions.

These replace the otherwise common idiom of iterating with `keys()` and using
indexing to get the values, allowing for simpler code.
This commit is contained in:
Dan Gohman
2018-03-30 11:33:44 -07:00
parent 9e4ab7dc86
commit 72b7a4b3ef
11 changed files with 274 additions and 43 deletions

View File

@@ -0,0 +1,109 @@
//! A double-ended iterator over entity references and entities.
use entity::EntityRef;
use std::marker::PhantomData;
use std::slice;
/// Iterate over all keys in order.
pub struct Iter<'a, K: EntityRef, V>
where
V: 'a,
{
pos: usize,
iter: slice::Iter<'a, V>,
unused: PhantomData<K>,
}
impl<'a, K: EntityRef, V> Iter<'a, K, V> {
/// Create an `Iter` iterator that visits the `PrimaryMap` keys and values
/// of `iter`.
pub fn new(key: K, iter: slice::Iter<'a, V>) -> Self {
Self {
pos: key.index(),
iter,
unused: PhantomData,
}
}
}
impl<'a, K: EntityRef, V> Iterator for Iter<'a, K, V> {
type Item = (K, &'a V);
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
let pos = self.pos;
self.pos += 1;
Some((K::new(pos), next))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, K: EntityRef, V> DoubleEndedIterator for Iter<'a, K, V> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(next_back) = self.iter.next_back() {
Some((K::new(self.pos), next_back))
} else {
None
}
}
}
impl<'a, K: EntityRef, V> ExactSizeIterator for Iter<'a, K, V> {}
/// Iterate over all keys in order.
pub struct IterMut<'a, K: EntityRef, V>
where
V: 'a,
{
pos: usize,
iter: slice::IterMut<'a, V>,
unused: PhantomData<K>,
}
impl<'a, K: EntityRef, V> IterMut<'a, K, V> {
/// Create an `IterMut` iterator that visits the `PrimaryMap` keys and values
/// of `iter`.
pub fn new(key: K, iter: slice::IterMut<'a, V>) -> Self {
Self {
pos: key.index(),
iter,
unused: PhantomData,
}
}
}
impl<'a, K: EntityRef, V> Iterator for IterMut<'a, K, V> {
type Item = (K, &'a mut V);
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.iter.next() {
let pos = self.pos;
self.pos += 1;
Some((K::new(pos), next))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(next_back) = self.iter.next_back() {
Some((K::new(self.pos), next_back))
} else {
None
}
}
}
impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {}

View File

@@ -1,9 +1,10 @@
//! Densely numbered entity references as mapping keys.
use entity::{EntityRef, Keys};
use entity::{EntityRef, Keys, Iter, IterMut};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
use std::slice;
/// A mapping `K -> V` for densely indexed entity references.
///
@@ -68,11 +69,31 @@ where
self.elems.clear()
}
/// Iterate over all the keys and values in this map.
pub fn iter(&self) -> Iter<K, V> {
Iter::new(K::new(0), self.elems.iter())
}
/// Iterate over all the keys and values in this map, mutable edition.
pub fn iter_mut(&mut self) -> IterMut<K, V> {
IterMut::new(K::new(0), self.elems.iter_mut())
}
/// Iterate over all the keys in this map.
pub fn keys(&self) -> Keys<K> {
Keys::new(self.elems.len())
}
/// Iterate over all the keys in this map.
pub fn values(&self) -> slice::Iter<V> {
self.elems.iter()
}
/// Iterate over all the keys in this map, mutable edition.
pub fn values_mut(&mut self) -> slice::IterMut<V> {
self.elems.iter_mut()
}
/// Resize the map to have `n` entries by adding default entries as needed.
pub fn resize(&mut self, n: usize) {
self.elems.resize(n, self.default.clone());

View File

@@ -30,6 +30,7 @@
//! `Vec`.
mod keys;
mod iter;
mod list;
mod map;
mod primary;
@@ -37,6 +38,7 @@ mod sparse;
mod set;
pub use self::keys::Keys;
pub use self::iter::{Iter, IterMut};
pub use self::list::{EntityList, ListPool};
pub use self::map::EntityMap;
pub use self::primary::PrimaryMap;

View File

@@ -1,8 +1,9 @@
//! Densely numbered entity references as mapping keys.
use entity::{EntityRef, Keys};
use entity::{EntityRef, Keys, Iter, IterMut};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
use std::slice;
/// A primary mapping `K -> V` allocating dense entity references.
///
@@ -59,6 +60,26 @@ where
Keys::new(self.elems.len())
}
/// Iterate over all the values in this map.
pub fn values(&self) -> slice::Iter<V> {
self.elems.iter()
}
/// Iterate over all the values in this map, mutable edition.
pub fn values_mut(&mut self) -> slice::IterMut<V> {
self.elems.iter_mut()
}
/// Iterate over all the keys and values in this map.
pub fn iter(&self) -> Iter<K, V> {
Iter::new(K::new(0), self.elems.iter())
}
/// Iterate over all the keys and values in this map, mutable edition.
pub fn iter_mut(&mut self) -> IterMut<K, V> {
IterMut::new(K::new(0), self.elems.iter_mut())
}
/// Remove all entries from this map.
pub fn clear(&mut self) {
self.elems.clear()
@@ -133,13 +154,80 @@ mod tests {
#[test]
fn push() {
let mut m = PrimaryMap::new();
let k1: E = m.push(12);
let k2 = m.push(33);
let k0: E = m.push(12);
let k1 = m.push(33);
assert_eq!(m[k1], 12);
assert_eq!(m[k2], 33);
assert_eq!(m[k0], 12);
assert_eq!(m[k1], 33);
let v: Vec<E> = m.keys().collect();
assert_eq!(v, [k1, k2]);
assert_eq!(v, [k0, k1]);
}
#[test]
fn iter() {
let mut m: PrimaryMap<E, usize> = PrimaryMap::new();
m.push(12);
m.push(33);
let mut i = 0;
for (key, value) in m.iter() {
assert_eq!(key.index(), i);
match i {
0 => assert_eq!(*value, 12),
1 => assert_eq!(*value, 33),
_ => panic!(),
}
i += 1;
}
i = 0;
for (key_mut, value_mut) in m.iter_mut() {
assert_eq!(key_mut.index(), i);
match i {
0 => assert_eq!(*value_mut, 12),
1 => assert_eq!(*value_mut, 33),
_ => panic!(),
}
i += 1;
}
}
#[test]
fn keys() {
let mut m: PrimaryMap<E, usize> = PrimaryMap::new();
m.push(12);
m.push(33);
let mut i = 0;
for key in m.keys() {
assert_eq!(key.index(), i);
i += 1;
}
}
#[test]
fn values() {
let mut m: PrimaryMap<E, usize> = PrimaryMap::new();
m.push(12);
m.push(33);
let mut i = 0;
for value in m.values() {
match i {
0 => assert_eq!(*value, 12),
1 => assert_eq!(*value, 33),
_ => panic!(),
}
i += 1;
}
i = 0;
for value_mut in m.values_mut() {
match i {
0 => assert_eq!(*value_mut, 12),
1 => assert_eq!(*value_mut, 33),
_ => panic!(),
}
i += 1;
}
}
}

View File

@@ -3,11 +3,12 @@
//! The `StackSlotData` struct keeps track of a single stack slot in a function.
//!
use entity::{PrimaryMap, Keys};
use entity::{PrimaryMap, Keys, Iter, IterMut};
use ir::{Type, StackSlot};
use packed_option::PackedOption;
use std::cmp;
use std::fmt;
use std::slice;
use std::ops::{Index, IndexMut};
use std::str::FromStr;
use std::vec::Vec;
@@ -208,6 +209,26 @@ impl StackSlots {
self.slots[ss].offset = Some(offset);
}
/// Get an iterator over all the stack slot keys.
pub fn iter(&self) -> Iter<StackSlot, StackSlotData> {
self.slots.iter()
}
/// Get an iterator over all the stack slot keys, mutable edition.
pub fn iter_mut(&mut self) -> IterMut<StackSlot, StackSlotData> {
self.slots.iter_mut()
}
/// Get an iterator over all the stack slot records.
pub fn values(&self) -> slice::Iter<StackSlotData> {
self.slots.values()
}
/// Get an iterator over all the stack slot records, mutable edition.
pub fn values_mut(&mut self) -> slice::IterMut<StackSlotData> {
self.slots.values_mut()
}
/// Get an iterator over all the stack slot keys.
pub fn keys(&self) -> Keys<StackSlot> {
self.slots.keys()

View File

@@ -35,9 +35,9 @@ use std::vec::Vec;
pub fn legalize_signatures(func: &mut Function, isa: &TargetIsa) {
isa.legalize_signature(&mut func.signature, true);
func.signature.compute_argument_bytes();
for sig in func.dfg.signatures.keys() {
isa.legalize_signature(&mut func.dfg.signatures[sig], false);
func.dfg.signatures[sig].compute_argument_bytes();
for sig_data in func.dfg.signatures.values_mut() {
isa.legalize_signature(sig_data, false);
sig_data.compute_argument_bytes();
}
if let Some(entry) = func.layout.entry_block() {

View File

@@ -29,8 +29,8 @@ pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function) -> bool {
fn find_funcref(libcall: ir::LibCall, func: &ir::Function) -> Option<ir::FuncRef> {
// We're assuming that all libcall function decls are at the end.
// If we get this wrong, worst case we'll have duplicate libcall decls which is harmless.
for fref in func.dfg.ext_funcs.keys().rev() {
match func.dfg.ext_funcs[fref].name {
for (fref, func_data) in func.dfg.ext_funcs.iter().rev() {
match func_data.name {
ir::ExternalName::LibCall(lc) => {
if lc == libcall {
return Some(fref);

View File

@@ -39,9 +39,7 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<Stac
let mut outgoing_max = 0;
let mut min_align = alignment;
for ss in frame.keys() {
let slot = &frame[ss];
for slot in frame.values() {
if slot.size > max_size {
return Err(CtonError::ImplLimitExceeded);
}
@@ -72,9 +70,7 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<Stac
let mut offset = incoming_min;
debug_assert!(min_align.is_power_of_two());
while min_align <= alignment {
for ss in frame.keys() {
let slot = frame[ss].clone();
for slot in frame.values_mut() {
// Pick out explicit and spill slots with exact alignment `min_align`.
match slot.kind {
StackSlotKind::SpillSlot |
@@ -94,7 +90,7 @@ pub fn layout_stack(frame: &mut StackSlots, alignment: StackSize) -> Result<Stac
// Aligning the negative offset can never cause overflow. We're only clearing bits.
offset &= -(min_align as StackOffset);
frame.set_offset(ss, offset);
slot.offset = Some(offset);
}
// Move on to the next higher alignment.

View File

@@ -44,44 +44,38 @@ fn write_preamble(
) -> result::Result<bool, Error> {
let mut any = false;
for ss in func.stack_slots.keys() {
for (ss, slot) in func.stack_slots.iter() {
any = true;
writeln!(w, " {} = {}", ss, func.stack_slots[ss])?;
writeln!(w, " {} = {}", ss, slot)?;
}
for gv in func.global_vars.keys() {
for (gv, gv_data) in func.global_vars.iter() {
any = true;
writeln!(w, " {} = {}", gv, func.global_vars[gv])?;
writeln!(w, " {} = {}", gv, gv_data)?;
}
for heap in func.heaps.keys() {
for (heap, heap_data) in func.heaps.iter() {
any = true;
writeln!(w, " {} = {}", heap, func.heaps[heap])?;
writeln!(w, " {} = {}", heap, heap_data)?;
}
// Write out all signatures before functions since function declarations can refer to
// signatures.
for sig in func.dfg.signatures.keys() {
for (sig, sig_data) in func.dfg.signatures.iter() {
any = true;
writeln!(
w,
" {} = {}",
sig,
func.dfg.signatures[sig].display(regs)
)?;
writeln!(w, " {} = {}", sig, sig_data.display(regs))?;
}
for fnref in func.dfg.ext_funcs.keys() {
for (fnref, ext_func) in func.dfg.ext_funcs.iter() {
any = true;
let ext_func = &func.dfg.ext_funcs[fnref];
if ext_func.signature != SigRef::reserved_value() {
writeln!(w, " {} = {}", fnref, ext_func)?;
}
}
for jt in func.jump_tables.keys() {
for (jt, jt_data) in func.jump_tables.iter() {
any = true;
writeln!(w, " {} = {}", jt, func.jump_tables[jt])?;
writeln!(w, " {} = {}", jt, jt_data)?;
}
Ok(any)

View File

@@ -130,8 +130,8 @@ impl SubTest for TestBinEmit {
// Fix the stack frame layout so we can test spill/fill encodings.
let min_offset = func.stack_slots
.keys()
.map(|ss| func.stack_slots[ss].offset.unwrap())
.values()
.map(|slot| slot.offset.unwrap())
.min();
func.stack_slots.frame_size = min_offset.map(|off| (-off) as u32);

View File

@@ -439,14 +439,14 @@ where
pub fn finalize(&mut self) {
// Check that all the `Ebb`s are filled and sealed.
debug_assert!(
self.func_ctx.ebbs.keys().all(|ebb| {
self.func_ctx.ebbs[ebb].pristine || self.func_ctx.ssa.is_sealed(ebb)
self.func_ctx.ebbs.iter().all(|(ebb, ebb_data)| {
ebb_data.pristine || self.func_ctx.ssa.is_sealed(ebb)
}),
"all blocks should be sealed before dropping a FunctionBuilder"
);
debug_assert!(
self.func_ctx.ebbs.keys().all(|ebb| {
self.func_ctx.ebbs[ebb].pristine || self.func_ctx.ebbs[ebb].filled
self.func_ctx.ebbs.values().all(|ebb_data| {
ebb_data.pristine || ebb_data.filled
}),
"all blocks should be filled before dropping a FunctionBuilder"
);