File tree Expand file tree Collapse file tree 3 files changed +48
-0
lines changed Expand file tree Collapse file tree 3 files changed +48
-0
lines changed Original file line number Diff line number Diff line change @@ -215,6 +215,8 @@ pub enum Object {
215
215
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
216
216
pub struct TreeRef < ' a > {
217
217
/// 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.
218
220
#[ cfg_attr( feature = "serde" , serde( borrow) ) ]
219
221
pub entries : Vec < tree:: EntryRef < ' a > > ,
220
222
}
@@ -231,6 +233,8 @@ pub struct TreeRefIter<'a> {
231
233
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
232
234
pub struct Tree {
233
235
/// 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.
234
238
pub entries : Vec < tree:: Entry > ,
235
239
}
236
240
Original file line number Diff line number Diff line change
1
+ use bstr:: BStr ;
1
2
use std:: convert:: TryFrom ;
2
3
3
4
use nom:: error:: ParseError ;
@@ -17,6 +18,27 @@ impl<'a> TreeRef<'a> {
17
18
decode:: tree ( data) . map ( |( _, t) | t) . map_err ( crate :: decode:: Error :: from)
18
19
}
19
20
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
+
20
42
/// Create an instance of the empty tree.
21
43
///
22
44
/// It's particularly useful as static part of a program.
Original file line number Diff line number Diff line change @@ -143,6 +143,28 @@ mod entries {
143
143
144
144
tree. entries . sort ( ) ;
145
145
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
+ ) ;
146
168
147
169
let mut tree: Tree = tree. into ( ) ;
148
170
let expected = tree. entries . clone ( ) ;
You can’t perform that action at this time.
0 commit comments