Skip to content

Commit def11d9

Browse files
committed
optimizing hot path take/skip/first/last
1 parent be034de commit def11d9

File tree

2 files changed

+372
-168
lines changed

2 files changed

+372
-168
lines changed

src/lib.rs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,19 @@ where
7777
/// however, Calcit is heavy in cloning(reference though... according real practice),
7878
/// so here we still choose `ref_get` for speed in Calcit project.
7979
pub fn get(&self, idx: usize) -> Option<&T> {
80-
if self.is_empty() || idx >= self.len() {
80+
let l = self.len();
81+
if l == 0 || idx >= l {
8182
None
83+
} else if idx == 0 {
84+
match self {
85+
Empty => None,
86+
Tree(t) => t.ref_first(),
87+
}
88+
} else if idx == l - 1 {
89+
match self {
90+
Empty => None,
91+
Tree(t) => t.ref_last(),
92+
}
8293
} else {
8394
self.ref_get(idx)
8495
}
@@ -148,6 +159,8 @@ where
148159
Tree(t) => t.last(),
149160
}
150161
}
162+
163+
// at known index, update value
151164
pub fn assoc(&self, idx: usize, item: T) -> Result<Self, String> {
152165
match self {
153166
Empty => Err(String::from("empty")),
@@ -208,7 +221,13 @@ where
208221
}
209222
}
210223

211-
Tree(t) => Ok(TernaryTreeList::Tree(t.insert(idx, item, after)?)),
224+
Tree(t) => {
225+
if after {
226+
Ok(TernaryTreeList::Tree(t.insert_after(idx, item)?))
227+
} else {
228+
Ok(TernaryTreeList::Tree(t.insert_before(idx, item)?))
229+
}
230+
}
212231
}
213232
}
214233
pub fn assoc_before(&self, idx: usize, item: T) -> Result<Self, String> {
@@ -241,7 +260,7 @@ where
241260
pub fn append(&self, item: T) -> Self {
242261
match self {
243262
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(item)),
244-
Tree(t) => TernaryTreeList::Tree(t.append(item)),
263+
Tree(t) => TernaryTreeList::Tree(t.push_right(item)),
245264
}
246265
}
247266
/// optimized for amortized `O(1)` performance at best cases
@@ -381,10 +400,33 @@ where
381400
}
382401

383402
pub fn skip(&self, idx: usize) -> Result<Self, String> {
384-
self.slice(idx, self.len())
403+
// self.slice(idx, self.len())
404+
405+
match self {
406+
Empty => Ok(TernaryTreeList::Empty),
407+
Tree(t) => {
408+
let size = t.len();
409+
match idx.cmp(&size) {
410+
Ordering::Equal => Ok(TernaryTreeList::Empty),
411+
Ordering::Greater => Err(format!("Skip range too large {} for {}", idx, self.format_inline())),
412+
Ordering::Less => Ok(TernaryTreeList::Tree(t.take_right(idx)?)),
413+
}
414+
}
415+
}
385416
}
386417
pub fn take(&self, idx: usize) -> Result<Self, String> {
387-
self.slice(0, idx)
418+
match self {
419+
Empty => Ok(TernaryTreeList::Empty),
420+
Tree(t) => {
421+
if idx == 0 {
422+
Ok(TernaryTreeList::Empty)
423+
} else if idx > self.len() {
424+
Err(format!("Take range too large {} for {}", idx, self.format_inline()))
425+
} else {
426+
Ok(TernaryTreeList::Tree(t.take_left(idx)?))
427+
}
428+
}
429+
}
388430
}
389431

390432
pub fn reverse(&self) -> Self {

0 commit comments

Comments
 (0)