use std::collections::hash_map::Entry; use std::collections::HashMap; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::ops::{Add, Index, Range};
/// Utility function to check if a range is empty that works on older rust versions #[inline(always)] #[allow(clippy::neg_cmp_op_on_partial_ord)] pubfn is_empty_range<T: PartialOrd<T>>(range: &Range<T>) -> bool {
!(range.start < range.end)
}
/// Represents an item in the vector returned by [`unique`]. /// /// It compares like the underlying item does it was created from but /// carries the index it was originally created from. pubstruct UniqueItem<'a, Idx: ?Sized> {
lookup: &'a Idx,
index: usize,
}
impl<Idx: ?Sized> UniqueItem<'_, Idx> where
Idx: Index<usize>,
{ /// Returns the value. #[inline(always)] pubfn value(&self) -> &Idx::Output {
&self.lookup[self.index]
}
/// Returns the original index. #[inline(always)] pubfn original_index(&self) -> usize { self.index
}
}
/// Returns only unique items in the sequence as vector. /// /// Each item is wrapped in a [`UniqueItem`] so that both the value and the /// index can be extracted. pubfn unique<Idx>(lookup: &Idx, range: Range<usize>) -> Vec<UniqueItem<Idx>> where
Idx: Index<usize> + ?Sized,
Idx::Output: Hash + Eq,
{ letmut by_item = HashMap::new(); for index in range { match by_item.entry(&lookup[index]) {
Entry::Vacant(entry) => {
entry.insert(Some(index));
}
Entry::Occupied(mut entry) => { let entry = entry.get_mut(); if entry.is_some() {
*entry = None
}
}
}
} letmut rv = by_item
.into_iter()
.filter_map(|(_, x)| x)
.map(|index| UniqueItem { lookup, index })
.collect::<Vec<_>>();
rv.sort_by_key(|a| a.original_index());
rv
}
/// Given two lookups and ranges calculates the length of the common prefix. pubfn common_prefix_len<Old, New>(
old: &Old,
old_range: Range<usize>,
new: &New,
new_range: Range<usize>,
) -> usize where
Old: Index<usize> + ?Sized,
New: Index<usize> + ?Sized,
New::Output: PartialEq<Old::Output>,
{ if is_empty_range(&old_range) || is_empty_range(&new_range) { return0;
}
new_range
.zip(old_range)
.take_while( #[inline(always)]
|x| new[x.0] == old[x.1],
)
.count()
}
/// Given two lookups and ranges calculates the length of common suffix. pubfn common_suffix_len<Old, New>(
old: &Old,
old_range: Range<usize>,
new: &New,
new_range: Range<usize>,
) -> usize where
Old: Index<usize> + ?Sized,
New: Index<usize> + ?Sized,
New::Output: PartialEq<Old::Output>,
{ if is_empty_range(&old_range) || is_empty_range(&new_range) { return0;
}
new_range
.rev()
.zip(old_range.rev())
.take_while( #[inline(always)]
|x| new[x.0] == old[x.1],
)
.count()
}
/// A utility struct to convert distinct items to unique integers. /// /// This can be helpful on larger inputs to speed up the comparisons /// performed by doing a first pass where the data set gets reduced /// to (small) integers. /// /// The idea is that instead of passing two sequences to a diffling algorithm /// you first pass it via [`IdentifyDistinct`]: /// /// ```rust /// use similar::capture_diff; /// use similar::algorithms::{Algorithm, IdentifyDistinct}; /// /// let old = &["foo", "bar", "baz"][..]; /// let new = &["foo", "blah", "baz"][..]; /// let h = IdentifyDistinct::<u32>::new(old, 0..old.len(), new, 0..new.len()); /// let ops = capture_diff( /// Algorithm::Myers, /// h.old_lookup(), /// h.old_range(), /// h.new_lookup(), /// h.new_range(), /// ); /// ``` /// /// The indexes are the same as with the passed source ranges. pubstruct IdentifyDistinct<Int> {
old: OffsetLookup<Int>,
new: OffsetLookup<Int>,
}
letmut map = HashMap::new(); letmut old_seq = Vec::new(); letmut new_seq = Vec::new(); letmut next_id = Int::default(); let step = Int::from(1); let old_start = old_range.start; let new_start = new_range.start;
for idx in old_range { let item = Key::Old(&old[idx]); let id = match map.entry(item) {
Entry::Occupied(o) => *o.get(),
Entry::Vacant(v) => { let id = next_id;
next_id = next_id + step;
*v.insert(id)
}
};
old_seq.push(id);
}
for idx in new_range { let item = Key::New(&new[idx]); let id = match map.entry(item) {
Entry::Occupied(o) => *o.get(),
Entry::Vacant(v) => { let id = next_id;
next_id = next_id + step;
*v.insert(id)
}
};
new_seq.push(id);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.