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