Skip to content

Commit 7734736

Browse files
committed
Merge branch 'improvements-for-crates-index'
2 parents 2fc66b5 + 424d347 commit 7734736

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

gix-object/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ pub enum Object {
215215
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
216216
pub struct TreeRef<'a> {
217217
/// The directories and files contained in this tree.
218+
///
219+
/// Beware that the sort order isn't *quite* by name, so one may bisect only with a [`tree::EntryRef`] to handle ordering correctly.
218220
#[cfg_attr(feature = "serde", serde(borrow))]
219221
pub entries: Vec<tree::EntryRef<'a>>,
220222
}
@@ -231,6 +233,8 @@ pub struct TreeRefIter<'a> {
231233
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
232234
pub struct Tree {
233235
/// The directories and files contained in this tree. They must be and remain sorted by [`filename`][tree::Entry::filename].
236+
///
237+
/// Beware that the sort order isn't *quite* by name, so one may bisect only with a [`tree::Entry`] to handle ordering correctly.
234238
pub entries: Vec<tree::Entry>,
235239
}
236240

gix-object/src/tree/ref_iter.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bstr::BStr;
12
use std::convert::TryFrom;
23

34
use nom::error::ParseError;
@@ -17,6 +18,27 @@ impl<'a> TreeRef<'a> {
1718
decode::tree(data).map(|(_, t)| t).map_err(crate::decode::Error::from)
1819
}
1920

21+
/// Find an entry named `name` knowing if the entry is a directory or not, using a binary search.
22+
///
23+
/// Note that it's impossible to binary search by name alone as the sort order is special.
24+
pub fn bisect_entry(&self, name: &BStr, is_dir: bool) -> Option<EntryRef<'a>> {
25+
static NULL_HASH: gix_hash::ObjectId = gix_hash::Kind::shortest().null();
26+
27+
let search = EntryRef {
28+
mode: if is_dir {
29+
tree::EntryMode::Tree
30+
} else {
31+
tree::EntryMode::Blob
32+
},
33+
filename: name,
34+
oid: &NULL_HASH,
35+
};
36+
self.entries
37+
.binary_search_by(|e| e.cmp(&search))
38+
.ok()
39+
.map(|idx| self.entries[idx])
40+
}
41+
2042
/// Create an instance of the empty tree.
2143
///
2244
/// It's particularly useful as static part of a program.

gix-object/tests/tree/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,28 @@ mod entries {
143143

144144
tree.entries.sort();
145145
assert_eq!(tree.entries, expected);
146+
let mut failures_when_searching_by_name = 0;
147+
for entry in expected {
148+
assert!(
149+
tree.entries.binary_search_by(|e| e.cmp(&entry)).is_ok(),
150+
"ordering works with binary search"
151+
);
152+
failures_when_searching_by_name += usize::from(
153+
tree.entries
154+
.binary_search_by(|e| e.filename.cmp(entry.filename))
155+
.is_err(),
156+
);
157+
assert_eq!(
158+
tree.bisect_entry(entry.filename, entry.mode.is_tree())
159+
.expect("entry is present"),
160+
entry
161+
)
162+
}
163+
164+
assert_eq!(
165+
failures_when_searching_by_name, 2,
166+
"it's not possible to do a binary search by name alone"
167+
);
146168

147169
let mut tree: Tree = tree.into();
148170
let expected = tree.entries.clone();

0 commit comments

Comments
 (0)