Re-use memory with a free-list

master
Raymon Zutekouw 3 years ago
parent 64f097b0ff
commit 2aeb187b36
Signed by: raymon
GPG Key ID: 0E62222846283925
  1. 62
      src/main.rs

@ -24,13 +24,14 @@ struct MemCell {
} }
impl MemCell { impl MemCell {
pub fn allocate(address: u32) -> Self { pub fn allocate_to(address: u32) -> Self {
Self { address } Self { address }
} }
} }
struct State { struct State {
alloc_cnt: u32, alloc_cnt: u32,
free_list: Vec<u32>,
mem_pointer: u32, mem_pointer: u32,
variables: HashMap<String, MemCell>, variables: HashMap<String, MemCell>,
} }
@ -71,23 +72,35 @@ fn to_bf(rule: Rule, operand: &str, state: &mut State, out: &mut Builder) {
match rule { match rule {
Rule::var => { Rule::var => {
let variable_name = operand; let variable_name = operand;
let mem_extension: u32;
let new_address: u32;
if !state.free_list.is_empty() {
new_address = state.free_list.pop().unwrap();
mem_extension = 0;
} else {
new_address = state.alloc_cnt;
mem_extension = 1;
}
if let Some(_v) = state.variables.insert( if let Some(_v) = state.variables.insert(
String::from(variable_name), String::from(variable_name),
MemCell::allocate(state.alloc_cnt), MemCell::allocate_to(new_address),
) { ) {
panic!("Variable '{}' already exists", variable_name); panic!("Variable '{}' already exists", variable_name);
} }
state.alloc_cnt += 1; state.alloc_cnt += mem_extension;
} }
Rule::delvar => { Rule::delvar => {
let variable_name = operand; let variable_name = operand;
if state let memcell = state
.variables .variables
.remove(&String::from(variable_name)) .get(variable_name)
.is_none() .ok_or_else(|| format!("Variable '{}' did not exists", variable_name))
{ .unwrap();
panic!("Variable '{}' did not exists", variable_name); state.free_list.push(memcell.address);
} state.variables.remove(&String::from(variable_name));
} }
Rule::point => { Rule::point => {
let variable_name = operand; let variable_name = operand;
@ -234,6 +247,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut state = State { let mut state = State {
alloc_cnt: 0, alloc_cnt: 0,
free_list: Vec::new(),
mem_pointer: 0, mem_pointer: 0,
variables: HashMap::new(), variables: HashMap::new(),
}; };
@ -268,4 +282,34 @@ mod tests {
"Char literals are declared with \"_\", not \'_\'" "Char literals are declared with \"_\", not \'_\'"
); );
} }
#[test]
fn test_reuse_of_free_memcells() {
let mut builder = Builder::default();
let mut state = State {
alloc_cnt: 0,
free_list: Vec::new(),
mem_pointer: 0,
variables: HashMap::new(),
};
to_bf(Rule::var, "abc", &mut state, &mut builder);
assert_eq!(state.alloc_cnt, 1);
to_bf(Rule::delvar, "abc", &mut state, &mut builder);
assert_eq!(
state.alloc_cnt, 1,
"allocation should not be shrunken, that is too costly"
);
to_bf(Rule::var, "def", &mut state, &mut builder);
assert_ne!(
state.alloc_cnt, 2,
"the just de-allocated memorycell should be re-used"
);
assert_eq!(
state.alloc_cnt, 1,
"alloc, dealloc, alloc has a max usage of one memorycell"
);
}
} }

Loading…
Cancel
Save