use std::sync::Arc;
use smallvec::SmallVec;
use crate::rope::{Measurable, Rope};
use crate::tree::{BranchChildren, LeafSlice, Node, MAX_LEN, MAX_CHILDREN, MIN_LEN};
#[derive(Debug, Clone)]
pub struct RopeBuilder<M>
where
M: Measurable,
{
stack: SmallVec<[Arc<Node<M>>; 4]>,
buffer: Vec<M>,
last_chunk_len: usize,
}
impl<M> RopeBuilder<M>
where
M: Measurable,
{
pub fn new() -> Self {
RopeBuilder {
stack: {
let mut stack = SmallVec::new();
stack.push(Arc::new(Node::new()));
stack
},
buffer: Vec::new(),
last_chunk_len: 0,
}
}
pub fn append_slice(&mut self, chunk: &[M]) {
self.append_internal(chunk, false);
}
pub fn append(&mut self, element: M) {
self.append_internal(&[element], false);
}
pub fn finish(mut self) -> Rope<M> {
self.append_internal(&[], true);
self.finish_internal(true)
}
pub(crate) fn build_at_once(mut self, chunk: &[M]) -> Rope<M> {
self.append_internal(chunk, true);
self.finish_internal(true)
}
#[doc(hidden)]
pub fn _append_chunk(&mut self, contents: &[M]) {
self.append_leaf_node(Arc::new(Node::Leaf(LeafSlice::from_slice(contents))));
}
#[doc(hidden)]
pub fn _finish_no_fix(self) -> Rope<M> {
self.finish_internal(false)
}
fn append_internal(&mut self, chunk: &[M], is_last_chunk: bool) {
let mut chunk = chunk;
while !chunk.is_empty() || (!self.buffer.is_empty() && is_last_chunk) {
let (leaf_slice, remainder) = self.get_next_leaf_slice(chunk, is_last_chunk);
chunk = remainder;
self.last_chunk_len = chunk.len();
match leaf_slice {
NextSlice::None => break,
NextSlice::UseBuffer => {
let leaf_slice = LeafSlice::from_slice(self.buffer.as_slice());
self.append_leaf_node(Arc::new(Node::Leaf(leaf_slice)));
self.buffer.clear();
}
NextSlice::Slice(s) => {
self.append_leaf_node(Arc::new(Node::Leaf(LeafSlice::from_slice(s))));
}
}
}
}
fn finish_internal(mut self, fix_tree: bool) -> Rope<M> {
let mut stack_index = self.stack.len() - 1;
while stack_index >= 1 {
let node = self.stack.pop().unwrap();
if let Node::Branch(ref mut children) = *Arc::make_mut(&mut self.stack[stack_index - 1])
{
children.push((node.slice_info(), node));
} else {
unreachable!();
}
stack_index -= 1;
}
let mut rope = Rope {
root: self.stack.pop().unwrap(),
};
if fix_tree {
Arc::make_mut(&mut rope.root).zip_fix_right();
if self.last_chunk_len < MIN_LEN && self.last_chunk_len != rope.len() {
let index = rope.width() - rope.index_to_width(rope.len() - self.last_chunk_len);
Arc::make_mut(&mut rope.root).fix_tree_seam(index);
}
rope.pull_up_singular_nodes();
}
return rope;
}
#[inline(always)]
fn get_next_leaf_slice<'a>(
&mut self,
slice: &'a [M],
is_last_chunk: bool,
) -> (NextSlice<'a, M>, &'a [M]) {
assert!(
self.buffer.len() < MAX_LEN,
"RopeBuilder: buffer is already full when receiving a chunk! \
This should never happen!",
);
if self.buffer.is_empty() && slice.len() >= MAX_LEN {
let split_index = MAX_LEN.min(slice.len() - 1);
return (
NextSlice::Slice(&slice[..split_index]),
&slice[split_index..],
);
}
else if (slice.len() + self.buffer.len()) >= MAX_LEN {
let split_index = MAX_LEN - self.buffer.len();
self.buffer.extend_from_slice(&slice[..split_index]);
return (NextSlice::UseBuffer, &slice[split_index..]);
}
else {
if is_last_chunk {
if self.buffer.is_empty() {
return if slice.is_empty() {
(NextSlice::None, &[])
} else {
(NextSlice::Slice(slice), &[])
};
} else {
self.buffer.extend_from_slice(slice);
return (NextSlice::UseBuffer, &[]);
}
}
else {
self.buffer.extend_from_slice(slice);
return (NextSlice::None, &[]);
}
}
}
fn append_leaf_node(&mut self, leaf: Arc<Node<M>>) {
let last = self.stack.pop().unwrap();
match *last {
Node::Leaf(_) => {
if last.leaf_slice().is_empty() {
self.stack.push(leaf);
} else {
let mut children = BranchChildren::new();
children.push((last.slice_info(), last));
children.push((leaf.slice_info(), leaf));
self.stack.push(Arc::new(Node::Branch(children)));
}
}
Node::Branch(_) => {
self.stack.push(last);
let mut left = leaf;
let mut stack_index = (self.stack.len() - 1) as isize;
loop {
if stack_index < 0 {
let mut children = BranchChildren::new();
children.push((left.slice_info(), left));
self.stack.insert(0, Arc::new(Node::Branch(children)));
break;
} else if self.stack[stack_index as usize].child_count() < (MAX_CHILDREN - 1) {
Arc::make_mut(&mut self.stack[stack_index as usize])
.children_mut()
.push((left.slice_info(), left));
break;
} else {
left = Arc::new(Node::Branch(
Arc::make_mut(&mut self.stack[stack_index as usize])
.children_mut()
.push_split((left.slice_info(), left)),
));
std::mem::swap(&mut left, &mut self.stack[stack_index as usize]);
stack_index -= 1;
}
}
}
}
}
}
impl<M> Default for RopeBuilder<M>
where
M: Measurable,
{
fn default() -> Self {
Self::new()
}
}
enum NextSlice<'a, M>
where
M: Measurable,
{
None,
UseBuffer,
Slice(&'a [M]),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Lipsum::{self, *};
fn lorem_ipsum() -> Vec<Lipsum> {
(0..70)
.into_iter()
.map(|num| match num % 14 {
0 | 7 => Lorem,
1 | 8 => Ipsum,
2 => Dolor(4),
3 | 10 => Sit,
4 | 11 => Amet,
5 => Consectur("hello"),
6 => Adipiscing(true),
9 => Dolor(8),
12 => Consectur("bye"),
13 => Adipiscing(false),
_ => unreachable!(),
})
.collect()
}
#[test]
fn rope_builder_01() {
let mut builder = RopeBuilder::new();
for _ in 0..5 {
builder.append_slice(&[Lorem, Ipsum, Dolor(4), Sit, Amet]);
builder.append_slice(&[Consectur("hello"), Adipiscing(true)]);
builder.append_slice(&[Lorem, Ipsum, Dolor(8), Sit, Amet]);
builder.append_slice(&[Consectur("bye"), Adipiscing(false)]);
}
let rope = builder.finish();
assert_eq!(rope, lorem_ipsum());
rope.assert_integrity();
rope.assert_invariants();
}
#[test]
fn rope_builder_02() {
let mut builder = RopeBuilder::new();
for _ in 0..5 {
builder.append(Lorem);
builder.append(Ipsum);
builder.append(Dolor(4));
builder.append(Sit);
builder.append(Amet);
builder.append_slice(&[Consectur("hello"), Adipiscing(true)]);
builder.append(Lorem);
builder.append(Ipsum);
builder.append(Dolor(8));
builder.append(Sit);
builder.append(Amet);
builder.append_slice(&[Consectur("bye"), Adipiscing(false)]);
}
let rope = builder.finish();
assert_eq!(rope, lorem_ipsum());
rope.assert_integrity();
rope.assert_invariants();
}
#[test]
fn rope_builder_default_01() {
let mut builder = RopeBuilder::default();
for _ in 0..5 {
builder.append_slice(&[Lorem, Ipsum, Dolor(4), Sit, Amet]);
builder.append_slice(&[Consectur("hello"), Adipiscing(true)]);
builder.append_slice(&[Lorem, Ipsum, Dolor(8), Sit, Amet]);
builder.append_slice(&[Consectur("bye"), Adipiscing(false)]);
}
let rope = builder.finish();
assert_eq!(rope, lorem_ipsum());
rope.assert_integrity();
rope.assert_invariants();
}
}