use super::PlacementIndex;
#[derive(Clone, Debug, Default)]
pub struct LinearScanIndex {
bins: Vec<(usize, usize)>,
}
impl LinearScanIndex {
pub fn new() -> Self {
Self { bins: Vec::new() }
}
}
impl PlacementIndex for LinearScanIndex {
fn insert_bin(&mut self, bin_id: usize, remaining: usize) {
self.bins.push((bin_id, remaining));
}
fn update_bin(&mut self, bin_id: usize, _old_remaining: usize, new_remaining: usize) {
for entry in &mut self.bins {
if entry.0 == bin_id {
entry.1 = new_remaining;
return;
}
}
}
fn first_fit(&self, needed: usize) -> Option<usize> {
self.bins
.iter()
.filter(|(_, rem)| *rem >= needed)
.min_by_key(|(id, _)| *id)
.map(|(id, _)| *id)
}
fn best_fit(&self, needed: usize) -> Option<usize> {
self.bins
.iter()
.filter(|(_, rem)| *rem >= needed)
.min_by_key(|(id, rem)| (*rem, *id))
.map(|(id, _)| *id)
}
fn worst_fit(&self, needed: usize) -> Option<usize> {
self.bins
.iter()
.filter(|(_, rem)| *rem >= needed)
.max_by_key(|(_, rem)| *rem)
.map(|(id, _)| *id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert_bin() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 100);
idx.insert_bin(1, 50);
assert_eq!(idx.first_fit(50), Some(0));
assert_eq!(idx.first_fit(100), Some(0));
}
#[test]
fn test_update_bin() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 10);
idx.insert_bin(1, 10);
idx.update_bin(0, 10, 3);
assert_eq!(idx.first_fit(5), Some(1));
assert_eq!(idx.first_fit(3), Some(0));
}
#[test]
fn test_update_bin_to_zero() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 10);
idx.update_bin(0, 10, 0);
assert_eq!(idx.first_fit(1), None);
}
#[test]
fn test_first_fit_leftmost() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 2);
idx.insert_bin(1, 7);
idx.insert_bin(2, 7);
assert_eq!(idx.first_fit(6), Some(1));
}
#[test]
fn test_first_fit_none() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 5);
idx.insert_bin(1, 3);
assert_eq!(idx.first_fit(6), None);
}
#[test]
fn test_first_fit_exact() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 5);
assert_eq!(idx.first_fit(5), Some(0));
}
#[test]
fn test_first_fit_empty_index() {
let idx = LinearScanIndex::new();
assert_eq!(idx.first_fit(1), None);
}
#[test]
fn test_best_fit_tightest() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 9);
idx.insert_bin(1, 6);
idx.insert_bin(2, 6);
assert_eq!(idx.best_fit(5), Some(1));
}
#[test]
fn test_best_fit_exact_match() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 10);
idx.insert_bin(1, 5);
idx.insert_bin(2, 8);
assert_eq!(idx.best_fit(5), Some(1));
}
#[test]
fn test_best_fit_none() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 3);
assert_eq!(idx.best_fit(5), None);
}
#[test]
fn test_worst_fit_loosest() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 3);
idx.insert_bin(1, 9);
idx.insert_bin(2, 6);
assert_eq!(idx.worst_fit(5), Some(1));
}
#[test]
fn test_worst_fit_none() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 3);
idx.insert_bin(1, 4);
assert_eq!(idx.worst_fit(5), None);
}
#[test]
fn test_all_methods_agree_single_candidate() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 2);
idx.insert_bin(1, 5);
assert_eq!(idx.first_fit(5), Some(1));
assert_eq!(idx.best_fit(5), Some(1));
assert_eq!(idx.worst_fit(5), Some(1));
}
#[test]
fn test_all_methods_none_when_nothing_fits() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 3);
assert_eq!(idx.first_fit(5), None);
assert_eq!(idx.best_fit(5), None);
assert_eq!(idx.worst_fit(5), None);
}
#[test]
fn test_insert_place_update_cycle() {
let mut idx = LinearScanIndex::new();
idx.insert_bin(0, 10);
assert_eq!(idx.best_fit(7), Some(0));
idx.update_bin(0, 10, 3);
assert_eq!(idx.best_fit(5), None);
idx.insert_bin(1, 10);
assert_eq!(idx.best_fit(5), Some(1));
idx.update_bin(1, 10, 5);
assert_eq!(idx.best_fit(3), Some(0));
}
}