Skip to content

Commit d7ca26e

Browse files
committed
range: remove dead helpers (optimize_range_query, estimate_range_size, last-leaf helper); add differential range tests; docs: agent guideline to delete dead code immediately
1 parent aec495f commit d7ca26e

File tree

3 files changed

+103
-81
lines changed

3 files changed

+103
-81
lines changed

agent.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919

2020
- Hygiene before commit
2121
- Always remove dead code introduced by refactors.
22+
- Delete code as soon as it is dead.
2223
- Always format the workspace: `cd rust && cargo fmt --all`.
2324
- Always run all tests: `cargo test --workspace` (and benches if relevant).

rust/src/range_queries.rs

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -133,85 +133,5 @@ impl<K: Ord + Clone, V: Clone> BPlusTreeMap<K, V> {
133133
// RANGE OPTIMIZATION HELPERS
134134
// ============================================================================
135135

136-
/// Optimize range queries by pre-calculating bounds and positions.
137-
#[allow(dead_code)]
138-
pub fn optimize_range_query<R>(&self, range: R) -> Option<(NodeId, usize, NodeId, usize)>
139-
where
140-
R: RangeBounds<K>,
141-
{
142-
let start_pos = match range.start_bound() {
143-
Bound::Included(key) | Bound::Excluded(key) => self.find_leaf_for_key(key)?,
144-
Bound::Unbounded => {
145-
let first_leaf = self.get_first_leaf_id()?;
146-
(first_leaf, 0)
147-
}
148-
};
149-
150-
let end_pos = match range.end_bound() {
151-
Bound::Included(key) | Bound::Excluded(key) => self.find_leaf_for_key(key)?,
152-
Bound::Unbounded => {
153-
// Find the last leaf and its last position
154-
self.find_last_leaf_position()?
155-
}
156-
};
157-
158-
Some((start_pos.0, start_pos.1, end_pos.0, end_pos.1))
159-
}
160-
161-
/// Find the last leaf node and its last valid position.
162-
fn find_last_leaf_position(&self) -> Option<(NodeId, usize)> {
163-
// Start from root and go to rightmost leaf
164-
let mut current = &self.root;
165-
166-
loop {
167-
match current {
168-
NodeRef::Leaf(leaf_id, _) => {
169-
if let Some(leaf) = self.get_leaf(*leaf_id) {
170-
let last_index = if leaf.keys_is_empty() {
171-
0
172-
} else {
173-
leaf.keys_len() - 1
174-
};
175-
return Some((*leaf_id, last_index));
176-
} else {
177-
return None;
178-
}
179-
}
180-
NodeRef::Branch(branch_id, _) => {
181-
if let Some(branch) = self.get_branch(*branch_id) {
182-
if let Some(last_child) = branch.children.last() {
183-
current = last_child;
184-
} else {
185-
return None;
186-
}
187-
} else {
188-
return None;
189-
}
190-
}
191-
}
192-
}
193-
}
194-
195-
// ============================================================================
196-
// RANGE STATISTICS
197-
// ============================================================================
198-
199-
/// Estimate the number of elements in a range without iterating.
200-
#[allow(dead_code)]
201-
pub fn estimate_range_size<R>(&self, range: R) -> usize
202-
where
203-
R: RangeBounds<K>,
204-
{
205-
// Simple estimation based on tree structure
206-
// This could be optimized further with more sophisticated algorithms
207-
match (range.start_bound(), range.end_bound()) {
208-
(Bound::Unbounded, Bound::Unbounded) => self.len(),
209-
_ => {
210-
// For now, use a simple heuristic
211-
// In a real implementation, this could use tree statistics
212-
// to provide better estimates without full iteration
213-
self.len() / 4 // Conservative estimate
214-
}
215-
}
216-
}
136+
// (Removed dead code: optimize_range_query, estimate_range_size, find_last_leaf_position)
217137
}

