diff --git a/src/libcretonne/entity_map.rs b/src/libcretonne/entity_map.rs index a0f4f3fa6b..91ff7505a3 100644 --- a/src/libcretonne/entity_map.rs +++ b/src/libcretonne/entity_map.rs @@ -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 where K: EntityRef @@ -71,17 +70,6 @@ impl EntityMap 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 { Keys { @@ -92,6 +80,33 @@ impl EntityMap } } +/// 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 EntityMap + 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); diff --git a/src/libcretonne/ir/dfg.rs b/src/libcretonne/ir/dfg.rs index aba45354d7..4776220a6f 100644 --- a/src/libcretonne/ir/dfg.rs +++ b/src/libcretonne/ir/dfg.rs @@ -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, } +impl PrimaryEntityData for InstructionData {} +impl PrimaryEntityData for EbbData {} + impl DataFlowGraph { /// Create a new empty `DataFlowGraph`. pub fn new() -> DataFlowGraph { diff --git a/src/libcretonne/ir/mod.rs b/src/libcretonne/ir/mod.rs index 8d5ed99742..f0e8eda741 100644 --- a/src/libcretonne/ir/mod.rs +++ b/src/libcretonne/ir/mod.rs @@ -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 {