diff --git a/crates/rope/src/chunk.rs b/crates/rope/src/chunk.rs index a2a8e8d58df2d5ddc3336e8e56dd8446f4dcf118..c1916768c1f8a0980fb4d5aa1b718483b08c6087 100644 --- a/crates/rope/src/chunk.rs +++ b/crates/rope/src/chunk.rs @@ -47,22 +47,59 @@ impl Chunk { #[inline(always)] pub fn new(text: &str) -> Self { - let mut this = Chunk::default(); - this.push_str(text); - this + let text = ArrayString::from(text).unwrap(); + + const CHUNK_SIZE: usize = 8; + + let mut chars_bytes = [0; MAX_BASE / CHUNK_SIZE]; + let mut newlines_bytes = [0; MAX_BASE / CHUNK_SIZE]; + let mut tabs_bytes = [0; MAX_BASE / CHUNK_SIZE]; + let mut chars_utf16_bytes = [0; MAX_BASE / CHUNK_SIZE]; + + let mut chunk_ix = 0; + + let mut bytes = text.as_bytes(); + while !bytes.is_empty() { + let (chunk, rest) = bytes.split_at(bytes.len().min(CHUNK_SIZE)); + bytes = rest; + + let mut chars = 0; + let mut newlines = 0; + let mut tabs = 0; + let mut chars_utf16 = 0; + + for (ix, &b) in chunk.iter().enumerate() { + chars |= (util::is_utf8_char_boundary(b) as u8) << ix; + newlines |= ((b == b'\n') as u8) << ix; + tabs |= ((b == b'\t') as u8) << ix; + // b >= 240 when we are at the first byte of the 4 byte encoded + // utf-8 code point (U+010000 or greater) it means that it would + // be encoded as two 16-bit code units in utf-16 + chars_utf16 |= ((b >= 240) as u8) << ix; + } + + chars_bytes[chunk_ix] = chars; + newlines_bytes[chunk_ix] = newlines; + tabs_bytes[chunk_ix] = tabs; + chars_utf16_bytes[chunk_ix] = chars_utf16; + + chunk_ix += 1; + } + + let chars = Bitmap::from_le_bytes(chars_bytes); + + Chunk { + text, + chars, + chars_utf16: (Bitmap::from_le_bytes(chars_utf16_bytes) << 1) | chars, + newlines: Bitmap::from_le_bytes(newlines_bytes), + tabs: Bitmap::from_le_bytes(tabs_bytes), + } } #[inline(always)] pub fn push_str(&mut self, text: &str) { - for (char_ix, c) in text.char_indices() { - let ix = self.text.len() + char_ix; - self.chars |= 1 << ix; - self.chars_utf16 |= 1 << ix; - self.chars_utf16 |= (c.len_utf16() as Bitmap) << ix; - self.newlines |= ((c == '\n') as Bitmap) << ix; - self.tabs |= ((c == '\t') as Bitmap) << ix; - } - self.text.push_str(text); + self.append(Chunk::new(text).as_slice()); } #[inline(always)] diff --git a/crates/rope/src/rope.rs b/crates/rope/src/rope.rs index 50f9ba044d90072aa9c6fc2fc4abfd6d0e6b98cb..fba7b96aca83fa05c0d6f3e7992ad7443ec7958a 100644 --- a/crates/rope/src/rope.rs +++ b/crates/rope/src/rope.rs @@ -227,7 +227,7 @@ impl Rope { #[cfg(all(test, not(rust_analyzer)))] const PARALLEL_THRESHOLD: usize = 4; #[cfg(not(all(test, not(rust_analyzer))))] - const PARALLEL_THRESHOLD: usize = 4 * (2 * sum_tree::TREE_BASE); + const PARALLEL_THRESHOLD: usize = 84 * (2 * sum_tree::TREE_BASE); if new_chunks.len() >= PARALLEL_THRESHOLD { self.chunks diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index bfc4587969ec67bbda2fb90d34550c7d464317c9..6a76b73c3bbfb922e1b46fc1e228209ddf05b4a5 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -250,11 +250,11 @@ impl SumTree { ::add_summary(&mut summary, item_summary, cx); } - nodes.push(Node::Leaf { + nodes.push(SumTree(Arc::new(Node::Leaf { summary, items, item_summaries, - }); + }))); } let mut parent_nodes = Vec::new(); @@ -263,25 +263,27 @@ impl SumTree { height += 1; let mut current_parent_node = None; for child_node in nodes.drain(..) { - let parent_node = current_parent_node.get_or_insert_with(|| Node::Internal { - summary: ::zero(cx), - height, - child_summaries: ArrayVec::new(), - child_trees: ArrayVec::new(), + let parent_node = current_parent_node.get_or_insert_with(|| { + SumTree(Arc::new(Node::Internal { + summary: ::zero(cx), + height, + child_summaries: ArrayVec::new(), + child_trees: ArrayVec::new(), + })) }); let Node::Internal { summary, child_summaries, child_trees, .. - } = parent_node + } = Arc::get_mut(&mut parent_node.0).unwrap() else { unreachable!() }; let child_summary = child_node.summary(); ::add_summary(summary, child_summary, cx); child_summaries.push(child_summary.clone()); - child_trees.push(Self(Arc::new(child_node))); + child_trees.push(child_node); if child_trees.len() == 2 * TREE_BASE { parent_nodes.extend(current_parent_node.take()); @@ -295,7 +297,7 @@ impl SumTree { Self::new(cx) } else { debug_assert_eq!(nodes.len(), 1); - Self(Arc::new(nodes.pop().unwrap())) + nodes.pop().unwrap() } }