There was a regression after switching to ropes. Now it's pretty much back to pre-rope load times.
1459 lines
49 KiB
Rust
1459 lines
49 KiB
Rust
use std::cmp::{min, max};
|
|
use std::mem;
|
|
use std::str::Graphemes;
|
|
use std::ops::Index;
|
|
use string_utils::{grapheme_count, insert_text_at_grapheme_index, remove_text_between_grapheme_indices, split_string_at_grapheme_index, grapheme_pos_to_byte_pos};
|
|
|
|
const MIN_NODE_SIZE: usize = 64;
|
|
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.
|
|
pub struct Rope {
|
|
data: RopeData,
|
|
grapheme_count_: usize,
|
|
tree_height: u32,
|
|
}
|
|
|
|
|
|
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 = 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,
|
|
});
|
|
}
|
|
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) {
|
|
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) => {
|
|
insert_text_at_grapheme_index(s_text, text, pos);
|
|
},
|
|
}
|
|
|
|
self.update_stats();
|
|
self.split_if_too_large();
|
|
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) {
|
|
// TODO: make more efficient. Converting to a string and then
|
|
// inserting is pretty slow...
|
|
let s = rope.to_string();
|
|
let gc = self.grapheme_count();
|
|
self.insert_text_at_grapheme_index(s.as_slice(), gc);
|
|
}
|
|
|
|
/// 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,
|
|
};
|
|
}
|
|
|
|
|
|
//================================================================
|
|
// Private utility functions
|
|
//================================================================
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// 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
|
|
fn rebalance(&mut self) {
|
|
loop {
|
|
let mut rot: isize;
|
|
|
|
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;
|
|
}
|
|
// Balanced, stop
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// Leaf node, stop
|
|
break;
|
|
}
|
|
|
|
if rot == 1 {
|
|
self.rotate_right();
|
|
}
|
|
else if rot == -1 {
|
|
self.rotate_left();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 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 {
|
|
use super::*;
|
|
|
|
|
|
#[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 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 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());
|
|
}
|
|
}
|
|
|
|
#[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 = 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 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));
|
|
}
|
|
});
|
|
}
|
|
} |