Skip to content

Commit d284bda

Browse files
committed
fix: handle first key in subsets
1 parent eb35a48 commit d284bda

2 files changed

Lines changed: 55 additions & 10 deletions

File tree

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,14 @@ mod tests {
259259
current = current.entry(i - 1..i).or_insert(i)
260260
}
261261
}
262+
263+
#[test]
264+
// https://github.com/KaiserKarel/set-trie/issues/6
265+
fn subsets_small2() {
266+
let mut v = SetTrie::new();
267+
v.insert(&[1, 2], 'a');
268+
let mut s = v.subsets(&[&0, &2]);
269+
let o = s.next();
270+
assert_eq!(o, None);
271+
}
262272
}

src/subset.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use crate::{Node, SetTrie};
33
/// Iterator for [subset](SetTrie::subset) method.
44
#[derive(Debug, Clone)]
55
pub struct Subset<'a, 'b, K, T> {
6-
current: &'a Node<K, T>,
6+
current: Option<&'a Node<K, T>>,
7+
8+
/// Buffer of next nodes to visit.
79
next: Vec<(&'a K, &'a Node<K, T>)>,
810
idx: usize,
911
keys: &'b [K],
@@ -13,9 +15,33 @@ impl<'a, 'b, K, T> Subset<'a, 'b, K, T>
1315
where
1416
K: Ord,
1517
{
18+
#[must_use]
1619
pub(crate) fn new(trie: &'a SetTrie<K, T>, keys: &'b [K]) -> Self {
20+
// There might be a cleaner way to accomplish this. Right now we're doing
21+
// computation in the subset iterator, which means it's not fully lazy.
22+
let current = match keys.len() {
23+
// Empty keys has it's own leaves as childeren as items.
24+
0 => Some(&trie.0),
25+
_ => {
26+
if let Some(first) = keys.first() {
27+
if trie
28+
.0
29+
.children
30+
.binary_search_by(|(child, _)| child.cmp(first))
31+
.is_ok()
32+
{
33+
Some(&trie.0)
34+
} else {
35+
None
36+
}
37+
} else {
38+
Some(&trie.0)
39+
}
40+
}
41+
};
42+
1743
Subset {
18-
current: &trie.0,
44+
current,
1945
next: vec![],
2046
idx: 0,
2147
keys,
@@ -30,15 +56,20 @@ where
3056
type Item = &'a T;
3157

3258
fn next(&mut self) -> Option<Self::Item> {
33-
if self.idx < self.current.leaves.len() {
59+
if self.current.is_none() {
60+
return None;
61+
}
62+
63+
if self.idx < self.current.unwrap().leaves.len() {
3464
self.idx += 1;
35-
Some(&self.current.leaves[self.idx - 1])
65+
Some(&self.current.unwrap().leaves[self.idx - 1])
3666
} else {
3767
if let (Some(from), Some(to)) = (self.keys.first(), self.keys.last()) {
3868
self.next.extend(
3969
self.current
70+
.unwrap()
4071
// technically, between inclusive is only necessary on the first iteration,
41-
// where we check handle the root node. Every subsequent iter may use up-to,
72+
// where we handle the root node. Every subsequent iter may use up-to,
4273
// which saves a single binary search. For long key lengths this may matter.
4374
.between_inclusive(from, to)
4475
.iter()
@@ -49,7 +80,7 @@ where
4980
while let Some((k, node)) = self.next.pop() {
5081
if self.keys.binary_search(k).is_ok() {
5182
self.idx = 0;
52-
self.current = node;
83+
self.current = Some(node);
5384
return self.next();
5485
}
5586
self.next.extend(
@@ -64,7 +95,11 @@ where
6495
}
6596

6697
fn size_hint(&self) -> (usize, Option<usize>) {
67-
(self.current.leaves.len() - self.idx, None)
98+
if let Some(current) = self.current {
99+
(current.leaves.len() - self.idx, None)
100+
} else {
101+
(0, None)
102+
}
68103
}
69104
}
70105

@@ -94,11 +129,11 @@ mod tests {
94129
// A set is its own subset.
95130
assert_eq!(v.subsets(&[]).collect::<Vec<_>>(), vec![&'f']);
96131

97-
// Quite a specific match should work.
132+
// // Quite a specific match should work.
98133
assert_eq!(v.subsets(&[&5]).collect::<Vec<_>>(), vec![&'f', &'i']);
99134

100-
// Non-existing key should match nothing
101-
assert_eq!(v.subsets(&[&6]).collect::<Vec<_>>(), vec![&'f']);
135+
// // Non-existing key should match nothing
136+
assert_eq!(v.subsets(&[&6]).collect::<Vec<&char>>().len(), 0);
102137
}
103138

104139
mod proptest {

0 commit comments

Comments
 (0)