Skip to content

Commit 6892999

Browse files
committed
feat: search::Outcome::copy_into() can now copy values from a previous search.
This allows to perform a search once, finding all attributes, and then copy the results over to another outcome, typically one with selected attributes.
1 parent df83d74 commit 6892999

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

gix-attributes/src/search/outcome.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ impl Outcome {
7373
self.selected.iter().filter(|(_name, id)| id.is_some()).count()
7474
});
7575
}
76+
77+
/// A performance optimization which allows results from this instance to be efficiently copied over to `dest`.
78+
/// For this to work, `collection` must be the one used to initialize our state, and `dest` should not have been initialized
79+
/// with any meaningful collection initially, i.e. be empty the first time this method is called.
80+
///
81+
/// Note that it's safe to call it multiple times, so that it can be called after this instance was used to store a search result.
82+
pub fn copy_into(&self, collection: &MetadataCollection, dest: &mut Self) {
83+
dest.initialize(collection);
84+
dest.matches_by_id = self.matches_by_id.clone();
85+
if dest.patterns.len() != self.patterns.len() {
86+
dest.patterns = self.patterns.clone();
87+
}
88+
if dest.assignments.len() != self.assignments.len() {
89+
dest.assignments = self.assignments.clone();
90+
}
91+
if dest.source_paths.len() != self.source_paths.len() {
92+
dest.source_paths = self.source_paths.clone();
93+
}
94+
dest.remaining = self.remaining;
95+
}
7696
}
7797

7898
/// Access

gix-attributes/src/search/refmap.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ impl<T> RefMap<T>
2121
where
2222
T: Hash + Clone,
2323
{
24+
pub(crate) fn len(&self) -> usize {
25+
self.0.len()
26+
}
2427
pub(crate) fn insert(&mut self, value: &T) -> RefMapKey {
2528
let mut s = DefaultHasher::new();
2629
value.hash(&mut s);

gix-attributes/tests/search/mod.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ fn all_attributes_are_listed_in_declaration_order() -> crate::Result {
141141
true, /* use macros */
142142
)?;
143143

144-
let mut out = gix_attributes::search::Outcome::default();
144+
let mut out = Outcome::default();
145145
out.initialize(&collection);
146+
let mut alt = Outcome::default();
147+
alt.initialize(&collection);
146148

147149
let mut orders = collection
148150
.iter()
@@ -206,10 +208,13 @@ fn all_attributes_are_listed_in_declaration_order() -> crate::Result {
206208
assert_references(&out);
207209
let actual: Vec<_> = out.iter().map(|m| m.assignment).collect();
208210
assert_eq!(
209-
by_name(actual),
211+
by_name(actual.clone()),
210212
by_name(expected),
211213
"{rela_path}: the order of everything matches perfectly"
212214
);
215+
out.copy_into(&collection, &mut alt);
216+
let alt_actual: Vec<_> = alt.iter().map(|m| m.assignment).collect();
217+
assert_eq!(alt_actual, actual);
213218
}
214219
assert_eq!(
215220
out.iter().count(),
@@ -234,8 +239,10 @@ fn given_attributes_are_made_available_in_given_order() -> crate::Result {
234239
true, /* use macros */
235240
)?;
236241

237-
let mut out = gix_attributes::search::Outcome::default();
242+
let mut out = Outcome::default();
238243
out.initialize_with_selection(&collection, ["my-binary", "recursive", "unspecified"]);
244+
let mut alt = Outcome::default();
245+
alt.initialize_with_selection(&collection, ["my-binary", "unspecified"]);
239246

240247
for (rela_path, expected) in (baseline::Expectations { lines: input.lines() }) {
241248
out.reset();
@@ -246,6 +253,10 @@ fn given_attributes_are_made_available_in_given_order() -> crate::Result {
246253
actual, expected,
247254
"{rela_path}: the order of everything matches perfectly"
248255
);
256+
out.copy_into(&collection, &mut alt);
257+
let alt_actual: Vec<_> = alt.iter_selected().map(|m| m.assignment).collect();
258+
assert_eq!(alt_actual[0], actual[0]);
259+
assert_eq!(alt_actual[1], actual[2]);
249260
}
250261
assert_eq!(
251262
out.iter().count(),
@@ -255,6 +266,15 @@ fn given_attributes_are_made_available_in_given_order() -> crate::Result {
255266
Ok(())
256267
}
257268

269+
#[test]
270+
fn size_of_outcome() {
271+
assert_eq!(
272+
std::mem::size_of::<Outcome>(),
273+
904,
274+
"it's quite big, shouldn't change without us noticing"
275+
)
276+
}
277+
258278
fn by_name(assignments: Vec<AssignmentRef>) -> BTreeMap<NameRef, StateRef> {
259279
assignments.into_iter().map(|a| (a.name, a.state)).collect()
260280
}

0 commit comments

Comments
 (0)