1743 lines
60 KiB
Rust
1743 lines
60 KiB
Rust
use std::cmp::{min, max};
|
|
use std::mem;
|
|
use std::str::Graphemes;
|
|
use std::ops::Index;
|
|
use string_utils::{grapheme_count, grapheme_count_is_less_than, insert_text_at_grapheme_index, remove_text_between_grapheme_indices, split_string_at_grapheme_index, grapheme_pos_to_byte_pos};
|
|
|
|
pub const MIN_NODE_SIZE: usize = 64;
|
|
pub const MAX_NODE_SIZE: usize = MIN_NODE_SIZE * 2;
|
|
|
|
|
|
/// A rope data structure for storing text in a format that is efficient
|
|
/// for insertion and removal even for extremely large strings.
|
|
#[derive(Debug)]
|
|
pub struct Rope {
|
|
data: RopeData,
|
|
grapheme_count_: usize,
|
|
tree_height: u32,
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
enum RopeData {
|
|
Leaf(String),
|
|
Branch(Box<Rope>, Box<Rope>),
|
|
}
|
|
|
|
|
|
impl Rope {
|
|
/// Creates a new empty rope
|
|
pub fn new() -> Rope {
|
|
Rope {
|
|
data: RopeData::Leaf(String::new()),
|
|
grapheme_count_: 0,
|
|
tree_height: 1,
|
|
}
|
|
}
|
|
|
|
|
|
/// Creates a new rope from a string slice
|
|
pub fn new_from_str(s: &str) -> Rope {
|
|
let mut rope_stack: Vec<Rope> = Vec::new();
|
|
|
|
let mut s1 = s;
|
|
loop {
|
|
// Get the next chunk of the string to add
|
|
let mut i = 0;
|
|
let mut byte_i = 0;
|
|
for (bi, g) in s1.grapheme_indices(true) {
|
|
byte_i = bi + g.len();
|
|
i += 1;
|
|
if i >= MAX_NODE_SIZE {
|
|
break;
|
|
}
|
|
}
|
|
if i == 0 {
|
|
break;
|
|
}
|
|
let chunk = &s1[..byte_i];
|
|
|
|
// Add chunk
|
|
rope_stack.push(Rope {
|
|
data: RopeData::Leaf(String::from_str(chunk)),
|
|
grapheme_count_: i,
|
|
tree_height: 1,
|
|
});
|
|
|
|
// Do merges
|
|
loop {
|
|
let rsl = rope_stack.len();
|
|
if rsl > 1 && rope_stack[rsl-2].tree_height <= rope_stack[rsl-1].tree_height {
|
|
let right = Box::new(rope_stack.pop().unwrap());
|
|
let left = Box::new(rope_stack.pop().unwrap());
|
|
let h = max(left.tree_height, right.tree_height) + 1;
|
|
let gc = left.grapheme_count_ + right.grapheme_count_;
|
|
rope_stack.push(Rope {
|
|
data: RopeData::Branch(left, right),
|
|
grapheme_count_: gc,
|
|
tree_height: h,
|
|
});
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
s1 = &s1[byte_i..];
|
|
}
|
|
|
|
|
|
// Handle possible final unmerged case
|
|
let rope = if rope_stack.len() == 0 {
|
|
Rope::new()
|
|
}
|
|
else {
|
|
while rope_stack.len() > 1 {
|
|
let right = rope_stack.pop().unwrap();
|
|
let mut left = rope_stack.pop().unwrap();
|
|
left.append_right(right);
|
|
rope_stack.push(left);
|
|
}
|
|
rope_stack.pop().unwrap()
|
|
};
|
|
|
|
return rope;
|
|
}
|
|
|
|
pub fn new_from_str_with_count(s: &str, count: usize) -> Rope {
|
|
if count <= MAX_NODE_SIZE {
|
|
Rope {
|
|
data: RopeData::Leaf(String::from_str(s)),
|
|
grapheme_count_: count,
|
|
tree_height: 1,
|
|
}
|
|
}
|
|
else {
|
|
Rope::new_from_str(s)
|
|
}
|
|
}
|
|
|
|
/// Creates a new rope from a string, consuming the string
|
|
pub fn new_from_string(s: String) -> Rope {
|
|
// TODO: special case short strings?
|
|
Rope::new_from_str(s.as_slice())
|
|
}
|
|
|
|
pub fn grapheme_count(&self) -> usize {
|
|
return self.grapheme_count_;
|
|
}
|
|
|
|
pub fn insert_text_at_grapheme_index(&mut self, text: &str, pos: usize) {
|
|
let mut leaf_insert = false;
|
|
|
|
match self.data {
|
|
// Find node for text to be inserted into
|
|
RopeData::Branch(ref mut left, ref mut right) => {
|
|
if pos < left.grapheme_count_ {
|
|
left.insert_text_at_grapheme_index(text, pos);
|
|
}
|
|
else {
|
|
right.insert_text_at_grapheme_index(text, pos - left.grapheme_count_);
|
|
}
|
|
},
|
|
|
|
// Insert the text
|
|
RopeData::Leaf(ref mut s_text) => {
|
|
if grapheme_count_is_less_than(text, MAX_NODE_SIZE - self.grapheme_count_ + 1) {
|
|
// Simple case
|
|
insert_text_at_grapheme_index(s_text, text, pos);
|
|
}
|
|
else {
|
|
// Special cases
|
|
leaf_insert = true;
|
|
}
|
|
},
|
|
}
|
|
|
|
// The special cases of inserting at a leaf node.
|
|
// These have to be done outside of the match statement because
|
|
// of the borrow checker, but logically they take place in the
|
|
// RopeData::Leaf branch of the match statement above.
|
|
if leaf_insert {
|
|
// TODO: these special cases are currently prone to causing leaf
|
|
// fragmentation. Find ways to reduce that.
|
|
if pos == 0 {
|
|
let mut new_rope = Rope::new();
|
|
mem::swap(self, &mut new_rope);
|
|
self.data = RopeData::Branch(Box::new(Rope::new_from_str(text)), Box::new(new_rope));
|
|
}
|
|
else if pos == self.grapheme_count_ {
|
|
let mut new_rope = Rope::new();
|
|
mem::swap(self, &mut new_rope);
|
|
self.data = RopeData::Branch(Box::new(new_rope), Box::new(Rope::new_from_str(text)));
|
|
}
|
|
else {
|
|
// Split the leaf node at the insertion point
|
|
let mut node_l = Rope::new();
|
|
let node_r = self.split(pos);
|
|
mem::swap(self, &mut node_l);
|
|
|
|
// Set the inserted text as the main node
|
|
*self = Rope::new_from_str(text);
|
|
|
|
// Append the left and right split nodes to either side of
|
|
// the main node.
|
|
self.append_left(node_l);
|
|
self.append_right(node_r);
|
|
}
|
|
}
|
|
|
|
self.update_stats();
|
|
self.rebalance();
|
|
}
|
|
|
|
pub fn remove_text_between_grapheme_indices(&mut self, pos_a: usize, pos_b: usize) {
|
|
// Bounds checks
|
|
if pos_a > pos_b {
|
|
panic!("Rope::remove_text_between_grapheme_indices(): pos_a must be less than or equal to pos_b.");
|
|
}
|
|
if pos_b > self.grapheme_count_ {
|
|
panic!("Rope::remove_text_between_grapheme_indices(): attempt to remove text after end of node text.");
|
|
}
|
|
|
|
match self.data {
|
|
RopeData::Leaf(ref mut text) => {
|
|
remove_text_between_grapheme_indices(text, pos_a, pos_b);
|
|
},
|
|
|
|
RopeData::Branch(ref mut left, ref mut right) => {
|
|
let lgc = left.grapheme_count_;
|
|
|
|
if pos_a < lgc {
|
|
left.remove_text_between_grapheme_indices(pos_a, min(pos_b, lgc));
|
|
}
|
|
|
|
if pos_b > lgc {
|
|
right.remove_text_between_grapheme_indices(pos_a - min(pos_a, lgc), pos_b - lgc);
|
|
}
|
|
}
|
|
}
|
|
|
|
self.update_stats();
|
|
self.merge_if_too_small();
|
|
self.rebalance();
|
|
}
|
|
|
|
/// Splits a rope into two pieces from the given grapheme index.
|
|
/// The first piece remains in this rope, the second piece is returned
|
|
/// as a new rope.
|
|
pub fn split(&mut self, pos: usize) -> Rope {
|
|
// TODO: make more efficient.
|
|
let s = self.to_string();
|
|
let gc = self.grapheme_count();
|
|
let bp = grapheme_pos_to_byte_pos(s.as_slice(), pos);
|
|
self.remove_text_between_grapheme_indices(pos, gc);
|
|
|
|
Rope::new_from_str(&s.as_slice()[bp..])
|
|
}
|
|
|
|
/// Appends another rope to the end of this one, consuming the other rope.
|
|
pub fn append(&mut self, rope: Rope) {
|
|
if self.tree_height > rope.tree_height {
|
|
self.append_right(rope);
|
|
}
|
|
else {
|
|
let mut rope = rope;
|
|
mem::swap(self, &mut rope);
|
|
self.append_left(rope);
|
|
}
|
|
}
|
|
|
|
|
|
/// Makes a copy of the rope as a string
|
|
pub fn to_string(&self) -> String {
|
|
let mut s = String::new();
|
|
|
|
for chunk in self.chunk_iter() {
|
|
s.push_str(chunk);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
/// Creates a chunk iterator for the rope
|
|
pub fn chunk_iter<'a>(&'a self) -> RopeChunkIter<'a> {
|
|
self.chunk_iter_at_index(0).1
|
|
}
|
|
|
|
|
|
/// Creates a chunk iter starting at the chunk containing the given
|
|
/// grapheme index. Returns the chunk and its starting grapheme index.
|
|
pub fn chunk_iter_at_index<'a>(&'a self, index: usize) -> (usize, RopeChunkIter<'a>) {
|
|
let mut node_stack: Vec<&'a Rope> = Vec::new();
|
|
let mut cur_node = self;
|
|
let mut grapheme_i = index;
|
|
|
|
// Find the right rope node, and populate the stack at the same time
|
|
loop {
|
|
match cur_node.data {
|
|
RopeData::Leaf(_) => {
|
|
node_stack.push(cur_node);
|
|
break;
|
|
},
|
|
|
|
RopeData::Branch(ref left, ref right) => {
|
|
if grapheme_i < left.grapheme_count_ {
|
|
node_stack.push(&(**right));
|
|
cur_node = &(**left);
|
|
}
|
|
else {
|
|
cur_node = &(**right);
|
|
grapheme_i -= left.grapheme_count_;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
(index - grapheme_i, RopeChunkIter {node_stack: node_stack})
|
|
}
|
|
|
|
|
|
/// Creates an iterator at the first grapheme of the rope
|
|
pub fn grapheme_iter<'a>(&'a self) -> RopeGraphemeIter<'a> {
|
|
self.grapheme_iter_at_index(0)
|
|
}
|
|
|
|
|
|
/// Creates an iterator at the given grapheme index
|
|
pub fn grapheme_iter_at_index<'a>(&'a self, index: usize) -> RopeGraphemeIter<'a> {
|
|
let (grapheme_i, mut chunk_iter) = self.chunk_iter_at_index(index);
|
|
|
|
// Create the grapheme iter for the current node
|
|
let mut giter = if let Some(text) = chunk_iter.next() {
|
|
text.as_slice().graphemes(true)
|
|
}
|
|
else {
|
|
unreachable!()
|
|
};
|
|
|
|
// Get to the right spot in the iter
|
|
for _ in grapheme_i..index {
|
|
giter.next();
|
|
}
|
|
|
|
// Create the rope grapheme iter
|
|
return RopeGraphemeIter {
|
|
chunk_iter: chunk_iter,
|
|
cur_chunk: giter,
|
|
};
|
|
}
|
|
|
|
|
|
// Creates a graphviz document of the Rope's structure, and returns
|
|
// it as a string.
|
|
pub fn to_graphviz(&self) -> String {
|
|
let mut text = String::from_str("digraph {\n");
|
|
self.to_graphviz_recursive(&mut text, String::from_str("s"));
|
|
text.push_str("}");
|
|
return text;
|
|
}
|
|
|
|
|
|
//================================================================
|
|
// Private utility functions
|
|
//================================================================
|
|
|
|
|
|
fn to_graphviz_recursive(&self, text: &mut String, name: String) {
|
|
match self.data {
|
|
RopeData::Leaf(_) => {
|
|
text.push_str(format!("{} [label=\"{}\"];\n", name, self.grapheme_count_).as_slice());
|
|
},
|
|
|
|
RopeData::Branch(ref left, ref right) => {
|
|
let mut lname = name.clone();
|
|
let mut rname = name.clone();
|
|
lname.push('l');
|
|
rname.push('r');
|
|
text.push_str(format!("{} [shape=box, label=\"h={}\\nc={}\"];\n", name, self.tree_height, self.grapheme_count_).as_slice());
|
|
text.push_str(format!("{} -> {{ {} {} }};\n", name, lname, rname).as_slice());
|
|
left.to_graphviz_recursive(text, lname);
|
|
right.to_graphviz_recursive(text, rname);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fn is_leaf(&self) -> bool {
|
|
if let RopeData::Leaf(_) = self.data {
|
|
true
|
|
}
|
|
else {
|
|
false
|
|
}
|
|
}
|
|
|
|
|
|
/// Non-recursively updates the stats of a node
|
|
fn update_stats(&mut self) {
|
|
match self.data {
|
|
RopeData::Leaf(ref text) => {
|
|
self.grapheme_count_ = grapheme_count(text);
|
|
self.tree_height = 1;
|
|
},
|
|
|
|
RopeData::Branch(ref left, ref right) => {
|
|
self.grapheme_count_ = left.grapheme_count_ + right.grapheme_count_;
|
|
self.tree_height = max(left.tree_height, right.tree_height) + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fn append_right(&mut self, rope: Rope) {
|
|
if self.tree_height <= rope.tree_height || self.is_leaf() {
|
|
let mut temp_rope = Box::new(Rope::new());
|
|
mem::swap(self, &mut (*temp_rope));
|
|
self.data = RopeData::Branch(temp_rope, Box::new(rope));
|
|
}
|
|
else if let RopeData::Branch(_, ref mut right) = self.data {
|
|
right.append_right(rope);
|
|
}
|
|
|
|
self.update_stats();
|
|
self.rebalance();
|
|
}
|
|
|
|
|
|
fn append_left(&mut self, rope: Rope) {
|
|
if self.tree_height <= rope.tree_height || self.is_leaf() {
|
|
let mut temp_rope = Box::new(Rope::new());
|
|
mem::swap(self, &mut (*temp_rope));
|
|
self.data = RopeData::Branch(Box::new(rope), temp_rope);
|
|
}
|
|
else if let RopeData::Branch(ref mut left, _) = self.data {
|
|
left.append_left(rope);
|
|
}
|
|
|
|
self.update_stats();
|
|
self.rebalance();
|
|
}
|
|
|
|
|
|
/// Splits a leaf node into pieces if it's too large
|
|
// TODO: find a way to do this that's more algorithmically efficient
|
|
// if lots of splits need to happen. This version ends up re-scanning
|
|
// the text quite a lot, as well as doing quite a few unnecessary
|
|
// allocations.
|
|
fn split_if_too_large(&mut self) {
|
|
if self.grapheme_count_ > MAX_NODE_SIZE && self.is_leaf() {
|
|
|
|
// Calculate split position and how large the left and right
|
|
// sides are going to be
|
|
let split_pos = self.grapheme_count_ / 2;
|
|
let new_gc_l = split_pos;
|
|
let new_gc_r = self.grapheme_count_ - split_pos;
|
|
|
|
// Do the split
|
|
let mut nl = Box::new(Rope::new());
|
|
let mut nr = Box::new(Rope::new());
|
|
mem::swap(self, &mut (*nl));
|
|
if let RopeData::Leaf(ref mut text) = nl.data {
|
|
nr.data = RopeData::Leaf(split_string_at_grapheme_index(text, split_pos));
|
|
text.shrink_to_fit();
|
|
}
|
|
|
|
// Recursively split
|
|
nl.grapheme_count_ = new_gc_l;
|
|
nr.grapheme_count_ = new_gc_r;
|
|
nl.split_if_too_large();
|
|
nr.split_if_too_large();
|
|
|
|
// Update the new left and right node's stats
|
|
nl.update_stats();
|
|
nr.update_stats();
|
|
|
|
// Create the new branch node with the new left and right nodes
|
|
self.data = RopeData::Branch(nl, nr);
|
|
self.update_stats();
|
|
}
|
|
}
|
|
|
|
|
|
/// Merges a non-leaf node into a leaf node if it's too small
|
|
fn merge_if_too_small(&mut self) {
|
|
if self.grapheme_count_ < MIN_NODE_SIZE && !self.is_leaf() {
|
|
let mut merged_text = String::new();
|
|
|
|
if let RopeData::Branch(ref mut left, ref mut right) = self.data {
|
|
// First, recursively merge the children
|
|
left.merge_if_too_small();
|
|
right.merge_if_too_small();
|
|
|
|
// Then put their text into merged_text
|
|
if let RopeData::Leaf(ref mut text) = left.data {
|
|
mem::swap(&mut merged_text, text);
|
|
}
|
|
if let RopeData::Leaf(ref mut text) = right.data {
|
|
merged_text.push_str(text.as_slice());
|
|
}
|
|
}
|
|
|
|
// Make this a leaf node with merged_text as its data
|
|
self.data = RopeData::Leaf(merged_text);
|
|
self.tree_height = 1;
|
|
// Don't need to update grapheme count, because it should be the
|
|
// same as before.
|
|
}
|
|
}
|
|
|
|
|
|
/// Rotates the tree under the node left
|
|
fn rotate_left(&mut self) {
|
|
let mut temp = Rope::new();
|
|
|
|
if let RopeData::Branch(_, ref mut right) = self.data {
|
|
mem::swap(&mut temp, &mut (**right));
|
|
|
|
if let RopeData::Branch(ref mut left, _) = temp.data {
|
|
mem::swap(&mut (**left), &mut (**right));
|
|
}
|
|
else {
|
|
panic!("Rope::rotate_left(): attempting to rotate node without branching right child.");
|
|
}
|
|
}
|
|
else {
|
|
panic!("Rope::rotate_left(): attempting to rotate leaf node.");
|
|
}
|
|
|
|
if let RopeData::Branch(ref mut left, _) = temp.data {
|
|
mem::swap(&mut (**left), self);
|
|
left.update_stats();
|
|
}
|
|
|
|
mem::swap(&mut temp, self);
|
|
self.update_stats();
|
|
}
|
|
|
|
|
|
/// Rotates the tree under the node right
|
|
fn rotate_right(&mut self) {
|
|
let mut temp = Rope::new();
|
|
|
|
if let RopeData::Branch(ref mut left, _) = self.data {
|
|
mem::swap(&mut temp, &mut (**left));
|
|
|
|
if let RopeData::Branch(_, ref mut right) = temp.data {
|
|
mem::swap(&mut (**right), &mut (**left));
|
|
}
|
|
else {
|
|
panic!("Rope::rotate_right(): attempting to rotate node without branching left child.");
|
|
}
|
|
}
|
|
else {
|
|
panic!("Rope::rotate_right(): attempting to rotate leaf node.");
|
|
}
|
|
|
|
if let RopeData::Branch(_, ref mut right) = temp.data {
|
|
mem::swap(&mut (**right), self);
|
|
right.update_stats();
|
|
}
|
|
|
|
mem::swap(&mut temp, self);
|
|
self.update_stats();
|
|
}
|
|
|
|
|
|
/// Balances the tree under this node. Assumes that both the left and
|
|
/// right sub-trees are themselves aleady balanced.
|
|
/// Runs in time linear to the difference in height between the two
|
|
/// sub-trees. Thus worst-case is O(log N) time, and best-case is O(1)
|
|
/// time.
|
|
fn rebalance(&mut self) {
|
|
let mut rot: isize = 0;
|
|
|
|
if let RopeData::Branch(ref mut left, ref mut right) = self.data {
|
|
let height_diff = (left.tree_height as isize) - (right.tree_height as isize);
|
|
|
|
// Left side higher than right side
|
|
if height_diff > 1 {
|
|
let mut child_rot = false;
|
|
if let RopeData::Branch(ref lc, ref rc) = left.data {
|
|
if lc.tree_height < rc.tree_height {
|
|
child_rot = true;
|
|
}
|
|
}
|
|
|
|
if child_rot {
|
|
left.rotate_left();
|
|
}
|
|
|
|
rot = 1;
|
|
}
|
|
// Right side higher then left side
|
|
else if height_diff < -1 {
|
|
let mut child_rot = false;
|
|
if let RopeData::Branch(ref lc, ref rc) = right.data {
|
|
if lc.tree_height > rc.tree_height {
|
|
child_rot = true;
|
|
}
|
|
}
|
|
|
|
if child_rot {
|
|
right.rotate_right();
|
|
}
|
|
|
|
rot = -1;
|
|
}
|
|
}
|
|
|
|
if rot == 1 {
|
|
self.rotate_right();
|
|
if let RopeData::Branch(_, ref mut right) = self.data {
|
|
right.rebalance();
|
|
}
|
|
}
|
|
else if rot == -1 {
|
|
self.rotate_left();
|
|
if let RopeData::Branch(ref mut left, _) = self.data {
|
|
left.rebalance();
|
|
}
|
|
}
|
|
|
|
self.update_stats();
|
|
}
|
|
|
|
|
|
/// Tests if the rope adheres to the AVL balancing invariants.
|
|
fn is_balanced(&self) -> bool {
|
|
match self.data {
|
|
RopeData::Leaf(_) => {
|
|
return true;
|
|
},
|
|
|
|
RopeData::Branch(ref left, ref right) => {
|
|
let mut diff = left.tree_height as isize - right.tree_height as isize;
|
|
diff = if diff < 0 {-diff} else {diff};
|
|
return (diff < 2) && left.is_balanced() && right.is_balanced();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Direct indexing to graphemes in the rope
|
|
impl Index<usize> for Rope {
|
|
type Output = str;
|
|
|
|
fn index<'a>(&'a self, index: &usize) -> &'a str {
|
|
if *index >= self.grapheme_count() {
|
|
panic!("Rope::Index: attempting to fetch grapheme that outside the bounds of the text.");
|
|
}
|
|
|
|
match self.data {
|
|
RopeData::Leaf(ref text) => {
|
|
let mut i: usize = 0;
|
|
for g in text.graphemes(true) {
|
|
if i == *index {
|
|
return &g;
|
|
}
|
|
i += 1;
|
|
}
|
|
unreachable!();
|
|
},
|
|
|
|
RopeData::Branch(ref left, ref right) => {
|
|
if *index < left.grapheme_count() {
|
|
return &left[*index];
|
|
}
|
|
else {
|
|
return &right[*index - left.grapheme_count()];
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//=============================================================
|
|
// Rope iterators
|
|
//=============================================================
|
|
|
|
/// An iterator over a rope's string chunks
|
|
pub struct RopeChunkIter<'a> {
|
|
node_stack: Vec<&'a Rope>,
|
|
}
|
|
|
|
impl<'a> Iterator for RopeChunkIter<'a> {
|
|
type Item = &'a str;
|
|
|
|
fn next(&mut self) -> Option<&'a str> {
|
|
if let Some(next_chunk) = self.node_stack.pop() {
|
|
loop {
|
|
if let Option::Some(node) = self.node_stack.pop() {
|
|
match node.data {
|
|
RopeData::Leaf(_) => {
|
|
self.node_stack.push(node);
|
|
break;
|
|
},
|
|
|
|
RopeData::Branch(ref left, ref right) => {
|
|
self.node_stack.push(&(**right));
|
|
self.node_stack.push(&(**left));
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if let RopeData::Leaf(ref text) = next_chunk.data {
|
|
return Some(text.as_slice());
|
|
}
|
|
else {
|
|
unreachable!();
|
|
}
|
|
}
|
|
else {
|
|
return None;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over a rope's graphemes
|
|
pub struct RopeGraphemeIter<'a> {
|
|
chunk_iter: RopeChunkIter<'a>,
|
|
cur_chunk: Graphemes<'a>,
|
|
}
|
|
|
|
|
|
impl<'a> Iterator for RopeGraphemeIter<'a> {
|
|
type Item = &'a str;
|
|
|
|
fn next(&mut self) -> Option<&'a str> {
|
|
loop {
|
|
if let Some(g) = self.cur_chunk.next() {
|
|
return Some(g);
|
|
}
|
|
else {
|
|
if let Some(s) = self.chunk_iter.next() {
|
|
self.cur_chunk = s.graphemes(true);
|
|
continue;
|
|
}
|
|
else {
|
|
return None;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//===================================================================
|
|
// Unit test
|
|
//===================================================================
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#![allow(unused_imports)]
|
|
use std::iter;
|
|
use super::{Rope, RopeData, RopeGraphemeIter, MAX_NODE_SIZE};
|
|
use std::old_path::Path;
|
|
use std::old_io::fs::File;
|
|
use std::old_io::BufferedWriter;
|
|
|
|
|
|
#[test]
|
|
fn new_1() {
|
|
let rope = Rope::new();
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert_eq!(None, iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn new_2() {
|
|
let rope = Rope::new_from_str("Hello world!");
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert_eq!(Some("H"), iter.next());
|
|
assert_eq!(Some("e"), iter.next());
|
|
assert_eq!(Some("l"), iter.next());
|
|
assert_eq!(Some("l"), iter.next());
|
|
assert_eq!(Some("o"), iter.next());
|
|
assert_eq!(Some(" "), iter.next());
|
|
assert_eq!(Some("w"), iter.next());
|
|
assert_eq!(Some("o"), iter.next());
|
|
assert_eq!(Some("r"), iter.next());
|
|
assert_eq!(Some("l"), iter.next());
|
|
assert_eq!(Some("d"), iter.next());
|
|
assert_eq!(Some("!"), iter.next());
|
|
assert_eq!(None, iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn new_3() {
|
|
let s = String::from_str("Hello world!");
|
|
let rope = Rope::new_from_string(s);
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert_eq!(Some("H"), iter.next());
|
|
assert_eq!(Some("e"), iter.next());
|
|
assert_eq!(Some("l"), iter.next());
|
|
assert_eq!(Some("l"), iter.next());
|
|
assert_eq!(Some("o"), iter.next());
|
|
assert_eq!(Some(" "), iter.next());
|
|
assert_eq!(Some("w"), iter.next());
|
|
assert_eq!(Some("o"), iter.next());
|
|
assert_eq!(Some("r"), iter.next());
|
|
assert_eq!(Some("l"), iter.next());
|
|
assert_eq!(Some("d"), iter.next());
|
|
assert_eq!(Some("!"), iter.next());
|
|
assert_eq!(None, iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn new_4() {
|
|
let rope = Rope::new_from_str(String::from_utf8(vec!['c' as u8; 1 + MAX_NODE_SIZE * 53]).unwrap().as_slice());
|
|
|
|
assert!(rope.is_balanced());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn index() {
|
|
let rope = Rope::new_from_str("Hel世界lo world!");
|
|
|
|
assert_eq!("H", &rope[0]);
|
|
assert_eq!("界", &rope[4]);
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn to_string() {
|
|
let rope = Rope::new_from_str("Hello there good people of the world!");
|
|
let s = rope.to_string();
|
|
|
|
assert_eq!("Hello there good people of the world!", s.as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn split_1() {
|
|
let mut rope1 = Rope::new_from_str("Hello there good people of the world!");
|
|
let rope2 = rope1.split(18);
|
|
|
|
assert_eq!("Hello there good p", rope1.to_string().as_slice());
|
|
assert_eq!("eople of the world!", rope2.to_string().as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn split_2() {
|
|
let mut rope1 = Rope::new_from_str("Hello there good people of the world!");
|
|
let rope2 = rope1.split(37);
|
|
|
|
assert_eq!("Hello there good people of the world!", rope1.to_string().as_slice());
|
|
assert_eq!("", rope2.to_string().as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn split_3() {
|
|
let mut rope1 = Rope::new_from_str("Hello there good people of the world!");
|
|
let rope2 = rope1.split(0);
|
|
|
|
assert_eq!("", rope1.to_string().as_slice());
|
|
assert_eq!("Hello there good people of the world!", rope2.to_string().as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn append_1() {
|
|
let mut rope1 = Rope::new_from_str("Hello there good p");
|
|
let rope2 = Rope::new_from_str("eople of the world!");
|
|
|
|
rope1.append(rope2);
|
|
|
|
assert_eq!("Hello there good people of the world!", rope1.to_string().as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn append_2() {
|
|
let mut rope1 = Rope::new_from_str("Hello there good people of the world!");
|
|
let rope2 = Rope::new_from_str("");
|
|
|
|
rope1.append(rope2);
|
|
|
|
assert_eq!("Hello there good people of the world!", rope1.to_string().as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn append_3() {
|
|
let mut rope1 = Rope::new_from_str("");
|
|
let rope2 = Rope::new_from_str("Hello there good people of the world!");
|
|
|
|
rope1.append(rope2);
|
|
|
|
assert_eq!("Hello there good people of the world!", rope1.to_string().as_slice());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn append_4() {
|
|
let mut rope1 = Rope::new_from_str("1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.");
|
|
let rope2 = Rope::new_from_str("Z");
|
|
|
|
rope1.append(rope2);
|
|
|
|
assert_eq!(rope1.to_string(), "1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.Z");
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn append_5() {
|
|
let mut rope1 = Rope::new_from_str("Z");
|
|
let rope2 = Rope::new_from_str("1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.");
|
|
|
|
rope1.append(rope2);
|
|
|
|
assert_eq!(rope1.to_string(), "Z1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.");
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text() {
|
|
let mut rope = Rope::new();
|
|
|
|
rope.insert_text_at_grapheme_index("Hello 世界!", 0);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 9);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_1() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index("Again ", 0);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 17);
|
|
assert!(Some("A") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_2() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index(" again", 5);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 17);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_3() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index("again", 6);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 16);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_4() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index("again", 11);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 16);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_5() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index("again", 2);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 16);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_6() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index("again", 8);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 16);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn insert_text_in_non_empty_buffer_7() {
|
|
let mut rope = Rope::new_from_str("Hello\n 世界\r\n!");
|
|
|
|
rope.insert_text_at_grapheme_index("\nag\n\nain\n", 2);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 20);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("g") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("a") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("n") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some(" ") == iter.next());
|
|
assert!(Some("世") == iter.next());
|
|
assert!(Some("界") == iter.next());
|
|
assert!(Some("\r\n") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_1() {
|
|
let mut rope = Rope::new_from_str("Hi\nthere\npeople\nof\nthe\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(0, 3);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 26);
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("r") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("f") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("w") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("r") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("d") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_2() {
|
|
let mut rope = Rope::new_from_str("Hi\nthere\npeople\nof\nthe\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(0, 12);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 17);
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("f") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("w") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("r") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("d") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_3() {
|
|
let mut rope = Rope::new_from_str("Hi\nthere\npeople\nof\nthe\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(5, 17);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 17);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("f") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("w") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("r") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("d") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_4() {
|
|
let mut rope = Rope::new_from_str("Hi\nthere\npeople\nof\nthe\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(23, 29);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 23);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("r") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("f") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_5() {
|
|
let mut rope = Rope::new_from_str("Hi\nthere\npeople\nof\nthe\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(17, 29);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 17);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("r") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("p") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_6() {
|
|
let mut rope = Rope::new_from_str("Hello\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(3, 12);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 3);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_7() {
|
|
let mut rope = Rope::new_from_str("Hi\nthere\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(5, 15);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 5);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("i") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("t") == iter.next());
|
|
assert!(Some("h") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_8() {
|
|
let mut rope = Rope::new_from_str("Hello\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(3, 11);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 4);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("!") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_9() {
|
|
let mut rope = Rope::new_from_str("Hello\nworld!");
|
|
|
|
rope.remove_text_between_grapheme_indices(8, 12);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 8);
|
|
assert!(Some("H") == iter.next());
|
|
assert!(Some("e") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("l") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("w") == iter.next());
|
|
assert!(Some("o") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_10() {
|
|
let mut rope = Rope::new_from_str("12\n34\n56\n78");
|
|
|
|
rope.remove_text_between_grapheme_indices(4, 11);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 4);
|
|
assert!(Some("1") == iter.next());
|
|
assert!(Some("2") == iter.next());
|
|
assert!(Some("\n") == iter.next());
|
|
assert!(Some("3") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn remove_text_11() {
|
|
let mut rope = Rope::new_from_str("1234567890");
|
|
|
|
rope.remove_text_between_grapheme_indices(9, 10);
|
|
|
|
let mut iter = rope.grapheme_iter();
|
|
|
|
assert!(rope.grapheme_count() == 9);
|
|
assert!(Some("1") == iter.next());
|
|
assert!(Some("2") == iter.next());
|
|
assert!(Some("3") == iter.next());
|
|
assert!(Some("4") == iter.next());
|
|
assert!(Some("5") == iter.next());
|
|
assert!(Some("6") == iter.next());
|
|
assert!(Some("7") == iter.next());
|
|
assert!(Some("8") == iter.next());
|
|
assert!(Some("9") == iter.next());
|
|
assert!(None == iter.next());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn rebalance_1() {
|
|
let left = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 64]).unwrap().as_slice());
|
|
let right = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1]).unwrap().as_slice());
|
|
|
|
let mut rope = Rope {
|
|
data: RopeData::Branch(Box::new(left), Box::new(right)),
|
|
grapheme_count_: 0,
|
|
tree_height: 1,
|
|
};
|
|
rope.update_stats();
|
|
|
|
//let mut f1 = BufferedWriter::new(File::create(&Path::new("yar1.gv")).unwrap());
|
|
//f1.write_str(rope.to_graphviz().as_slice());
|
|
|
|
rope.rebalance();
|
|
|
|
//let mut f2 = BufferedWriter::new(File::create(&Path::new("yar2.gv")).unwrap());
|
|
//f2.write_str(rope.to_graphviz().as_slice());
|
|
|
|
assert!(rope.is_balanced());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn rebalance_2() {
|
|
let left = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1]).unwrap().as_slice());
|
|
let right = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 64]).unwrap().as_slice());
|
|
|
|
let mut rope = Rope {
|
|
data: RopeData::Branch(Box::new(left), Box::new(right)),
|
|
grapheme_count_: 0,
|
|
tree_height: 1,
|
|
};
|
|
rope.update_stats();
|
|
|
|
//let mut f1 = BufferedWriter::new(File::create(&Path::new("yar1.gv")).unwrap());
|
|
//f1.write_str(rope.to_graphviz().as_slice());
|
|
|
|
rope.rebalance();
|
|
|
|
//let mut f2 = BufferedWriter::new(File::create(&Path::new("yar2.gv")).unwrap());
|
|
//f2.write_str(rope.to_graphviz().as_slice());
|
|
|
|
assert!(rope.is_balanced());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn rebalance_3() {
|
|
let left = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 53]).unwrap().as_slice());
|
|
let right = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1]).unwrap().as_slice());
|
|
|
|
let mut rope = Rope {
|
|
data: RopeData::Branch(Box::new(left), Box::new(right)),
|
|
grapheme_count_: 0,
|
|
tree_height: 1,
|
|
};
|
|
rope.update_stats();
|
|
|
|
//let mut f1 = BufferedWriter::new(File::create(&Path::new("yar1.gv")).unwrap());
|
|
//f1.write_str(rope.to_graphviz().as_slice());
|
|
|
|
rope.rebalance();
|
|
|
|
//let mut f2 = BufferedWriter::new(File::create(&Path::new("yar2.gv")).unwrap());
|
|
//f2.write_str(rope.to_graphviz().as_slice());
|
|
|
|
assert!(rope.is_balanced());
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn rebalance_4() {
|
|
let left = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1]).unwrap().as_slice());
|
|
let right = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 53]).unwrap().as_slice());
|
|
|
|
let mut rope = Rope {
|
|
data: RopeData::Branch(Box::new(left), Box::new(right)),
|
|
grapheme_count_: 0,
|
|
tree_height: 1,
|
|
};
|
|
rope.update_stats();
|
|
|
|
//let mut f1 = BufferedWriter::new(File::create(&Path::new("yar1.gv")).unwrap());
|
|
//f1.write_str(rope.to_graphviz().as_slice());
|
|
|
|
rope.rebalance();
|
|
|
|
//let mut f2 = BufferedWriter::new(File::create(&Path::new("yar2.gv")).unwrap());
|
|
//f2.write_str(rope.to_graphviz().as_slice());
|
|
|
|
assert!(rope.is_balanced());
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod benches {
|
|
use super::*;
|
|
use test::Bencher;
|
|
|
|
|
|
#[bench]
|
|
fn new_from_str_1(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let _ = Rope::new_from_str("
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn new_from_str_2(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let _ = Rope::new_from_str("
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn new_from_str_3(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let _ = Rope::new_from_str("
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn new_from_str_4(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let _ = Rope::new_from_str("
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn insert_text_bench_1(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let mut rope = Rope::new();
|
|
for _ in 0..200 {
|
|
rope.insert_text_at_grapheme_index("Hi", 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn insert_text_bench_2(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let mut rope = Rope::new();
|
|
for i in 0..200 {
|
|
rope.insert_text_at_grapheme_index("Hi", i/2);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn insert_text_bench_3(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let mut rope = Rope::new();
|
|
for i in 0..200 {
|
|
rope.insert_text_at_grapheme_index("Hi", i);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn insert_large_text_bench_1(b: &mut Bencher) {
|
|
let s = String::from_utf8(vec!['c' as u8; 3457]).unwrap();
|
|
b.iter(|| {
|
|
let mut rope = Rope::new_from_str("Hello there!");
|
|
rope.insert_text_at_grapheme_index(s.as_slice(), 0);
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn insert_large_text_bench_2(b: &mut Bencher) {
|
|
let s = String::from_utf8(vec!['c' as u8; 3457]).unwrap();
|
|
b.iter(|| {
|
|
let mut rope = Rope::new_from_str("Hello there!");
|
|
rope.insert_text_at_grapheme_index(s.as_slice(), 3);
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn insert_large_text_bench_3(b: &mut Bencher) {
|
|
let s = String::from_utf8(vec!['c' as u8; 3457]).unwrap();
|
|
b.iter(|| {
|
|
let mut rope = Rope::new_from_str("Hello there!");
|
|
rope.insert_text_at_grapheme_index(s.as_slice(), 12);
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn remove_text_bench_1(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let mut rope = Rope::new_from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
for _ in 0..200 {
|
|
rope.remove_text_between_grapheme_indices(0, 2);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn remove_text_bench_2(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let mut rope = Rope::new_from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
for i in 0..200 {
|
|
rope.remove_text_between_grapheme_indices((200-i)-1, (200-i)+1);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
#[bench]
|
|
fn remove_text_bench_3(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let mut rope = Rope::new_from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
for i in 0..200 {
|
|
rope.remove_text_between_grapheme_indices(400-(i*2)-2, 400-(i*2));
|
|
}
|
|
});
|
|
}
|
|
} |