Show More
@@ -7,6 +7,9 b'' | |||||
7 |
|
7 | |||
8 | //! Structs and types for matching files and directories. |
|
8 | //! Structs and types for matching files and directories. | |
9 |
|
9 | |||
|
10 | use format_bytes::format_bytes; | |||
|
11 | use once_cell::sync::OnceCell; | |||
|
12 | ||||
10 | use crate::{ |
|
13 | use crate::{ | |
11 | dirstate::dirs_multiset::DirsChildrenMultiset, |
|
14 | dirstate::dirs_multiset::DirsChildrenMultiset, | |
12 | filepatterns::{ |
|
15 | filepatterns::{ | |
@@ -23,11 +26,11 b' use crate::{' | |||||
23 |
|
26 | |||
24 | use crate::dirstate::status::IgnoreFnType; |
|
27 | use crate::dirstate::status::IgnoreFnType; | |
25 | use crate::filepatterns::normalize_path_bytes; |
|
28 | use crate::filepatterns::normalize_path_bytes; | |
26 | use std::borrow::ToOwned; |
|
|||
27 | use std::collections::HashSet; |
|
29 | use std::collections::HashSet; | |
28 | use std::fmt::{Display, Error, Formatter}; |
|
30 | use std::fmt::{Display, Error, Formatter}; | |
29 | use std::ops::Deref; |
|
31 | use std::ops::Deref; | |
30 | use std::path::{Path, PathBuf}; |
|
32 | use std::path::{Path, PathBuf}; | |
|
33 | use std::{borrow::ToOwned, collections::BTreeSet}; | |||
31 |
|
34 | |||
32 | #[derive(Debug, PartialEq)] |
|
35 | #[derive(Debug, PartialEq)] | |
33 | pub enum VisitChildrenSet { |
|
36 | pub enum VisitChildrenSet { | |
@@ -173,6 +176,7 b' impl Matcher for NeverMatcher {' | |||||
173 | pub struct FileMatcher { |
|
176 | pub struct FileMatcher { | |
174 | files: HashSet<HgPathBuf>, |
|
177 | files: HashSet<HgPathBuf>, | |
175 | dirs: DirsMultiset, |
|
178 | dirs: DirsMultiset, | |
|
179 | sorted_visitchildrenset_candidates: OnceCell<BTreeSet<HgPathBuf>>, | |||
176 | } |
|
180 | } | |
177 |
|
181 | |||
178 | impl FileMatcher { |
|
182 | impl FileMatcher { | |
@@ -181,6 +185,7 b' impl FileMatcher {' | |||||
181 | Ok(Self { |
|
185 | Ok(Self { | |
182 | files: HashSet::from_iter(files.into_iter()), |
|
186 | files: HashSet::from_iter(files.into_iter()), | |
183 | dirs, |
|
187 | dirs, | |
|
188 | sorted_visitchildrenset_candidates: OnceCell::new(), | |||
184 | }) |
|
189 | }) | |
185 | } |
|
190 | } | |
186 | fn inner_matches(&self, filename: &HgPath) -> bool { |
|
191 | fn inner_matches(&self, filename: &HgPath) -> bool { | |
@@ -199,30 +204,34 b' impl Matcher for FileMatcher {' | |||||
199 | self.inner_matches(filename) |
|
204 | self.inner_matches(filename) | |
200 | } |
|
205 | } | |
201 | fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet { |
|
206 | fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet { | |
202 |
if self.files.is_empty() || !self.dirs.contains( |
|
207 | if self.files.is_empty() || !self.dirs.contains(directory) { | |
203 | return VisitChildrenSet::Empty; |
|
208 | return VisitChildrenSet::Empty; | |
204 | } |
|
209 | } | |
205 | let mut candidates: HashSet<HgPathBuf> = |
|
|||
206 | self.dirs.iter().cloned().collect(); |
|
|||
207 |
|
210 | |||
208 | candidates.extend(self.files.iter().cloned()); |
|
211 | let compute_candidates = || -> BTreeSet<HgPathBuf> { | |
209 | candidates.remove(HgPath::new(b"")); |
|
212 | let mut candidates: BTreeSet<HgPathBuf> = | |
210 |
|
213 | self.dirs.iter().cloned().collect(); | ||
211 | if !directory.as_ref().is_empty() { |
|
214 | candidates.extend(self.files.iter().cloned()); | |
212 | let directory = [directory.as_ref().as_bytes(), b"/"].concat(); |
|
215 | candidates.remove(HgPath::new(b"")); | |
213 |
candidates |
|
216 | candidates | |
214 | .iter() |
|
217 | }; | |
215 | .filter_map(|c| { |
|
218 | let candidates = | |
216 | if c.as_bytes().starts_with(&directory) { |
|
219 | if directory.as_ref().is_empty() { | |
217 | Some(HgPathBuf::from_bytes( |
|
220 | compute_candidates() | |
218 | &c.as_bytes()[directory.len()..], |
|
221 | } else { | |
219 | )) |
|
222 | let sorted_candidates = self | |
220 | } else { |
|
223 | .sorted_visitchildrenset_candidates | |
221 | None |
|
224 | .get_or_init(compute_candidates); | |
222 | } |
|
225 | let directory_bytes = directory.as_ref().as_bytes(); | |
223 | }) |
|
226 | let start: HgPathBuf = | |
224 | .collect(); |
|
227 | format_bytes!(b"{}/", directory_bytes).into(); | |
225 | } |
|
228 | let start_len = start.len(); | |
|
229 | // `0` sorts after `/` | |||
|
230 | let end = format_bytes!(b"{}0", directory_bytes).into(); | |||
|
231 | BTreeSet::from_iter(sorted_candidates.range(start..end).map( | |||
|
232 | |c| HgPathBuf::from_bytes(&c.as_bytes()[start_len..]), | |||
|
233 | )) | |||
|
234 | }; | |||
226 |
|
235 | |||
227 | // `self.dirs` includes all of the directories, recursively, so if |
|
236 | // `self.dirs` includes all of the directories, recursively, so if | |
228 | // we're attempting to match 'foo/bar/baz.txt', it'll have '', 'foo', |
|
237 | // we're attempting to match 'foo/bar/baz.txt', it'll have '', 'foo', |
General Comments 0
You need to be logged in to leave comments.
Login now