rust/tests/range_differential.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use bplustree::BPlusTreeMap;
2+
use std::collections::BTreeMap;
3+
4+
fn populate_maps(capacity: usize, data: &[i32]) -> (BPlusTreeMap<i32, i32>, BTreeMap<i32, i32>) {
5+
let mut tree = BPlusTreeMap::new(capacity).unwrap();
6+
let mut map = BTreeMap::new();
7+
for &k in data {
8+
tree.insert(k, k * 10);
9+
map.insert(k, k * 10);
10+
}
11+
(tree, map)
12+
}
13+
14+
#[test]
15+
fn test_range_differential_basic_boundaries() {
16+
// Use small capacities to force multiple leaves and boundary transitions
17+
for &cap in &[4_usize, 5, 8] {
18+
let data: Vec<i32> = (0..20).collect();
19+
let (tree, map) = populate_maps(cap, &data);
20+
21+
// Helper to compare results for a range expression
22+
let assert_same = |lhs: Vec<(i32, i32)>, rhs: Vec<(i32, i32)>, label: &str| {
23+
assert_eq!(lhs, rhs, "mismatch for range: {} (cap={})", label, cap);
24+
};
25+
26+
// Closed-open typical range
27+
let got: Vec<_> = tree.range(3..7).map(|(k, v)| (*k, *v)).collect();
28+
let exp: Vec<_> = map.range(3..7).map(|(k, v)| (*k, *v)).collect();
29+
assert_same(got, exp, "3..7");
30+
31+
// Closed-closed
32+
let got: Vec<_> = tree.range(3..=7).map(|(k, v)| (*k, *v)).collect();
33+
let exp: Vec<_> = map.range(3..=7).map(|(k, v)| (*k, *v)).collect();
34+
assert_same(got, exp, "3..=7");
35+
36+
// Open-ended start
37+
let got: Vec<_> = tree.range(..5).map(|(k, v)| (*k, *v)).collect();
38+
let exp: Vec<_> = map.range(..5).map(|(k, v)| (*k, *v)).collect();
39+
assert_same(got, exp, "..5");
40+
41+
// Open-ended end
42+
let got: Vec<_> = tree.range(5..).map(|(k, v)| (*k, *v)).collect();
43+
let exp: Vec<_> = map.range(5..).map(|(k, v)| (*k, *v)).collect();
44+
assert_same(got, exp, "5..");
45+
46+
// Full range
47+
let got: Vec<_> = tree.range(..).map(|(k, v)| (*k, *v)).collect();
48+
let exp: Vec<_> = map.range(..).map(|(k, v)| (*k, *v)).collect();
49+
assert_same(got, exp, "..");
50+
51+
// Singleton ranges
52+
let got: Vec<_> = tree.range(4..=4).map(|(k, v)| (*k, *v)).collect();
53+
let exp: Vec<_> = map.range(4..=4).map(|(k, v)| (*k, *v)).collect();
54+
assert_same(got, exp, "4..=4");
55+
56+
// Empty by construction
57+
let got: Vec<_> = tree.range(4..4).map(|(k, v)| (*k, *v)).collect();
58+
let exp: Vec<_> = map.range(4..4).map(|(k, v)| (*k, *v)).collect();
59+
assert_same(got, exp, "4..4 (empty)");
60+
}
61+
}
62+
63+
#[test]
64+
fn test_range_differential_gaps_and_nonexistent_bounds() {
65+
// Data with gaps to test non-existing bound keys and cross-leaf traversal
66+
for &cap in &[4_usize, 5, 8] {
67+
let data = vec![0, 1, 2, 4, 7, 8, 10, 13, 14, 18];
68+
let (tree, map) = populate_maps(cap, &data);
69+
70+
let assert_same = |lhs: Vec<(i32, i32)>, rhs: Vec<(i32, i32)>, label: &str| {
71+
assert_eq!(lhs, rhs, "mismatch for range: {} (cap={})", label, cap);
72+
};
73+
74+
// Start/end on non-existent keys (between 2 and 4; between 8 and 10)
75+
let got: Vec<_> = tree.range(3..9).map(|(k, v)| (*k, *v)).collect();
76+
let exp: Vec<_> = map.range(3..9).map(|(k, v)| (*k, *v)).collect();
77+
assert_same(got, exp, "3..9");
78+
79+
// Inclusive upper bound non-existent
80+
let got: Vec<_> = tree.range(3..=9).map(|(k, v)| (*k, *v)).collect();
81+
let exp: Vec<_> = map.range(3..=9).map(|(k, v)| (*k, *v)).collect();
82+
assert_same(got, exp, "3..=9");
83+
84+
// Exclusive lower bound non-existent
85+
let got: Vec<_> = tree.range(3..=4).map(|(k, v)| (*k, *v)).collect();
86+
let exp: Vec<_> = map.range(3..=4).map(|(k, v)| (*k, *v)).collect();
87+
assert_same(got, exp, "3..=4");
88+
89+
// Entirely out-of-range
90+
let got: Vec<_> = tree.range(100..200).map(|(k, v)| (*k, *v)).collect();
91+
let exp: Vec<_> = map.range(100..200).map(|(k, v)| (*k, *v)).collect();
92+
assert_same(got, exp, "100..200 (empty)");
93+
94+
// Negative lower bound below min
95+
let got: Vec<_> = tree.range(-5..3).map(|(k, v)| (*k, *v)).collect();
96+
let exp: Vec<_> = map.range(-5..3).map(|(k, v)| (*k, *v)).collect();
97+
assert_same(got, exp, "-5..3");
98+
99+
// Intentionally avoid inverted ranges: std::BTreeMap panics for start > end
100+
}
101+
}

0 commit comments

Comments
 (0)