1 //! Jump table representation.
2 //!
3 //! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.
4 //! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.
5 
6 use crate::ir::entities::Block;
7 use alloc::vec::Vec;
8 use core::fmt::{self, Display, Formatter};
9 use core::slice::{Iter, IterMut};
10 
11 /// Contents of a jump table.
12 ///
13 /// All jump tables use 0-based indexing and are densely populated.
14 #[derive(Clone)]
15 pub struct JumpTableData {
16     // Table entries.
17     table: Vec<Block>,
18 }
19 
20 impl JumpTableData {
21     /// Create a new empty jump table.
new() -> Self22     pub fn new() -> Self {
23         Self { table: Vec::new() }
24     }
25 
26     /// Create a new empty jump table with the specified capacity.
with_capacity(capacity: usize) -> Self27     pub fn with_capacity(capacity: usize) -> Self {
28         Self {
29             table: Vec::with_capacity(capacity),
30         }
31     }
32 
33     /// Get the number of table entries.
len(&self) -> usize34     pub fn len(&self) -> usize {
35         self.table.len()
36     }
37 
38     /// Append a table entry.
push_entry(&mut self, dest: Block)39     pub fn push_entry(&mut self, dest: Block) {
40         self.table.push(dest)
41     }
42 
43     /// Checks if any of the entries branch to `block`.
branches_to(&self, block: Block) -> bool44     pub fn branches_to(&self, block: Block) -> bool {
45         self.table.iter().any(|target_block| *target_block == block)
46     }
47 
48     /// Access the whole table as a slice.
as_slice(&self) -> &[Block]49     pub fn as_slice(&self) -> &[Block] {
50         self.table.as_slice()
51     }
52 
53     /// Access the whole table as a mutable slice.
as_mut_slice(&mut self) -> &mut [Block]54     pub fn as_mut_slice(&mut self) -> &mut [Block] {
55         self.table.as_mut_slice()
56     }
57 
58     /// Returns an iterator over the table.
iter(&self) -> Iter<Block>59     pub fn iter(&self) -> Iter<Block> {
60         self.table.iter()
61     }
62 
63     /// Returns an iterator that allows modifying each value.
iter_mut(&mut self) -> IterMut<Block>64     pub fn iter_mut(&mut self) -> IterMut<Block> {
65         self.table.iter_mut()
66     }
67 }
68 
69 impl Display for JumpTableData {
fmt(&self, fmt: &mut Formatter) -> fmt::Result70     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
71         write!(fmt, "jump_table [")?;
72         match self.table.first() {
73             None => (),
74             Some(first) => write!(fmt, "{}", first)?,
75         }
76         for block in self.table.iter().skip(1) {
77             write!(fmt, ", {}", block)?;
78         }
79         write!(fmt, "]")
80     }
81 }
82 
83 #[cfg(test)]
84 mod tests {
85     use super::JumpTableData;
86     use crate::entity::EntityRef;
87     use crate::ir::Block;
88     use alloc::string::ToString;
89 
90     #[test]
empty()91     fn empty() {
92         let jt = JumpTableData::new();
93 
94         assert_eq!(jt.as_slice().get(0), None);
95         assert_eq!(jt.as_slice().get(10), None);
96 
97         assert_eq!(jt.to_string(), "jump_table []");
98 
99         let v = jt.as_slice();
100         assert_eq!(v, []);
101     }
102 
103     #[test]
insert()104     fn insert() {
105         let e1 = Block::new(1);
106         let e2 = Block::new(2);
107 
108         let mut jt = JumpTableData::new();
109 
110         jt.push_entry(e1);
111         jt.push_entry(e2);
112         jt.push_entry(e1);
113 
114         assert_eq!(jt.to_string(), "jump_table [block1, block2, block1]");
115 
116         let v = jt.as_slice();
117         assert_eq!(v, [e1, e2, e1]);
118     }
119 }
120