@@ 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;
}