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::Ebb;
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 densely populated.
14 #[derive(Clone)]
15 pub struct JumpTableData {
16     // Table entries.
17     table: Vec<Ebb>,
18 }
19 
20 impl JumpTableData {
21     /// Create a new empty jump table.
22     pub fn new() -> Self {
23         Self { table: Vec::new() }
24     }
25 
26     /// Create a new empty jump table with the specified capacity.
27     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.
34     pub fn len(&self) -> usize {
35         self.table.len()
36     }
37 
38     /// Append a table entry.
39     pub fn push_entry(&mut self, dest: Ebb) {
40         self.table.push(dest)
41     }
42 
43     /// Checks if any of the entries branch to `ebb`.
44     pub fn branches_to(&self, ebb: Ebb) -> bool {
45         self.table.iter().any(|target_ebb| *target_ebb == ebb)
46     }
47 
48     /// Access the whole table as a slice.
49     pub fn as_slice(&self) -> &[Ebb] {
50         self.table.as_slice()
51     }
52 
53     /// Access the whole table as a mutable slice.
54     pub fn as_mut_slice(&mut self) -> &mut [Ebb] {
55         self.table.as_mut_slice()
56     }
57 
58     /// Returns an iterator over the table.
59     pub fn iter(&self) -> Iter<Ebb> {
60         self.table.iter()
61     }
62 
63     /// Returns an iterator that allows modifying each value.
64     pub fn iter_mut(&mut self) -> IterMut<Ebb> {
65         self.table.iter_mut()
66     }
67 }
68 
69 impl Display for JumpTableData {
70     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 ebb in self.table.iter().skip(1) {
77             write!(fmt, ", {}", ebb)?;
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::Ebb;
88     use alloc::string::ToString;
89 
90     #[test]
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]
104     fn insert() {
105         let e1 = Ebb::new(1);
106         let e2 = Ebb::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 [ebb1, ebb2, ebb1]");
115 
116         let v = jt.as_slice();
117         assert_eq!(v, [e1, e2, e1]);
118     }
119 }
120