~asayers/inukshuk

1cb651d5b6c24c5f5cde34dfbabdad9c4aaaa2f3 — Alex Sayers 5 years ago 67ecdca leveled
WIP
1 files changed, 108 insertions(+), 58 deletions(-)

M src/item.rs
M src/item.rs => src/item.rs +108 -58
@@ 14,8 14,7 @@ use std::str::FromStr;
pub struct Item {
    path: PathBuf,
    file: BufReader<File>,
    forward_patches: Leveled,
    reverse_patches: FlatVec<PatchOperation>,
    cache: PatchCache,
    pub timestamps: Vec<Option<DateTime<Utc>>>,
    pub crcs: Vec<u32>,
    head_val: Value,


@@ 28,8 27,7 @@ impl Item {
        Ok(Item {
            path: path.into(),
            file: BufReader::new(file),
            forward_patches: Leveled::new(),
            reverse_patches: FlatVec::new(),
            cache: PatchCache::new(),
            timestamps: vec![None],
            head_val: json!({}),
            crcs: vec![2745614147],


@@ 57,12 55,7 @@ impl Item {
            let p = line.patch;
            let old_head = self.head_val.clone();
            patch(&mut self.head_val, &p).map_err(|e| Error::BadPatch(e))?;
            // FIXME: This is a naive implementation and can surely be improved in
            // terms of performance.
            let mut r = diff(&self.head_val, &old_head);
            r.0.reverse();
            self.forward_patches.push(&p);
            self.reverse_patches.push(&r.0);
            self.cache.push(&p)?;
            self.timestamps.push(line.ts);
            // TODO: share?
            let mut h = crc32fast::Hasher::new();


@@ 84,17 77,7 @@ impl Item {
            json_patch::from_value(json!([{"op":"add", "path":"", "value": self.head_val}]))
                .unwrap()
        } else {
            Patch(match to.cmp(&from) {
                Ordering::Equal => Vec::new(),
                Ordering::Greater => self.forward_patches.get(from, to)?,
                Ordering::Less => {
                    let ps = self.reverse_patches.get(to, from).unwrap();
                    let mut p = Vec::new();
                    p.extend_from_slice(ps);
                    p.reverse();
                    p
                }
            })
            self.cache.get(from, to)?
        };
        let patch = minimize(patch);
        Ok((from, to, patch))


@@ 156,64 139,131 @@ impl RevSpec {
}

#[derive(Clone, Debug)]
struct Leveled {
    l_0: FlatVec<PatchOperation>, // all elements
    l_1: FlatVec<PatchOperation>, // mod 16
    l_2: FlatVec<PatchOperation>, // mod 256
    l_3: FlatVec<PatchOperation>, // mod 4096
struct Leveled<T> {
    l_0: FlatVec<T>, // all elements
    l_1: FlatVec<T>, // mod 16
    l_2: FlatVec<T>, // mod 256
    l_3: FlatVec<T>, // mod 4096
}

struct PatchCache {
    forward: Leveled<PatchOperation>,
    reverse: Leveled<PatchOperation>,
    head_0: Value,
    head_1: Value,
    head_2: Value,
    head_3: Value,
}

impl Leveled {
    fn new() -> Leveled {
impl<T> Leveled<T> {
    fn new() -> Leveled<T> {
        Leveled {
            l_0: FlatVec::new(),
            l_1: FlatVec::new(),
            l_2: FlatVec::new(),
            l_3: FlatVec::new(),
            head_0: json!({}),
            head_1: json!({}),
            head_2: json!({}),
            head_3: json!({}),
        }
    }

    fn len(&self) -> usize {
        self.l_0.len()
    }

    // TODO: We may be able to reduce the bounds-checking here.
    fn get(&self, from: usize, to: usize) -> Result<Vec<PatchOperation>, Error> {
    fn get(&self, from: usize, upto: usize) -> Result<Vec<T>, Error> {
        let mut ret = Vec::new();
        ret.extend_from_slice(self.l_0.get(from, 16 * (from / 16)).unwrap_or(&[][..]));
        ret.extend_from_slice(self.l_1.get(from / 16, 16 * (from / 256)).unwrap_or(&[][..]));
        ret.extend_from_slice(self.l_2.get(from / 256, 16 * (from / 4096)).unwrap_or(&[][..]));
        ret.extend_from_slice(self.l_3.get(from / 4096, to / 4096).unwrap_or(&[][..]));
        ret.extend_from_slice(self.l_2.get(16 * (to / 4096), to / 256).unwrap_or(&[][..]));
        ret.extend_from_slice(self.l_1.get(16 * (to / 256), to / 16).unwrap_or(&[][..]));
        ret.extend_from_slice(self.l_0.get(16 * (to / 16), to).unwrap_or(&[][..]));
        ret.extend_from_slice(
            self.l_1
                .get(from / 16, 16 * (from / 256))
                .unwrap_or(&[][..]),
        );
        ret.extend_from_slice(
            self.l_2
                .get(from / 256, 16 * (from / 4096))
                .unwrap_or(&[][..]),
        );
        ret.extend_from_slice(self.l_3.get(from / 4096, upto / 4096).unwrap_or(&[][..]));
        ret.extend_from_slice(
            self.l_2
                .get(16 * (upto / 4096), upto / 256)
                .unwrap_or(&[][..]),
        );
        ret.extend_from_slice(
            self.l_1
                .get(16 * (upto / 256), upto / 16)
                .unwrap_or(&[][..]),
        );
        ret.extend_from_slice(self.l_0.get(16 * (upto / 16), upto).unwrap_or(&[][..]));
        Ok(ret)
    }
}

    fn len(&self) -> usize {
        self.l_0.len()
impl PatchCache {
    fn new() -> PatchCache {
        PatchCache {
            forward: Leveled::new(),
            reverse: Leveled::new(),
            head_0: json!({}),
            head_1: json!({}),
            head_2: json!({}),
            head_3: json!({}),
        }
    }

    fn get(from: usize, to: usize) -> Result<Patch, Error> {
        let ops = match to.cmp(&from) {
            Ordering::Equal => Vec::new(),
            Ordering::Greater => self.forward.get(from, to)?,
            Ordering::Less => {
                let ops = self.reverse.get(to, from)?;
                ops.reverse();
                ops
            }
        };
        Ok(Patch(ops))
    }

    fn push(&mut self, p_0: &Patch) -> Result<(), Error> {
        fn fdiff(from: &Value, to: &Value) -> Patch {
            diff(from, to)
        }
        fn rdiff(from: &Value, to: &Value) -> Patch {
            let mut r = diff(to, from);
            r.0.reverse();
            r
        }

        let old_head_0 = self.head_0.clone();
        patch(&mut self.head_0, &p_0).map_err(|e| Error::BadPatch(e))?;
        self.l_0.push(&p_0.0);
        if self.l_0.len() % 16 == 0 {
            let p_1 = diff(&self.head_1, &self.head_0);
            self.l_1.push(&p_1.0);

        let mut r_0 = rdiff(&old_head_0, &self.head_0);

        self.forward.l_0.push(&p_0.0);
        self.reverse.l_0.push(&r_0.0);

        assert_eq!(self.forward.l_0.len(), self.reverse.l_0.len());
        let rev = self.forward.l_0.len();

        if rev % 16 == 0 {
            let p_1 = fdiff(&self.head_1, &self.head_0);
            let r_1 = rdiff(&self.head_1, &self.head_0);
            self.forward.l_1.push(&p_1.0);
            self.reverse.l_1.push(&r_1.0);
            self.head_1 = self.head_0.clone();
        }
        if self.l_0.len() % 256 == 0 {
            let p_2 = diff(&self.head_2, &self.head_0);
            self.l_2.push(&p_2.0);
        if rev % 256 == 0 {
            let p_2 = fdiff(&self.head_2, &self.head_0);
            let r_2 = rdiff(&self.head_2, &self.head_0);
            self.forward.l_2.push(&p_2.0);
            self.reverse.l_2.push(&r_2.0);
            self.head_2 = self.head_0.clone();
        }
        if self.l_0.len() % 4096 == 0 {
            let p_3 = diff(&self.head_3, &self.head_0);
            self.l_3.push(&p_3.0);
        if rev % 4096 == 0 {
            let p_3 = fdiff(&self.head_3, &self.head_0);
            let r_3 = rdiff(&self.head_3, &self.head_0);
            self.forward.l_3.push(&p_3.0);
            self.reverse.l_3.push(&r_3.0);
            self.head_3 = self.head_0.clone();
        }
        Ok(())


@@ 221,18 271,18 @@ impl Leveled {

    fn push_rev(&mut self, p_0: &Patch) -> Result<(), Error> {
        patch(&mut self.head_0, &p_0).map_err(|e| Error::BadPatch(e))?;
        self.l_0.push(&p_0.0);
        if self.l_0.len() % 16 == 0 {
        self.reverse.l_0.push(&p_0.0);
        if self.reverse.l_0.len() % 16 == 0 {
            let p_1 = diff(&self.head_1, &self.head_0);
            self.l_1.push(&p_1.0);
            self.reverse.l_1.push(&p_1.0);
        }
        if self.l_0.len() % 256 == 0 {
        if self.reverse.l_0.len() % 256 == 0 {
            let p_2 = diff(&self.head_2, &self.head_0);
            self.l_2.push(&p_2.0);
            self.reverse.l_2.push(&p_2.0);
        }
        if self.l_0.len() % 4096 == 0 {
        if self.reverse.l_0.len() % 4096 == 0 {
            let p_3 = diff(&self.head_3, &self.head_0);
            self.l_3.push(&p_3.0);
            self.reverse.l_3.push(&p_3.0);
        }
        Ok(())
    }