mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Swap arrayvec crate for heapless to use LenT optimization (#47101)
Swaps the `arrayvec` dependency for `heapless`, as the `heapless` library allows changing the type used for the `len` field, which `arrayvec` hard-codes to `usize`. This means that, for all the `ArrayVec`s in Zed, we can save 7 bytes on 64 bit platforms by just storing the length as a `u8`. I have not benchmarked this change locally, as I don't know what benchmarking tools are in this project. As a small bit of context, I wrote the PR to `heapless` to add this `LenT` generic after seeing a PR on the `arrayvec` crate that seems to be dead now. Once I saw some of Zed's blog posts about the `rope` crate and noticed the usage of `arrayvec`, I thought this might be a welcome change. Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
parent
abec0efce8
commit
aabc967b1c
13 changed files with 176 additions and 116 deletions
30
Cargo.lock
generated
30
Cargo.lock
generated
|
|
@ -334,7 +334,6 @@ dependencies = [
|
|||
"agent_settings",
|
||||
"ai_onboarding",
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
"assistant_slash_command",
|
||||
"assistant_slash_commands",
|
||||
"assistant_text_thread",
|
||||
|
|
@ -363,6 +362,7 @@ dependencies = [
|
|||
"git",
|
||||
"gpui",
|
||||
"gpui_tokio",
|
||||
"heapless",
|
||||
"html_to_markdown",
|
||||
"http_client",
|
||||
"image",
|
||||
|
|
@ -733,9 +733,6 @@ name = "arrayvec"
|
|||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "as-raw-xcb-connection"
|
||||
|
|
@ -5238,7 +5235,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"ai_onboarding",
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
"brotli",
|
||||
"buffer_diff",
|
||||
"client",
|
||||
|
|
@ -5256,6 +5252,7 @@ dependencies = [
|
|||
"fs",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"heapless",
|
||||
"indoc",
|
||||
"itertools 0.14.0",
|
||||
"language",
|
||||
|
|
@ -8027,6 +8024,15 @@ dependencies = [
|
|||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
|
@ -8111,6 +8117,16 @@ dependencies = [
|
|||
"http 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
|
|
@ -14672,10 +14688,10 @@ dependencies = [
|
|||
name = "rope"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"criterion",
|
||||
"ctor",
|
||||
"gpui",
|
||||
"heapless",
|
||||
"log",
|
||||
"rand 0.9.2",
|
||||
"rayon",
|
||||
|
|
@ -16736,8 +16752,8 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||
name = "sum_tree"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ctor",
|
||||
"heapless",
|
||||
"log",
|
||||
"proptest",
|
||||
"rand 0.9.2",
|
||||
|
|
|
|||
|
|
@ -480,7 +480,6 @@ aho-corasick = "1.1"
|
|||
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "9d9640d4" }
|
||||
any_vec = "0.14"
|
||||
anyhow = "1.0.86"
|
||||
arrayvec = { version = "0.7.4", features = ["serde"] }
|
||||
ashpd = { version = "0.13", default-features = false, features = [
|
||||
"async-io",
|
||||
"notification",
|
||||
|
|
@ -564,6 +563,7 @@ futures-lite = "1.13"
|
|||
gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "37f3c0575d379c218a9c455ee67585184e40d43f" }
|
||||
git2 = { version = "0.20.1", default-features = false, features = ["vendored-libgit2"] }
|
||||
globset = "0.4"
|
||||
heapless = "0.9.2"
|
||||
handlebars = "4.3"
|
||||
heck = "0.5"
|
||||
heed = { version = "0.21.0", features = ["read-txn-no-tls"] }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ agent_servers.workspace = true
|
|||
agent_settings.workspace = true
|
||||
ai_onboarding.workspace = true
|
||||
anyhow.workspace = true
|
||||
arrayvec.workspace = true
|
||||
heapless.workspace = true
|
||||
assistant_text_thread.workspace = true
|
||||
assistant_slash_command.workspace = true
|
||||
assistant_slash_commands.workspace = true
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use agent_servers::AgentServerDelegate;
|
|||
use agent_servers::{AgentServer, GEMINI_TERMINAL_AUTH_METHOD_ID};
|
||||
use agent_settings::{AgentProfileId, AgentSettings};
|
||||
use anyhow::{Result, anyhow};
|
||||
use arrayvec::ArrayVec;
|
||||
use audio::{Audio, Sound};
|
||||
use buffer_diff::BufferDiff;
|
||||
use client::zed_urls;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use editor::actions::OpenExcerpts;
|
|||
use crate::StartThreadIn;
|
||||
use crate::message_editor::SharedSessionCapabilities;
|
||||
use gpui::{Corner, List};
|
||||
use heapless::Vec as ArrayVec;
|
||||
use language_model::{LanguageModelEffortLevel, Speed};
|
||||
use settings::update_settings_file;
|
||||
use ui::{ButtonLike, SplitButton, SplitButtonStyle, Tab};
|
||||
|
|
@ -6367,7 +6368,7 @@ impl ThreadView {
|
|||
focus_handle: &FocusHandle,
|
||||
cx: &Context<Self>,
|
||||
) -> Div {
|
||||
let mut seen_kinds: ArrayVec<acp::PermissionOptionKind, 3> = ArrayVec::new();
|
||||
let mut seen_kinds: ArrayVec<acp::PermissionOptionKind, 3, u8> = ArrayVec::new();
|
||||
|
||||
div()
|
||||
.p_1()
|
||||
|
|
@ -6417,7 +6418,7 @@ impl ThreadView {
|
|||
return this;
|
||||
}
|
||||
|
||||
seen_kinds.push(option.kind);
|
||||
seen_kinds.push(option.kind).unwrap();
|
||||
|
||||
this.key_binding(
|
||||
KeyBinding::for_action_in(action, focus_handle, cx)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ cli-support = []
|
|||
[dependencies]
|
||||
ai_onboarding.workspace = true
|
||||
anyhow.workspace = true
|
||||
arrayvec.workspace = true
|
||||
heapless.workspace = true
|
||||
brotli.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
client.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use anyhow::Result;
|
||||
use arrayvec::ArrayVec;
|
||||
use client::{Client, EditPredictionUsage, UserStore};
|
||||
use cloud_api_types::{OrganizationId, SubmitEditPredictionFeedbackBody};
|
||||
use cloud_llm_client::predict_edits_v3::{
|
||||
|
|
@ -27,6 +26,7 @@ use gpui::{
|
|||
http_client::{self, AsyncBody, Method},
|
||||
prelude::*,
|
||||
};
|
||||
use heapless::Vec as ArrayVec;
|
||||
use language::language_settings::all_language_settings;
|
||||
use language::{Anchor, Buffer, File, Point, TextBufferSnapshot, ToOffset, ToPoint};
|
||||
use language::{BufferSnapshot, OffsetRangeExt};
|
||||
|
|
@ -332,7 +332,7 @@ struct ProjectState {
|
|||
registered_buffers: HashMap<gpui::EntityId, RegisteredBuffer>,
|
||||
current_prediction: Option<CurrentEditPrediction>,
|
||||
next_pending_prediction_id: usize,
|
||||
pending_predictions: ArrayVec<PendingPrediction, 2>,
|
||||
pending_predictions: ArrayVec<PendingPrediction, 2, u8>,
|
||||
debug_tx: Option<mpsc::UnboundedSender<DebugEvent>>,
|
||||
last_edit_prediction_refresh: Option<(EntityId, Instant)>,
|
||||
last_jump_prediction_refresh: Option<(EntityId, Instant)>,
|
||||
|
|
@ -2311,18 +2311,24 @@ impl EditPredictionStore {
|
|||
});
|
||||
|
||||
if project_state.pending_predictions.len() < max_pending_predictions {
|
||||
project_state.pending_predictions.push(PendingPrediction {
|
||||
id: pending_prediction_id,
|
||||
task,
|
||||
drop_on_cancel,
|
||||
});
|
||||
project_state
|
||||
.pending_predictions
|
||||
.push(PendingPrediction {
|
||||
id: pending_prediction_id,
|
||||
task,
|
||||
drop_on_cancel,
|
||||
})
|
||||
.unwrap();
|
||||
} else {
|
||||
let pending_prediction = project_state.pending_predictions.pop().unwrap();
|
||||
project_state.pending_predictions.push(PendingPrediction {
|
||||
id: pending_prediction_id,
|
||||
task,
|
||||
drop_on_cancel,
|
||||
});
|
||||
project_state
|
||||
.pending_predictions
|
||||
.push(PendingPrediction {
|
||||
id: pending_prediction_id,
|
||||
task,
|
||||
drop_on_cancel,
|
||||
})
|
||||
.unwrap();
|
||||
project_state.cancel_pending_prediction(pending_prediction, cx);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ workspace = true
|
|||
path = "src/rope.rs"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.7.1"
|
||||
heapless.workspace = true
|
||||
log.workspace = true
|
||||
rayon.workspace = true
|
||||
sum_tree.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{OffsetUtf16, Point, PointUtf16, TextSummary, Unclipped};
|
||||
use arrayvec::ArrayString;
|
||||
use heapless::String as ArrayString;
|
||||
use std::{cmp, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
use unicode_segmentation::GraphemeCursor;
|
||||
|
|
@ -29,7 +29,7 @@ pub struct Chunk {
|
|||
newlines: Bitmap,
|
||||
/// If bit[i] is set, then the character at index i is an ascii tab.
|
||||
tabs: Bitmap,
|
||||
pub text: ArrayString<MAX_BASE>,
|
||||
pub text: ArrayString<MAX_BASE, u8>,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -47,7 +47,11 @@ impl Chunk {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn new(text: &str) -> Self {
|
||||
let text = ArrayString::from(text).unwrap();
|
||||
let text = {
|
||||
let mut buf = ArrayString::new();
|
||||
buf.push_str(text).unwrap();
|
||||
buf
|
||||
};
|
||||
|
||||
const CHUNK_SIZE: usize = 8;
|
||||
|
||||
|
|
@ -118,7 +122,7 @@ impl Chunk {
|
|||
self.chars_utf16 |= slice.chars_utf16 << base_ix;
|
||||
self.newlines |= slice.newlines << base_ix;
|
||||
self.tabs |= slice.tabs << base_ix;
|
||||
self.text.push_str(slice.text);
|
||||
self.text.push_str(slice.text).unwrap();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -137,9 +141,9 @@ impl Chunk {
|
|||
self.newlines = slice.newlines | (self.newlines << shift);
|
||||
self.tabs = slice.tabs | (self.tabs << shift);
|
||||
|
||||
let mut new_text = ArrayString::<MAX_BASE>::new();
|
||||
new_text.push_str(slice.text);
|
||||
new_text.push_str(&self.text);
|
||||
let mut new_text = ArrayString::<MAX_BASE, u8>::new();
|
||||
new_text.push_str(slice.text).unwrap();
|
||||
new_text.push_str(&self.text).unwrap();
|
||||
self.text = new_text;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ mod point;
|
|||
mod point_utf16;
|
||||
mod unclipped;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use heapless::Vec as ArrayVec;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator as _};
|
||||
use std::{
|
||||
cmp, fmt, io, mem,
|
||||
|
|
@ -184,7 +184,7 @@ impl Rope {
|
|||
return self.push_large(text);
|
||||
}
|
||||
// 16 is enough as otherwise we will hit the branch above
|
||||
let mut new_chunks = ArrayVec::<_, NUM_CHUNKS>::new();
|
||||
let mut new_chunks = ArrayVec::<_, NUM_CHUNKS, u8>::new();
|
||||
|
||||
while !text.is_empty() {
|
||||
let mut split_ix = cmp::min(chunk::MAX_BASE, text.len());
|
||||
|
|
@ -192,7 +192,7 @@ impl Rope {
|
|||
split_ix -= 1;
|
||||
}
|
||||
let (chunk, remainder) = text.split_at(split_ix);
|
||||
new_chunks.push(chunk);
|
||||
new_chunks.push(chunk).unwrap();
|
||||
text = remainder;
|
||||
}
|
||||
self.chunks
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ path = "src/sum_tree.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.7.1"
|
||||
heapless.workspace = true
|
||||
rayon.workspace = true
|
||||
log.workspace = true
|
||||
ztracing.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use arrayvec::ArrayVec;
|
||||
use heapless::Vec as ArrayVec;
|
||||
use std::{cmp::Ordering, mem, sync::Arc};
|
||||
use ztracing::instrument;
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for StackEntry<'_, T, D> {
|
|||
#[derive(Clone)]
|
||||
pub struct Cursor<'a, 'b, T: Item, D> {
|
||||
tree: &'a SumTree<T>,
|
||||
stack: ArrayVec<StackEntry<'a, T, D>, 16>,
|
||||
stack: ArrayVec<StackEntry<'a, T, D>, 16, u8>,
|
||||
pub position: D,
|
||||
did_seek: bool,
|
||||
at_end: bool,
|
||||
|
|
@ -53,7 +53,7 @@ where
|
|||
|
||||
pub struct Iter<'a, T: Item> {
|
||||
tree: &'a SumTree<T>,
|
||||
stack: ArrayVec<StackEntry<'a, T, ()>, 16>,
|
||||
stack: ArrayVec<StackEntry<'a, T, ()>, 16, u8>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, T, D> Cursor<'a, 'b, T, D>
|
||||
|
|
@ -231,11 +231,13 @@ where
|
|||
self.position = D::zero(self.cx);
|
||||
self.at_end = self.tree.is_empty();
|
||||
if !self.tree.is_empty() {
|
||||
self.stack.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: self.tree.0.child_summaries().len() as u32,
|
||||
position: D::from_summary(self.tree.summary(), self.cx),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: self.tree.0.child_summaries().len() as u32,
|
||||
position: D::from_summary(self.tree.summary(), self.cx),
|
||||
})
|
||||
.unwrap_oob();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,11 +269,13 @@ where
|
|||
Node::Internal { child_trees, .. } => {
|
||||
if descending {
|
||||
let tree = &child_trees[entry.index()];
|
||||
self.stack.push(StackEntry {
|
||||
position: D::zero(self.cx),
|
||||
tree,
|
||||
index: tree.0.child_summaries().len() as u32 - 1,
|
||||
})
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
position: D::zero(self.cx),
|
||||
tree,
|
||||
index: tree.0.child_summaries().len() as u32 - 1,
|
||||
})
|
||||
.unwrap_oob();
|
||||
}
|
||||
}
|
||||
Node::Leaf { .. } => {
|
||||
|
|
@ -297,11 +301,13 @@ where
|
|||
|
||||
if self.stack.is_empty() {
|
||||
if !self.at_end {
|
||||
self.stack.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: 0,
|
||||
position: D::zero(self.cx),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: 0,
|
||||
position: D::zero(self.cx),
|
||||
})
|
||||
.unwrap_oob();
|
||||
descend = true;
|
||||
}
|
||||
self.did_seek = true;
|
||||
|
|
@ -361,11 +367,13 @@ where
|
|||
|
||||
if let Some(subtree) = new_subtree {
|
||||
descend = true;
|
||||
self.stack.push(StackEntry {
|
||||
tree: subtree,
|
||||
index: 0,
|
||||
position: self.position.clone(),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: subtree,
|
||||
index: 0,
|
||||
position: self.position.clone(),
|
||||
})
|
||||
.unwrap_oob();
|
||||
} else {
|
||||
descend = false;
|
||||
self.stack.pop();
|
||||
|
|
@ -467,11 +475,13 @@ where
|
|||
|
||||
if !self.did_seek {
|
||||
self.did_seek = true;
|
||||
self.stack.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: 0,
|
||||
position: D::zero(self.cx),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: 0,
|
||||
position: D::zero(self.cx),
|
||||
})
|
||||
.unwrap_oob();
|
||||
}
|
||||
|
||||
let mut ascending = false;
|
||||
|
|
@ -503,11 +513,13 @@ where
|
|||
entry.index += 1;
|
||||
entry.position = self.position.clone();
|
||||
} else {
|
||||
self.stack.push(StackEntry {
|
||||
tree: child_tree,
|
||||
index: 0,
|
||||
position: self.position.clone(),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: child_tree,
|
||||
index: 0,
|
||||
position: self.position.clone(),
|
||||
})
|
||||
.unwrap_oob();
|
||||
ascending = false;
|
||||
continue 'outer;
|
||||
}
|
||||
|
|
@ -578,11 +590,13 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
|
|||
let mut descend = false;
|
||||
|
||||
if self.stack.is_empty() {
|
||||
self.stack.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: 0,
|
||||
position: (),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: self.tree,
|
||||
index: 0,
|
||||
position: (),
|
||||
})
|
||||
.unwrap_oob();
|
||||
descend = true;
|
||||
}
|
||||
|
||||
|
|
@ -611,11 +625,13 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
|
|||
|
||||
if let Some(subtree) = new_subtree {
|
||||
descend = true;
|
||||
self.stack.push(StackEntry {
|
||||
tree: subtree,
|
||||
index: 0,
|
||||
position: (),
|
||||
});
|
||||
self.stack
|
||||
.push(StackEntry {
|
||||
tree: subtree,
|
||||
index: 0,
|
||||
position: (),
|
||||
})
|
||||
.unwrap_oob();
|
||||
} else {
|
||||
descend = false;
|
||||
self.stack.pop();
|
||||
|
|
@ -748,8 +764,8 @@ trait SeekAggregate<'a, T: Item> {
|
|||
|
||||
struct SliceSeekAggregate<T: Item> {
|
||||
tree: SumTree<T>,
|
||||
leaf_items: ArrayVec<T, { 2 * TREE_BASE }>,
|
||||
leaf_item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
|
||||
leaf_items: ArrayVec<T, { 2 * TREE_BASE }, u8>,
|
||||
leaf_item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>,
|
||||
leaf_summary: T::Summary,
|
||||
}
|
||||
|
||||
|
|
@ -786,8 +802,8 @@ impl<T: Item> SeekAggregate<'_, T> for SliceSeekAggregate<T> {
|
|||
summary: &T::Summary,
|
||||
cx: <T::Summary as Summary>::Context<'_>,
|
||||
) {
|
||||
self.leaf_items.push(item.clone());
|
||||
self.leaf_item_summaries.push(summary.clone());
|
||||
self.leaf_items.push(item.clone()).unwrap_oob();
|
||||
self.leaf_item_summaries.push(summary.clone()).unwrap_oob();
|
||||
Summary::add_summary(&mut self.leaf_summary, summary, cx);
|
||||
}
|
||||
fn push_tree(
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ mod cursor;
|
|||
pub mod property_test;
|
||||
mod tree_map;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
pub use cursor::{Cursor, FilterCursor, Iter};
|
||||
use heapless::Vec as ArrayVec;
|
||||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator as _};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
|
@ -17,6 +17,17 @@ pub const TREE_BASE: usize = 2;
|
|||
#[cfg(not(test))]
|
||||
pub const TREE_BASE: usize = 6;
|
||||
|
||||
// Helper for when we cannot use ArrayVec::<T>::push().unwrap() as T doesn't impl Debug
|
||||
trait CapacityResultExt {
|
||||
fn unwrap_oob(self);
|
||||
}
|
||||
|
||||
impl<T> CapacityResultExt for Result<(), T> {
|
||||
fn unwrap_oob(self) {
|
||||
self.unwrap_or_else(|_| panic!("item should fit into fixed size ArrayVec"))
|
||||
}
|
||||
}
|
||||
|
||||
/// An item that can be stored in a [`SumTree`]
|
||||
///
|
||||
/// Must be summarized by a type that implements [`Summary`]
|
||||
|
|
@ -243,8 +254,9 @@ impl<T: Item> SumTree<T> {
|
|||
|
||||
let mut iter = iter.into_iter().fuse().peekable();
|
||||
while iter.peek().is_some() {
|
||||
let items: ArrayVec<T, { 2 * TREE_BASE }> = iter.by_ref().take(2 * TREE_BASE).collect();
|
||||
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }> =
|
||||
let items: ArrayVec<T, { 2 * TREE_BASE }, u8> =
|
||||
iter.by_ref().take(2 * TREE_BASE).collect();
|
||||
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8> =
|
||||
items.iter().map(|item| item.summary(cx)).collect();
|
||||
|
||||
let mut summary = item_summaries[0].clone();
|
||||
|
|
@ -284,8 +296,8 @@ impl<T: Item> SumTree<T> {
|
|||
};
|
||||
let child_summary = child_node.summary();
|
||||
<T::Summary as Summary>::add_summary(summary, child_summary, cx);
|
||||
child_summaries.push(child_summary.clone());
|
||||
child_trees.push(child_node);
|
||||
child_summaries.push(child_summary.clone()).unwrap_oob();
|
||||
child_trees.push(child_node.clone()).unwrap_oob();
|
||||
|
||||
if child_trees.len() == 2 * TREE_BASE {
|
||||
parent_nodes.extend(current_parent_node.take());
|
||||
|
|
@ -315,8 +327,8 @@ impl<T: Item> SumTree<T> {
|
|||
.into_par_iter()
|
||||
.chunks(2 * TREE_BASE)
|
||||
.map(|items| {
|
||||
let items: ArrayVec<T, { 2 * TREE_BASE }> = items.into_iter().collect();
|
||||
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }> =
|
||||
let items: ArrayVec<T, { 2 * TREE_BASE }, u8> = items.into_iter().collect();
|
||||
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8> =
|
||||
items.iter().map(|item| item.summary(cx)).collect();
|
||||
let mut summary = item_summaries[0].clone();
|
||||
for item_summary in &item_summaries[1..] {
|
||||
|
|
@ -337,9 +349,9 @@ impl<T: Item> SumTree<T> {
|
|||
.into_par_iter()
|
||||
.chunks(2 * TREE_BASE)
|
||||
.map(|child_nodes| {
|
||||
let child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }> =
|
||||
let child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }, u8> =
|
||||
child_nodes.into_iter().collect();
|
||||
let child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }> = child_trees
|
||||
let child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8> = child_trees
|
||||
.iter()
|
||||
.map(|child_tree| child_tree.summary().clone())
|
||||
.collect();
|
||||
|
|
@ -798,14 +810,16 @@ impl<T: Item> SumTree<T> {
|
|||
<T::Summary as Summary>::add_summary(summary, other_node.summary(), cx);
|
||||
|
||||
let height_delta = *height - other_node.height();
|
||||
let mut summaries_to_append = ArrayVec::<T::Summary, { 2 * TREE_BASE }>::new();
|
||||
let mut trees_to_append = ArrayVec::<SumTree<T>, { 2 * TREE_BASE }>::new();
|
||||
let mut summaries_to_append = ArrayVec::<T::Summary, { 2 * TREE_BASE }, u8>::new();
|
||||
let mut trees_to_append = ArrayVec::<SumTree<T>, { 2 * TREE_BASE }, u8>::new();
|
||||
if height_delta == 0 {
|
||||
summaries_to_append.extend(other_node.child_summaries().iter().cloned());
|
||||
trees_to_append.extend(other_node.child_trees().iter().cloned());
|
||||
} else if height_delta == 1 && !other_node.is_underflowing() {
|
||||
summaries_to_append.push(other_node.summary().clone());
|
||||
trees_to_append.push(other)
|
||||
summaries_to_append
|
||||
.push(other_node.summary().clone())
|
||||
.unwrap_oob();
|
||||
trees_to_append.push(other).unwrap_oob();
|
||||
} else {
|
||||
let tree_to_append = child_trees
|
||||
.last_mut()
|
||||
|
|
@ -815,15 +829,17 @@ impl<T: Item> SumTree<T> {
|
|||
child_trees.last().unwrap().0.summary().clone();
|
||||
|
||||
if let Some(split_tree) = tree_to_append {
|
||||
summaries_to_append.push(split_tree.0.summary().clone());
|
||||
trees_to_append.push(split_tree);
|
||||
summaries_to_append
|
||||
.push(split_tree.0.summary().clone())
|
||||
.unwrap_oob();
|
||||
trees_to_append.push(split_tree).unwrap_oob();
|
||||
}
|
||||
}
|
||||
|
||||
let child_count = child_trees.len() + trees_to_append.len();
|
||||
if child_count > 2 * TREE_BASE {
|
||||
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }>;
|
||||
let right_summaries: ArrayVec<_, { 2 * TREE_BASE }>;
|
||||
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8>;
|
||||
let right_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8>;
|
||||
let left_trees;
|
||||
let right_trees;
|
||||
|
||||
|
|
@ -868,7 +884,7 @@ impl<T: Item> SumTree<T> {
|
|||
let left_items;
|
||||
let right_items;
|
||||
let left_summaries;
|
||||
let right_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>;
|
||||
let right_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>;
|
||||
|
||||
let midpoint = (child_count + child_count % 2) / 2;
|
||||
{
|
||||
|
|
@ -933,8 +949,10 @@ impl<T: Item> SumTree<T> {
|
|||
*child_summaries.first_mut().unwrap() = first.summary().clone();
|
||||
if let Some(tree) = res {
|
||||
if child_trees.len() < 2 * TREE_BASE {
|
||||
child_summaries.insert(0, tree.summary().clone());
|
||||
child_trees.insert(0, tree);
|
||||
child_summaries
|
||||
.insert(0, tree.summary().clone())
|
||||
.unwrap_oob();
|
||||
child_trees.insert(0, tree).unwrap_oob();
|
||||
None
|
||||
} else {
|
||||
let new_child_summaries = {
|
||||
|
|
@ -1016,7 +1034,7 @@ impl<T: Item> SumTree<T> {
|
|||
.iter()
|
||||
.chain(child_summaries.iter())
|
||||
.cloned();
|
||||
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }> =
|
||||
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8> =
|
||||
all_summaries.by_ref().take(midpoint).collect();
|
||||
*child_summaries = all_summaries.collect();
|
||||
|
||||
|
|
@ -1065,7 +1083,7 @@ impl<T: Item> SumTree<T> {
|
|||
.iter()
|
||||
.chain(item_summaries.iter())
|
||||
.cloned();
|
||||
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }> =
|
||||
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8> =
|
||||
all_summaries.by_ref().take(midpoint).collect();
|
||||
*item_summaries = all_summaries.collect();
|
||||
|
||||
|
|
@ -1088,11 +1106,11 @@ impl<T: Item> SumTree<T> {
|
|||
) -> Self {
|
||||
let height = left.0.height() + 1;
|
||||
let mut child_summaries = ArrayVec::new();
|
||||
child_summaries.push(left.0.summary().clone());
|
||||
child_summaries.push(right.0.summary().clone());
|
||||
child_summaries.push(left.0.summary().clone()).unwrap_oob();
|
||||
child_summaries.push(right.0.summary().clone()).unwrap_oob();
|
||||
let mut child_trees = ArrayVec::new();
|
||||
child_trees.push(left);
|
||||
child_trees.push(right);
|
||||
child_trees.push(left).unwrap_oob();
|
||||
child_trees.push(right).unwrap_oob();
|
||||
SumTree(Arc::new(Node::Internal {
|
||||
height,
|
||||
summary: sum(child_summaries.iter(), cx),
|
||||
|
|
@ -1252,13 +1270,13 @@ pub enum Node<T: Item> {
|
|||
Internal {
|
||||
height: u8,
|
||||
summary: T::Summary,
|
||||
child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
|
||||
child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }>,
|
||||
child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>,
|
||||
child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }, u8>,
|
||||
},
|
||||
Leaf {
|
||||
summary: T::Summary,
|
||||
items: ArrayVec<T, { 2 * TREE_BASE }>,
|
||||
item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
|
||||
items: ArrayVec<T, { 2 * TREE_BASE }, u8>,
|
||||
item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1323,14 +1341,14 @@ impl<T: Item> Node<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn child_trees(&self) -> &ArrayVec<SumTree<T>, { 2 * TREE_BASE }> {
|
||||
fn child_trees(&self) -> &ArrayVec<SumTree<T>, { 2 * TREE_BASE }, u8> {
|
||||
match self {
|
||||
Node::Internal { child_trees, .. } => child_trees,
|
||||
Node::Leaf { .. } => panic!("Leaf nodes have no child trees"),
|
||||
}
|
||||
}
|
||||
|
||||
fn items(&self) -> &ArrayVec<T, { 2 * TREE_BASE }> {
|
||||
fn items(&self) -> &ArrayVec<T, { 2 * TREE_BASE }, u8> {
|
||||
match self {
|
||||
Node::Leaf { items, .. } => items,
|
||||
Node::Internal { .. } => panic!("Internal nodes have no items"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue