~raph/xi2

502b06bc2e0990f42087f8384d09a99f83547f8c — Raph Levien 1 year, 4 months ago e0c6afc
Checkpoint generic HeightRope

I'm going to commit the generic version of the HeightRope as a
checkpoint. Right now, I think this will go easier if I take it
non-generic, as it's starting to feel pretty specialized.
1 files changed, 88 insertions(+), 20 deletions(-)

M xi-druid/src/height_rope.rs
M xi-druid/src/height_rope.rs => xi-druid/src/height_rope.rs +88 -20
@@ 8,11 8,64 @@ use std::marker::PhantomData;
#[derive(Clone)]
pub struct Vector<T: Clone>(Node<VectorInfo<T>>);

/// A type representing a height measure.
///
/// Internally this is stored as `usize` using fixed point arithmetic,
/// for two reasons. First, it lets the rope reuse the `Metric` mechanism.
/// Second, it means that the monoid property is exact, which would not be
/// the case for `f64`.
///
/// Currently, there are 8 bits of fraction. On 32 bit platforms, that
/// means a maximum height of 16M, which should be good enough for most
/// practical use but could be a limitation. Of course, on 64 bit platforms,
/// the limit of 7.2e16 should never be a problem.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Height(usize);

impl std::ops::Add for Height {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Height(self.0 + other.0)
    }
}

impl std::ops::AddAssign for Height {
    fn add_assign(&mut self, other: Self) {
        self.0 += other.0
    }
}


impl Height {
    /// The number of fractional bits in the representation.
    pub const HEIGHT_FRAC_BITS: usize = 8;

    /// The scale factor for converting from `f64`.
    pub const SCALE_FACTOR: f64 = (1 << Self::HEIGHT_FRAC_BITS) as f64;

    pub fn from_raw_frac(frac: usize) -> Height {
        Height(frac)
    }

    pub fn as_raw_frac(self) -> usize {
        self.0
    }

    pub fn from_f64(height: f64) -> Height {
        Height((height * Self::SCALE_FACTOR).round() as usize)
    }

    pub fn to_f64(self) -> f64 {
        self.0 as f64 * Self::SCALE_FACTOR.recip()
    }
}

// This technically doesn't have to be newtyped, we could impl leaf on
// Vec directly.
#[derive(Clone)]
pub struct VectorLeaf<T> {
    data: Vec<T>,
    data: Vec<(Height, T)>,
}

// Have to implement by hand because rust issue #26925


@@ 24,16 77,24 @@ impl<T> Default for VectorLeaf<T> {

#[derive(Clone)]
pub struct VectorInfo<T> {
    /// The height of this section of rope.
    height: Height,
    phantom: PhantomData<T>,
}

impl<T: Clone> NodeInfo for VectorInfo<T> {
    type L = VectorLeaf<T>;

    fn accumulate(&mut self, _other: &Self) {}
    fn accumulate(&mut self, other: &Self) {
        self.height += other.height;
    }

    fn compute_info(_: &Self::L) -> Self {
        VectorInfo { phantom: Default::default() }
    fn compute_info(leaf: &Self::L) -> Self {
        let mut height = Height::default();
        for (leaf_height, _) in &leaf.data {
            height += *leaf_height;
        }
        VectorInfo { height, phantom: Default::default() }
    }
}



@@ 62,33 123,38 @@ impl<T: Clone> Leaf for VectorLeaf<T> {
    }
}

impl<T: Clone> From<Vec<T>> for Vector<T> {
    fn from(v: Vec<T>) -> Self {
impl<T: Clone> From<Vec<(Height, T)>> for Vector<T> {
    fn from(v: Vec<(Height, T)>) -> Self {
        Vector(Node::from_leaf(VectorLeaf { data: v }))
    }
}

// This probably shouldn't expose the internal representation as a pair. A deeper
// question is whether it should even be generic.

impl<T: Clone> Vector<T> {
    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn singleton(item: T) -> Vector<T> {
        vec![item].into()
    pub fn singleton(height: Height, item: T) -> Vector<T> {
        vec![(height, item)].into()
    }

    pub fn get(&self, index: usize) -> Option<&T> {
    pub fn get(&self, index: usize) -> Option<&(Height, T)> {
        let cursor = Cursor::new(&self.0, index);
        cursor.get_leaf().and_then(|(leaf, offset)| leaf.data.get(offset))
    }

    // Note: we can do get_mut too, but that requires mutable leaf access.

    pub fn push(&mut self, item: T) {
    pub fn push(&mut self, height: Height, item: T) {
        let el = Self::singleton(height, item);
        // This could be optimized more.
        self.0 = Node::concat(self.0.clone(), Self::singleton(item).0)
        self.0 = Node::concat(self.0.clone(), el.0)
    }

    // These mutation methods are not super-satisfying; for the general incremental
    // algorithm case, we're going to want to expose builder methods.

    pub fn remove(&mut self, index: usize) {
        let mut b = TreeBuilder::new();
        self.push_subseq(&mut b, Interval::new(0, index));


@@ 96,18 162,18 @@ impl<T: Clone> Vector<T> {
        self.0 = b.build();
    }

    pub fn set(&mut self, index: usize, value: T) {
    pub fn set(&mut self, index: usize, height: Height, value: T) {
        let mut b = TreeBuilder::new();
        self.push_subseq(&mut b, Interval::new(0, index));
        b.push_leaf(VectorLeaf { data: vec![value]});
        b.push_leaf(VectorLeaf { data: vec![(height, value)]});
        self.push_subseq(&mut b, Interval::new(index + 1, self.len()));
        self.0 = b.build();
    }

    pub fn insert(&mut self, index: usize, value: T) {
    pub fn insert(&mut self, index: usize, height: Height, value: T) {
        let mut b = TreeBuilder::new();
        self.push_subseq(&mut b, Interval::new(0, index));
        b.push_leaf(VectorLeaf { data: vec![value]});
        b.push_leaf(VectorLeaf { data: vec![(height, value)]});
        self.push_subseq(&mut b, Interval::new(index, self.len()));
        self.0 = b.build();
    }


@@ 126,7 192,9 @@ impl<T: Clone> Vector<T> {
}

impl<'a, T: Clone> IntoIterator for &'a Vector<T> {
    type Item = &'a T;
    // Maybe `(Height, &'a T)` would be better, not to expose the internal
    // tuple, but it's a bit more work.
    type Item = &'a (Height, T);

    type IntoIter = std::iter::Flatten<ChunkIter<'a, T>>;



@@ 141,9 209,9 @@ pub struct ChunkIter<'a, T: Clone> {
}

impl<'a, T: Clone> Iterator for ChunkIter<'a, T> {
    type Item = &'a [T];
    type Item = &'a [(Height, T)];

    fn next(&mut self) -> Option<&'a [T]> {
    fn next(&mut self) -> Option<Self::Item> {
        if self.cursor.pos() >= self.end {
            return None;
        }