use crate::ResizeError;
pub trait GrowStrategy {
fn try_grow(
&mut self,
min_req_len: MinimumRequiredLength,
old_len: usize,
bit_idx: usize,
) -> Result<FinalLength, ResizeError>;
fn is_force_grow(&self) -> bool {
false
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MinimumRequiredStrategy;
impl GrowStrategy for MinimumRequiredStrategy {
fn try_grow(
&mut self,
min_req_len: MinimumRequiredLength,
_old_len: usize,
_bit_idx: usize,
) -> Result<FinalLength, ResizeError> {
Ok(min_req_len.finalize())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct FixedStrategy(pub usize);
impl GrowStrategy for FixedStrategy {
fn try_grow(
&mut self,
min_req_len: MinimumRequiredLength,
_old_len: usize,
_bit_idx: usize,
) -> Result<FinalLength, ResizeError> {
if min_req_len.value() % self.0 == 0 {
Ok(min_req_len.finalize())
} else {
let rest = (min_req_len.value() / self.0 + 1) * self.0 - min_req_len.value();
Ok(min_req_len.advance_by(rest))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LimitStrategy<S> {
pub strategy: S,
pub limit: usize,
}
impl<S> GrowStrategy for LimitStrategy<S>
where
S: GrowStrategy,
{
fn try_grow(
&mut self,
min_req_len: MinimumRequiredLength,
old_len: usize,
bit_idx: usize,
) -> Result<FinalLength, ResizeError> {
let final_length = self.strategy.try_grow(min_req_len, old_len, bit_idx)?;
if final_length.value() <= self.limit {
Ok(final_length)
} else {
Err(ResizeError::new(format!(
"the new size {} is over the limit {}",
final_length.value(),
self.limit
)))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ForceGrowStrategy<S>(pub S);
impl<S> GrowStrategy for ForceGrowStrategy<S>
where
S: GrowStrategy,
{
fn try_grow(
&mut self,
min_req_len: MinimumRequiredLength,
old_len: usize,
bit_idx: usize,
) -> Result<FinalLength, ResizeError> {
self.0.try_grow(min_req_len, old_len, bit_idx)
}
fn is_force_grow(&self) -> bool {
true
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct MinimumRequiredLength(pub(crate) usize);
impl MinimumRequiredLength {
#[inline]
pub fn advance_by(self, v: usize) -> FinalLength {
FinalLength(self.0 + v)
}
#[inline]
pub fn finalize(self) -> FinalLength {
FinalLength(self.0)
}
#[inline]
pub fn value(&self) -> usize {
self.0
}
#[doc(hidden)]
pub fn new_unchecked(v: usize) -> Self {
Self(v)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct FinalLength(pub(crate) usize);
impl FinalLength {
#[inline]
pub fn value(&self) -> usize {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[rustfmt::skip]
fn test_minimal() {
let mut s = MinimumRequiredStrategy::default();
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 1, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 2, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 3, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 4, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 5, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 1, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 2, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 3, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 4, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 5, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 1, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 2, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 3, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 4, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 5, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(21), 5, 0).unwrap().value(), 21);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(25), 5, 0).unwrap().value(), 25);
}
#[test]
#[rustfmt::skip]
fn test_fixed() {
let mut s = FixedStrategy(3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 1, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 2, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 3, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 4, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 5, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 1, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 2, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 3, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 4, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 5, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 1, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 2, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 3, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 4, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 5, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 1, 0).unwrap().value(), 6);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 2, 0).unwrap().value(), 6);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 3, 0).unwrap().value(), 6);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 4, 0).unwrap().value(), 6);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 5, 0).unwrap().value(), 6);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(21), 5, 0).unwrap().value(), 21);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(25), 5, 0).unwrap().value(), 27);
}
#[test]
#[rustfmt::skip]
fn test_limit() {
let mut s = LimitStrategy{ strategy: MinimumRequiredStrategy, limit: 3 };
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 1, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 2, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 3, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 4, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(1), 5, 0).unwrap().value(), 1);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 1, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 2, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 3, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 4, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(2), 5, 0).unwrap().value(), 2);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 1, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 2, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 3, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 4, 0).unwrap().value(), 3);
assert_eq!(s.try_grow(MinimumRequiredLength::new_unchecked(3), 5, 0).unwrap().value(), 3);
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 1, 0).is_err());
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 2, 0).is_err());
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 3, 0).is_err());
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 4, 0).is_err());
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(4), 5, 0).is_err());
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(21), 5, 0).is_err());
assert!(s.try_grow(MinimumRequiredLength::new_unchecked(25), 5, 0).is_err());
}
}