|
1 | 1 | use std::cmp::Ordering; |
| 2 | +use std::ops::Range; |
2 | 3 |
|
3 | 4 | use bstr::{BStr, ByteSlice, ByteVec}; |
4 | 5 | use filetime::FileTime; |
@@ -223,6 +224,30 @@ impl State { |
223 | 224 | pub fn is_sparse(&self) -> bool { |
224 | 225 | self.is_sparse |
225 | 226 | } |
| 227 | + |
| 228 | + /// Return the range of entries that exactly match the given `path`, in all available stages, or `None` if no entry with such |
| 229 | + /// path exists. |
| 230 | + /// |
| 231 | + /// The range can be used to access the respective entries via [`entries()`](Self::entries()) or [`entries_mut()](Self::entries_mut()). |
| 232 | + pub fn entry_range(&self, path: &BStr) -> Option<Range<usize>> { |
| 233 | + let mut stage_at_index = 0; |
| 234 | + let idx = self |
| 235 | + .entries |
| 236 | + .binary_search_by(|e| { |
| 237 | + let res = e.path(self).cmp(path); |
| 238 | + if res.is_eq() { |
| 239 | + stage_at_index = e.stage(); |
| 240 | + } |
| 241 | + res |
| 242 | + }) |
| 243 | + .ok()?; |
| 244 | + |
| 245 | + let (start, end) = ( |
| 246 | + self.walk_entry_stages(path, idx, Ordering::Less).unwrap_or(idx), |
| 247 | + self.walk_entry_stages(path, idx, Ordering::Greater).unwrap_or(idx) + 1, |
| 248 | + ); |
| 249 | + Some(start..end) |
| 250 | + } |
226 | 251 | } |
227 | 252 |
|
228 | 253 | /// Mutation |
@@ -333,6 +358,25 @@ impl State { |
333 | 358 | .then_with(|| compare(a, b)) |
334 | 359 | }); |
335 | 360 | } |
| 361 | + |
| 362 | + /// Physically remove all entries for which `should_remove(idx, path, entry)` returns `true`, traversing them from first to last. |
| 363 | + /// |
| 364 | + /// Note that the memory used for the removed entries paths is not freed, as it's append-only. |
| 365 | + /// |
| 366 | + /// ### Performance |
| 367 | + /// |
| 368 | + /// To implement this operation typically, one would rather add [entry::Flags::REMOVE] to each entry to remove |
| 369 | + /// them when [writing the index](Self::write_to()). |
| 370 | + pub fn remove_entries(&mut self, mut should_remove: impl FnMut(usize, &BStr, &mut Entry) -> bool) { |
| 371 | + let mut index = 0; |
| 372 | + let paths = &self.path_backing; |
| 373 | + self.entries.retain_mut(|e| { |
| 374 | + let path = e.path_in(paths); |
| 375 | + let res = !should_remove(index, path, e); |
| 376 | + index += 1; |
| 377 | + res |
| 378 | + }); |
| 379 | + } |
336 | 380 | } |
337 | 381 |
|
338 | 382 | /// Extensions |
|
0 commit comments