use std::usize;
use crate::{Bin, Pack};
use super::OnlinePacker;
#[derive(Debug)]
pub struct NextKFitPacker<Item, SizeFn> {
bins: Vec<Bin<Item>>,
max_bin_size: usize,
size_fn: SizeFn,
}
impl<Item, SizeFn> NextKFitPacker<Item, SizeFn> {
pub fn new_with_key(k: usize, size: usize, size_fn: SizeFn) -> Self {
assert_ne!(k, 0, "k must be greater than 0");
assert_ne!(size, 0, "size must be greater than 0");
Self {
bins: (0..k).map(|_| Bin::with_capacity(size)).collect::<Vec<_>>(),
max_bin_size: size,
size_fn,
}
}
}
impl<Item> NextKFitPacker<Item, fn(&Item) -> usize> {
pub fn new(k: usize, size: usize) -> NextKFitPacker<Item, fn(&Item) -> usize>
where
Item: Pack,
{
fn pack_size(item: &impl Pack) -> usize {
item.size()
}
NextKFitPacker::<Item, _>::new_with_key(k, size, pack_size)
}
}
impl<Item, SizeFn> OnlinePacker<Item> for NextKFitPacker<Item, SizeFn>
where
SizeFn: Fn(&Item) -> usize,
{
fn try_add(
&mut self,
item: Item,
) -> Result<Vec<Bin<Item>>, super::online_packer::OnlinePackerError<Item>> {
let item_size = (self.size_fn)(&item);
if item_size > self.max_bin_size {
return Err(super::online_packer::OnlinePackerError::ItemTooLarge(item));
}
let mut most_filled_bin_idx = 0;
let mut most_filled_bin_capacity = usize::MAX;
for (bin_idx, bin) in self.bins.iter_mut().enumerate() {
if bin.remaining_capacity < most_filled_bin_capacity {
most_filled_bin_idx = bin_idx;
most_filled_bin_capacity = bin.remaining_capacity;
}
if item_size <= bin.remaining_capacity {
bin.add_with_size(item, item_size);
return Ok(Vec::new());
}
}
let mut bin = Bin::with_item_and_size(self.max_bin_size, item, item_size);
std::mem::swap(&mut self.bins[most_filled_bin_idx], &mut bin);
Ok(vec![bin])
}
fn finalize(mut self) -> Vec<Bin<Item>> {
self.bins.retain(|bin| !bin.contents.is_empty());
self.bins
}
}
#[cfg(test)]
mod tests {
use crate::tests::{generate_test_bins, generate_test_set_a, MyItem};
use super::*;
#[test]
fn empty_input_returns_no_bins() {
let packer: NextKFitPacker<MyItem, _> = NextKFitPacker::new(3, 10);
assert_eq!(packer.finalize(), vec![]);
let packer: NextKFitPacker<MyItem, _> = NextKFitPacker::new(3, 10);
assert_eq!(packer.pack_all(vec![].into_iter()).unwrap(), vec![]);
}
#[test]
fn test_dataset_a_k1() {
let (test_data, bin_size) = generate_test_set_a();
let packer = NextKFitPacker::new(1, bin_size);
let bins = packer.pack_all(test_data.into_iter()).unwrap();
let expected = generate_test_bins(
20,
vec![
vec![1, 1, 1, 1, 3, 4], vec![10, 10], vec![10], vec![19], vec![19], ],
);
assert_eq!(expected, bins);
}
#[test]
fn test_dataset_a_k1_seq() {
let (test_data, bin_size) = generate_test_set_a();
let mut packer = NextKFitPacker::new(1, bin_size);
let mut expected = [
None,
None,
None,
None,
None,
None,
Some(vec![1, 1, 1, 1, 3, 4]),
None,
Some(vec![10, 10]),
Some(vec![10]),
Some(vec![19]),
Some(vec![19]),
]
.map(|opt| {
opt.map(|vec| Bin {
contents: vec.iter().map(|i| MyItem { size: *i }).collect::<Vec<_>>(),
remaining_capacity: bin_size - vec.iter().sum::<usize>(),
})
})
.into_iter();
for item in test_data {
let produced_bin = packer.add(item).into_iter().next();
let expected_bin = expected.next().unwrap();
match (&expected_bin, &produced_bin) {
(Some(expected), Some(actual)) => assert_eq!(expected, actual),
(None, None) => (),
_ => panic!("Expected {:?}, got {:?}", expected_bin, produced_bin),
}
}
let final_bins = packer.finalize();
for (bin, expected) in final_bins.iter().zip(expected) {
assert_eq!(bin.contents, expected.unwrap().into_contents());
}
}
#[test]
fn test_dataset_a_k2() {
let (test_data, bin_size) = generate_test_set_a();
let packer = NextKFitPacker::new(2, bin_size);
let mut bins = packer.pack_all(test_data.into_iter()).unwrap();
let expected = generate_test_bins(
20,
vec![
vec![10, 10], vec![1, 1, 1, 1, 3, 4], vec![19], vec![19], vec![10], ],
);
println!("{:#?}", bins);
assert_eq!(expected, bins);
}
}