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