diff --git a/Cargo.lock b/Cargo.lock index 57fb05322f619f10df091bc092f019f42d8a5a60..e1c8cb0c5fa01904b6bbacfde9f56b81bb4cf6d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2175,7 +2175,6 @@ name = "gpui" version = "0.1.0" dependencies = [ "anyhow", - "arrayvec 0.7.1", "async-task", "backtrace", "bindgen", @@ -2212,6 +2211,7 @@ dependencies = [ "simplelog", "smallvec", "smol", + "sum_tree", "time 0.3.2", "tiny-skia", "tree-sitter", @@ -4940,6 +4940,14 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +[[package]] +name = "sum_tree" +version = "0.1.0" +dependencies = [ + "arrayvec 0.7.1", + "rand 0.8.3", +] + [[package]] name = "surf" version = "2.2.0" @@ -5927,6 +5935,7 @@ dependencies = [ "simplelog", "smallvec", "smol", + "sum_tree", "surf", "tempdir", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 248326d871cd864c43d662b8d79406f2e78190d1..96a40d043ecc659a1459acae210edd999c895177 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["fsevent", "gpui", "gpui_macros", "server", "zed", "zrpc"] +members = ["fsevent", "gpui", "gpui_macros", "server", "sum_tree", "zed", "zrpc"] default-members = ["zed"] [patch.crates-io] diff --git a/gpui/Cargo.toml b/gpui/Cargo.toml index be86a788d818bec2e565baff397fe0b39167dd04..ae01eaba63f8047198fa88d776b809071a6dc15c 100644 --- a/gpui/Cargo.toml +++ b/gpui/Cargo.toml @@ -8,7 +8,6 @@ version = "0.1.0" test-support = [] [dependencies] -arrayvec = "0.7.1" async-task = "4.0.3" backtrace = "0.3" ctor = "0.1" @@ -31,6 +30,7 @@ serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.64" smallvec = { version = "1.6", features = ["union"] } smol = "1.2" +sum_tree = { path = "../sum_tree" } time = { version = "0.3" } tiny-skia = "0.5" tree-sitter = "0.19" diff --git a/gpui/src/elements/list.rs b/gpui/src/elements/list.rs index 219c175168833a2798ad657a600cffab766f56b7..3fbd2a6d28e6e8da33eb4b8e3a7cc6f4e1422d0c 100644 --- a/gpui/src/elements/list.rs +++ b/gpui/src/elements/list.rs @@ -4,11 +4,11 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::json, - sum_tree::{self, Bias, SumTree}, DebugContext, Element, ElementBox, ElementRc, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, }; use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; +use sum_tree::{self, Bias, SumTree}; pub struct List { state: ListState, diff --git a/gpui/src/lib.rs b/gpui/src/lib.rs index 4b4d5f25d55060585df09f267c9bad55a258ced2..2ea6c322573f136635c308b567921c9f0106db2e 100644 --- a/gpui/src/lib.rs +++ b/gpui/src/lib.rs @@ -1,7 +1,6 @@ mod app; pub use app::*; mod assets; -pub mod sum_tree; #[cfg(test)] mod test; pub use assets::*; diff --git a/sum_tree/Cargo.toml b/sum_tree/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..510044cfb8f85bde5a066fd434335751de014c7f --- /dev/null +++ b/sum_tree/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "sum_tree" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +arrayvec = "0.7.1" + +[dev-dependencies] +rand = "0.8.3" diff --git a/gpui/src/sum_tree/cursor.rs b/sum_tree/src/cursor.rs similarity index 100% rename from gpui/src/sum_tree/cursor.rs rename to sum_tree/src/cursor.rs diff --git a/gpui/src/sum_tree.rs b/sum_tree/src/lib.rs similarity index 86% rename from gpui/src/sum_tree.rs rename to sum_tree/src/lib.rs index e256a1f33ba4cc42cc7cd0d2cef0295dcc8d01a9..2bbb567ba16824074bf3f34990d835828bb030ec 100644 --- a/gpui/src/sum_tree.rs +++ b/sum_tree/src/lib.rs @@ -674,101 +674,115 @@ mod tests { ); } - #[crate::test(self, iterations = 100)] - fn test_random(mut rng: StdRng) { - let rng = &mut rng; - let mut tree = SumTree::::new(); - let count = rng.gen_range(0..10); - tree.extend(rng.sample_iter(distributions::Standard).take(count), &()); - - for _ in 0..5 { - let splice_end = rng.gen_range(0..tree.extent::(&()).0 + 1); - let splice_start = rng.gen_range(0..splice_end + 1); - let count = rng.gen_range(0..3); - let tree_end = tree.extent::(&()); - let new_items = rng - .sample_iter(distributions::Standard) - .take(count) - .collect::>(); - - let mut reference_items = tree.items(&()); - reference_items.splice(splice_start..splice_end, new_items.clone()); - - tree = { - let mut cursor = tree.cursor::(); - let mut new_tree = cursor.slice(&Count(splice_start), Bias::Right, &()); - new_tree.extend(new_items, &()); - cursor.seek(&Count(splice_end), Bias::Right, &()); - new_tree.push_tree(cursor.slice(&tree_end, Bias::Right, &()), &()); - new_tree - }; - - assert_eq!(tree.items(&()), reference_items); - - let mut filter_cursor = tree.filter::<_, Count>(|summary| summary.contains_even, &()); - let mut reference_filter = tree - .items(&()) - .into_iter() - .enumerate() - .filter(|(_, item)| (item & 1) == 0); - while let Some(actual_item) = filter_cursor.item() { - let (reference_index, reference_item) = reference_filter.next().unwrap(); - assert_eq!(actual_item, &reference_item); - assert_eq!(filter_cursor.start().0, reference_index); - filter_cursor.next(&()); - } - assert!(reference_filter.next().is_none()); + #[test] + fn test_random() { + let mut starting_seed = 0; + if let Ok(value) = std::env::var("SEED") { + starting_seed = value.parse().expect("invalid SEED variable"); + } + let mut num_iterations = 100; + if let Ok(value) = std::env::var("ITERATIONS") { + num_iterations = value.parse().expect("invalid ITERATIONS variable"); + } - let mut pos = rng.gen_range(0..tree.extent::(&()).0 + 1); - let mut before_start = false; - let mut cursor = tree.cursor::(); - cursor.seek(&Count(pos), Bias::Right, &()); + for seed in starting_seed..(starting_seed + num_iterations) { + let mut rng = StdRng::seed_from_u64(seed); + + let rng = &mut rng; + let mut tree = SumTree::::new(); + let count = rng.gen_range(0..10); + tree.extend(rng.sample_iter(distributions::Standard).take(count), &()); + + for _ in 0..5 { + let splice_end = rng.gen_range(0..tree.extent::(&()).0 + 1); + let splice_start = rng.gen_range(0..splice_end + 1); + let count = rng.gen_range(0..3); + let tree_end = tree.extent::(&()); + let new_items = rng + .sample_iter(distributions::Standard) + .take(count) + .collect::>(); + + let mut reference_items = tree.items(&()); + reference_items.splice(splice_start..splice_end, new_items.clone()); + + tree = { + let mut cursor = tree.cursor::(); + let mut new_tree = cursor.slice(&Count(splice_start), Bias::Right, &()); + new_tree.extend(new_items, &()); + cursor.seek(&Count(splice_end), Bias::Right, &()); + new_tree.push_tree(cursor.slice(&tree_end, Bias::Right, &()), &()); + new_tree + }; + + assert_eq!(tree.items(&()), reference_items); + + let mut filter_cursor = + tree.filter::<_, Count>(|summary| summary.contains_even, &()); + let mut reference_filter = tree + .items(&()) + .into_iter() + .enumerate() + .filter(|(_, item)| (item & 1) == 0); + while let Some(actual_item) = filter_cursor.item() { + let (reference_index, reference_item) = reference_filter.next().unwrap(); + assert_eq!(actual_item, &reference_item); + assert_eq!(filter_cursor.start().0, reference_index); + filter_cursor.next(&()); + } + assert!(reference_filter.next().is_none()); - for i in 0..10 { - assert_eq!(cursor.start().0, pos); + let mut pos = rng.gen_range(0..tree.extent::(&()).0 + 1); + let mut before_start = false; + let mut cursor = tree.cursor::(); + cursor.seek(&Count(pos), Bias::Right, &()); - if pos > 0 { - assert_eq!(cursor.prev_item().unwrap(), &reference_items[pos - 1]); - } else { - assert_eq!(cursor.prev_item(), None); - } + for i in 0..10 { + assert_eq!(cursor.start().0, pos); - if pos < reference_items.len() && !before_start { - assert_eq!(cursor.item().unwrap(), &reference_items[pos]); - } else { - assert_eq!(cursor.item(), None); - } + if pos > 0 { + assert_eq!(cursor.prev_item().unwrap(), &reference_items[pos - 1]); + } else { + assert_eq!(cursor.prev_item(), None); + } - if i < 5 { - cursor.next(&()); - if pos < reference_items.len() { - pos += 1; - before_start = false; + if pos < reference_items.len() && !before_start { + assert_eq!(cursor.item().unwrap(), &reference_items[pos]); + } else { + assert_eq!(cursor.item(), None); } - } else { - cursor.prev(&()); - if pos == 0 { - before_start = true; + + if i < 5 { + cursor.next(&()); + if pos < reference_items.len() { + pos += 1; + before_start = false; + } + } else { + cursor.prev(&()); + if pos == 0 { + before_start = true; + } + pos = pos.saturating_sub(1); } - pos = pos.saturating_sub(1); } } - } - for _ in 0..10 { - let end = rng.gen_range(0..tree.extent::(&()).0 + 1); - let start = rng.gen_range(0..end + 1); - let start_bias = if rng.gen() { Bias::Left } else { Bias::Right }; - let end_bias = if rng.gen() { Bias::Left } else { Bias::Right }; + for _ in 0..10 { + let end = rng.gen_range(0..tree.extent::(&()).0 + 1); + let start = rng.gen_range(0..end + 1); + let start_bias = if rng.gen() { Bias::Left } else { Bias::Right }; + let end_bias = if rng.gen() { Bias::Left } else { Bias::Right }; - let mut cursor = tree.cursor::(); - cursor.seek(&Count(start), start_bias, &()); - let slice = cursor.slice(&Count(end), end_bias, &()); + let mut cursor = tree.cursor::(); + cursor.seek(&Count(start), start_bias, &()); + let slice = cursor.slice(&Count(end), end_bias, &()); - cursor.seek(&Count(start), start_bias, &()); - let summary = cursor.summary::<_, Sum>(&Count(end), end_bias, &()); + cursor.seek(&Count(start), start_bias, &()); + let summary = cursor.summary::<_, Sum>(&Count(end), end_bias, &()); - assert_eq!(summary.0, slice.summary().sum); + assert_eq!(summary.0, slice.summary().sum); + } } } diff --git a/zed/Cargo.toml b/zed/Cargo.toml index 17d42a04c95253c5f0943724a7cb52ea238c8faf..6f14398eb05f34af1570f16e0d76ee9fe828344b 100644 --- a/zed/Cargo.toml +++ b/zed/Cargo.toml @@ -51,6 +51,7 @@ similar = "1.3" simplelog = "0.9" smallvec = { version = "1.6", features = ["union"] } smol = "1.2.5" +sum_tree = { "path" = "../sum_tree" } surf = "2.2" tempdir = { version = "0.3.7", optional = true } thiserror = "1.0.29" diff --git a/zed/src/channel.rs b/zed/src/channel.rs index 40807cc58567f52a44caf19653432cac3ce0eab4..5b4dfa6d39b5933623827c3fb76c9d211c176f38 100644 --- a/zed/src/channel.rs +++ b/zed/src/channel.rs @@ -5,7 +5,6 @@ use crate::{ }; use anyhow::{anyhow, Context, Result}; use gpui::{ - sum_tree::{self, Bias, SumTree}, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle, }; use postage::prelude::Stream; @@ -16,6 +15,7 @@ use std::{ ops::Range, sync::Arc, }; +use sum_tree::{self, Bias, SumTree}; use time::OffsetDateTime; use zrpc::{ proto::{self, ChannelMessageSent}, diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index 99be7d4181eafc91c9b1fd8dde5403f4a155ccbd..d7ad88009399090b6eb8e69c87245ecbd0191169 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -13,8 +13,8 @@ use crate::{ }; pub use anchor::*; use anyhow::{anyhow, Result}; +use sum_tree::{self, FilterCursor, SumTree}; use gpui::{ - sum_tree::{self, FilterCursor, SumTree}, AppContext, Entity, ModelContext, ModelHandle, Task, }; use lazy_static::lazy_static; diff --git a/zed/src/editor/buffer/operation_queue.rs b/zed/src/editor/buffer/operation_queue.rs index 97ec360b8f44d10e41ad1ae55df0b51f42c90a90..ae426d77a4fd225df38fbf660c2ba4cb0053eb16 100644 --- a/zed/src/editor/buffer/operation_queue.rs +++ b/zed/src/editor/buffer/operation_queue.rs @@ -1,7 +1,7 @@ use super::Operation; use crate::time; -use gpui::sum_tree::{Cursor, Dimension, Edit, Item, KeyedItem, SumTree, Summary}; use std::{fmt::Debug, ops::Add}; +use sum_tree::{Cursor, Dimension, Edit, Item, KeyedItem, SumTree, Summary}; #[derive(Clone, Debug)] pub struct OperationQueue(SumTree); diff --git a/zed/src/editor/buffer/rope.rs b/zed/src/editor/buffer/rope.rs index a4fe867da6b2b8a883062ecdd120b115c38e4c9f..414679c2d902bc486aa1b9b31221325998640651 100644 --- a/zed/src/editor/buffer/rope.rs +++ b/zed/src/editor/buffer/rope.rs @@ -1,9 +1,9 @@ use super::Point; use crate::util::Bias; use arrayvec::ArrayString; -use gpui::sum_tree::{self, SumTree}; use smallvec::SmallVec; use std::{cmp, ops::Range, str}; +use sum_tree::{self, SumTree}; #[cfg(test)] const CHUNK_BASE: usize = 6; diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 1fa3a22e3f50b9d1aa995654ae0a57dcad6d1724..aa7d0f44fa2425224ac13fb9d6797b2b32c40842 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -3,10 +3,7 @@ use super::{ Anchor, Buffer, Point, ToOffset, }; use crate::{editor::buffer, settings::HighlightId, time, util::Bias}; -use gpui::{ - sum_tree::{self, Cursor, FilterCursor, SumTree}, - AppContext, ModelHandle, -}; +use gpui::{AppContext, ModelHandle}; use parking_lot::Mutex; use std::{ cmp::{self, Ordering}, @@ -14,6 +11,7 @@ use std::{ ops::Range, sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; +use sum_tree::{self, Cursor, FilterCursor, SumTree}; #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] pub struct FoldPoint(pub super::Point); diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index 4bc31785fff5fdd628dfd4ad5380d7e9a7357b3e..2aabe374ed27da8305168b457a6277ae128d89bb 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -3,15 +3,11 @@ use super::{ tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint, TextSummary}, }; use crate::{editor::Point, settings::HighlightId, util::Bias}; -use gpui::{ - fonts::FontId, - sum_tree::{self, Cursor, SumTree}, - text_layout::LineWrapper, - Entity, ModelContext, Task, -}; +use gpui::{fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, Task}; use lazy_static::lazy_static; use smol::future::yield_now; use std::{collections::VecDeque, ops::Range, time::Duration}; +use sum_tree::{self, Cursor, SumTree}; pub struct WrapMap { snapshot: Snapshot, diff --git a/zed/src/util.rs b/zed/src/util.rs index 9e7a912ce8dfa076e9e8d9ccfbe2d66e96b8d7e2..e199925d98742e6023a9383b57872da2c46af5ec 100644 --- a/zed/src/util.rs +++ b/zed/src/util.rs @@ -1,11 +1,11 @@ -use futures::{Future}; -pub use gpui::sum_tree::Bias; +use futures::Future; use rand::prelude::*; use std::{ cmp::Ordering, pin::Pin, task::{Context, Poll}, }; +pub use sum_tree::Bias; pub fn post_inc(value: &mut usize) -> usize { let prev = *value; diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index eaeefcd46257f293530eaee73488fd30461a9cc5..56ed2cb731fd9a9e2dd73478d904eac19ed69ef0 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -15,9 +15,9 @@ use ::ignore::gitignore::{Gitignore, GitignoreBuilder}; use anyhow::{anyhow, Result}; use futures::{Stream, StreamExt}; pub use fuzzy::{match_paths, PathMatch}; +use sum_tree::{self, Edit, SeekTarget, SumTree}; use gpui::{ executor, - sum_tree::{self, Edit, SeekTarget, SumTree}, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle, };