Skip to main content

hash_roll/
ram.rs

1#![cfg(feature = "ram")]
2
3//! Rapid Asymmetric Maximum (RAM) is a fast chunking algorithm
4//!
5//! - Has a minimum block size (it's "window" size)
6//! - Does not provide an upper bound on block size (though paper discusses a RAML variant that
7//!   does).
8//!
9//! doi:10.1016/j.future.2017.02.013
10//!
11use crate::{Chunk, ToChunkIncr, ChunkIncr};
12
13/// Parameters for the Rapid Asymmetric Maximum (RAM) chunking algorithm
14///
15/// Is window free, with very small (
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct Ram {
18    /// window size
19    ///
20    /// fixed data
21    w: u64,
22}
23
24impl Ram {
25    /// Construct a RAM instance with window size `w`
26    ///
27    /// `w` is also the minimum block size
28    pub fn with_w(w: u64) -> Self {
29        Self {
30            w,
31        }
32    }
33}
34
35impl Chunk for Ram {
36    type SearchState = RamState;
37
38    fn to_search_state(&self) -> Self::SearchState {
39        Default::default()
40    }
41
42    fn find_chunk_edge(&self, state: &mut Self::SearchState, data: &[u8]) -> (Option<usize>, usize) {
43        match state.push(self, data) {
44            Some(i) => (Some(i + 1), i + 1),
45            None => (None, data.len())
46        }
47    }
48}
49
50#[derive(Default, Debug, PartialEq, Eq, Clone)]
51pub struct RamState {
52    /// global index (number of processed bytes since split)
53    i: u64,
54
55    ///
56    max_val: u8,
57}
58
59impl RamState {
60    fn push(&mut self, params: &Ram, data: &[u8]) -> Option<usize> {
61        let i = self.i;
62
63        for (l_i, b) in data.iter().cloned().enumerate() {
64            if b >= self.max_val {
65                // minimum block size
66                let ri = l_i as u64 + i;
67                if ri > params.w {
68                    self.i = 0;
69                    self.max_val = 0;
70                    return Some(l_i);
71                }
72
73                self.max_val = b;
74            }
75        }
76
77        self.i += data.len() as u64;
78        None
79    }
80}
81
82impl ToChunkIncr for Ram {
83    type Incr = RamIncr;
84
85    fn to_chunk_incr(&self) -> Self::Incr {
86        self.into()
87    }
88}
89
90impl From<&Ram> for RamIncr {
91    fn from(params: &Ram) -> Self {
92        Self {
93            params: params.clone(),
94            state: Default::default(),
95        }
96    }
97}
98
99#[derive(Debug, PartialEq, Eq, Clone)]
100pub struct RamIncr {
101    params: Ram,
102    state: RamState,
103}
104
105impl ChunkIncr for RamIncr {
106    fn push(&mut self, data: &[u8]) -> Option<usize> {
107        self.state.push(&self.params, data) 
108    }
109}