From f5008567c9a479423a1fce1801fdce268e013b2f Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 1 Aug 2016 14:45:59 -0700 Subject: [PATCH] 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. --- src/libcretonne/entity_map.rs | 55 +++++++++++++++++++++++------------ src/libcretonne/ir/dfg.rs | 5 +++- src/libcretonne/ir/mod.rs | 5 +++- 3 files changed, 44 insertions(+), 21 deletions(-) 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 {