From a6c98b8f4369fe8a2040224768f8e8c161872d8e Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Sat, 9 Mar 2024 19:20:43 -0500 Subject: [PATCH] De-duplicate bridge replacement code --- crates/lox-library/src/lib.rs | 113 +++++++++++++--------------------- 1 file changed, 42 insertions(+), 71 deletions(-) diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 6152d97..bb8e7eb 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -547,85 +547,56 @@ impl BridgeAuth { let Some(positions) = reachable_bridges.get(bridge) else { return res; }; - if let Some(replacement) = available_bridge { - for (bucketnum, offset) in positions.iter() { - let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) { - Some(bridgelines) => *bridgelines, - None => return ReplaceSuccess::NotFound, + // select replacement: + // - first try the given bridge + // - second try to pick one from the set of available bridges + // - third dissolve a spare bucket to create more available bridges + let Some(replacement) = available_bridge.or_else(|| { + self.bridge_table.unallocated_bridges.pop().or_else(|| { + // First get the bucketnums for the replacement bridge in case it is a spare + let mut bucketnums: Vec = Vec::new(); + for (bucketnum, _) in positions.iter() { + bucketnums.push(*bucketnum); + } + let Some(spare) = self + .bridge_table + .spares + .iter() + .find(|x| !bucketnums.contains(x)) + .cloned() + else { + return None; }; - assert!(bridgelines[*offset] == *bridge); - bridgelines[*offset] = replacement; - self.bridge_table.buckets.insert(*bucketnum, bridgelines); - // Remove the bridge from the reachable bridges and add new bridge - self.bridge_table - .reachable - .insert(replacement, positions.clone()); - // Remove the bridge from the bucket - self.bridge_table.reachable.remove(bridge); - } - res = ReplaceSuccess::Replaced - } else if !self.bridge_table.unallocated_bridges.is_empty() { - let replacement = &self.bridge_table.unallocated_bridges.pop().unwrap(); - for (bucketnum, offset) in positions.iter() { - let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) { - Some(bridgelines) => *bridgelines, - // This should not happen if the rest of the function is correct, we can assume unwrap will succeed - None => return ReplaceSuccess::NotReplaced, + let Ok(_) = self.dissolve_spare_bucket(spare) else { + return None; }; - assert!(bridgelines[*offset] == *bridge); - bridgelines[*offset] = *replacement; - self.bridge_table.buckets.insert(*bucketnum, bridgelines); - self.bridge_table - .reachable - .insert(*replacement, positions.clone()); - // Remove the bridge from the bucket - self.bridge_table.reachable.remove(bridge); - } - res = ReplaceSuccess::Replaced - } else if !self.bridge_table.spares.is_empty() { - // First get the bucketnums for the replacement bridge in case it is a spare - let mut bucketnums: Vec = Vec::new(); - for (bucketnum, _) in positions.iter() { - bucketnums.push(*bucketnum); - } - // Get the first spare and remove it from the spares set. - let Some(spare) = self - .bridge_table - .spares - .iter() - .find(|x| !bucketnums.contains(x)) - .cloned() - else { - return ReplaceSuccess::NotReplaced; - }; - let Ok(_) = self.dissolve_spare_bucket(spare) else { - return ReplaceSuccess::NotReplaced; - }; - let replacement = &self.bridge_table.unallocated_bridges.pop().unwrap(); - for (bucketnum, offset) in positions.iter() { - let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) { - Some(bridgelines) => *bridgelines, - None => return ReplaceSuccess::NotReplaced, - }; - assert!(bridgelines[*offset] == *bridge); - bridgelines[*offset] = *replacement; - self.bridge_table.buckets.insert(*bucketnum, bridgelines); - self.bridge_table - .reachable - .insert(*replacement, positions.clone()); - // Remove the bridge from the bucket - self.bridge_table.reachable.remove(bridge); - } - res = ReplaceSuccess::Replaced - } else { - println!("No available bridges"); + self.bridge_table.unallocated_bridges.pop() + }) + }) else { // If there are no available bridges that can be assigned here, the only thing // that can be done is return an indication that updating the gone bridge // didn't work. // In this case, we do not mark the bridge as unreachable or remove it from the // reachable bridges so that we can still find it when a new bridge does become available - res = ReplaceSuccess::NotReplaced + println!("No available bridges"); + return ReplaceSuccess::NotReplaced; + }; + for (bucketnum, offset) in positions.iter() { + let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) { + Some(bridgelines) => *bridgelines, + None => return ReplaceSuccess::NotFound, + }; + assert!(bridgelines[*offset] == *bridge); + bridgelines[*offset] = replacement; + self.bridge_table.buckets.insert(*bucketnum, bridgelines); + // Remove the bridge from the reachable bridges and add new bridge + self.bridge_table + .reachable + .insert(replacement, positions.clone()); + // Remove the bridge from the bucket + self.bridge_table.reachable.remove(bridge); } + res = ReplaceSuccess::Replaced; res }