Add PrimaryEntityData marker trait.

Require this trait on the value type stored in an EntityMap to 'unlock' the
methods intended for primary entity maps that are allowed to create references
with the 'push method.

This prevents accidentally depending on these methods in secondary maps.
This commit is contained in:
Jakob Stoklund Olesen
2016-08-01 14:45:59 -07:00
parent 549a14bf96
commit f5008567c9
3 changed files with 44 additions and 21 deletions

View File

@@ -2,7 +2,13 @@
//!
//! This module defines an `EntityRef` trait that should be implemented by reference types wrapping
//! a small integer index. The `EntityMap` data structure uses the dense index space to implement a
//! map with a vector.
//! map with a vector. There are primary and secondary entity maps:
//!
//! - A *primary* `EntityMap` contains the main definition of an entity, and it can be used to
//! allocate new entity references with the `push` method. The values stores in a primary map
//! must implement the `PrimaryEntityData` marker trait.
//! - A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
//! values need to implement `Clone + Default` traits so the map can be grown with `ensure`.
use std::vec::Vec;
use std::default::Default;
@@ -39,13 +45,6 @@ pub trait EntityRef: Copy + Eq {
}
/// A mapping `K -> V` for densely indexed entity references.
///
/// A *primary* `EntityMap` contains the main definition of an entity, and it can be used to
/// allocate new entity references with the `push` method.
///
/// A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
/// values need to implement `Clone + Default` traits so the map can be grown with `ensure`.
///
#[derive(Debug)]
pub struct EntityMap<K, V>
where K: EntityRef
@@ -71,17 +70,6 @@ impl<K, V> EntityMap<K, V>
k.index() < self.elems.len()
}
/// Append `v` to the mapping, assigning a new key which is returned.
pub fn push(&mut self, v: V) -> K {
let k = K::new(self.elems.len());
self.elems.push(v);
k
}
pub fn len(&self) -> usize {
self.elems.len()
}
/// Iterate over all the keys in this map.
pub fn keys(&self) -> Keys<K> {
Keys {
@@ -92,6 +80,33 @@ impl<K, V> EntityMap<K, V>
}
}
/// A marker trait for data stored in primary entity maps.
///
/// A primary entity map can be used to allocate new entity references with the `push` method. It
/// is important that entity references can't be created anywhere else, so the data stored in a
/// primary entity map must be tagged as `PrimaryEntityData` to unlock the `push` method.
pub trait PrimaryEntityData {}
/// Additional methods for primary entry maps only.
///
/// These are identified by the `PrimaryEntityData` marker trait.
impl<K, V> EntityMap<K, V>
where K: EntityRef,
V: PrimaryEntityData
{
/// Append `v` to the mapping, assigning a new key which is returned.
pub fn push(&mut self, v: V) -> K {
let k = K::new(self.elems.len());
self.elems.push(v);
k
}
/// Get the total number of entity references created.
pub fn len(&self) -> usize {
self.elems.len()
}
}
/// Additional methods for value types that implement `Clone` and `Default`.
///
/// When the value type implements these additional traits, the `EntityMap` can be resized
@@ -193,6 +208,8 @@ mod tests {
}
}
impl PrimaryEntityData for isize {}
#[test]
fn basic() {
let r0 = E(0);

View File

@@ -1,6 +1,6 @@
//! Data flow graph tracking Instructions, Values, and EBBs.
use entity_map::EntityMap;
use entity_map::{EntityMap, PrimaryEntityData};
use ir::entities::{Ebb, Inst, Value, NO_VALUE, ExpandedValue};
use ir::instructions::InstructionData;
use ir::types::Type;
@@ -33,6 +33,9 @@ pub struct DataFlowGraph {
extended_values: Vec<ValueData>,
}
impl PrimaryEntityData for InstructionData {}
impl PrimaryEntityData for EbbData {}
impl DataFlowGraph {
/// Create a new empty `DataFlowGraph`.
pub fn new() -> DataFlowGraph {

View File

@@ -10,7 +10,7 @@ pub mod dfg;
pub mod layout;
use ir::types::{FunctionName, Signature};
use entity_map::{EntityRef, EntityMap};
use entity_map::{EntityRef, EntityMap, PrimaryEntityData};
use ir::entities::{StackSlot, JumpTable};
use ir::jumptable::JumpTableData;
use ir::dfg::DataFlowGraph;
@@ -39,6 +39,9 @@ pub struct Function {
pub layout: Layout,
}
// Tag JumpTableData as a primary entity so jump_tables above .
impl PrimaryEntityData for JumpTableData {}
impl Function {
/// Create a function with the given name and signature.
pub fn with_name_signature(name: FunctionName, sig: Signature) -> Function {