/// Extends this store with items from an iterator. /// /// It uses a two-pass (sort + dedup) approach to avoid any potential quadratic costs. /// /// The asymptotic worst case complexity is O((n + m) log(n + m)), where `n` /// is the number of elements already in `self` and `m` is the number of elements /// in the iterator. The best case complexity is O(m), when the input iterator is /// already sorted, keys aren't duplicated and all keys sort after the existing ones. #[inline] fn lm_extend<I>(&mutself, iter: I) where
I: IntoIterator<Item = (K, V)>,
K: Ord,
{ // First N elements in self that are already sorted and not duplicated. letmut sorted_len = self.len(); // Use Vec::extend as it has a specialized code for slice and trusted-len iterators. self.extend(iter); // `sorted_len` is the length of the sorted run before extension // window slice `w` is guaranteed to have a length of 2. #[allow(clippy::indexing_slicing)]
{ // Count new elements that are sorted and non-duplicated. // Starting from the end of the existing sorted run, if any. // Thus, start the slice at sorted_len.saturating_sub(1).
sorted_len += self[sorted_len.saturating_sub(1)..]
.windows(2)
.take_while(|w| w[0].0 < w[1].0)
.count();
} // `windows(2)` only yields `slice len - 1` times, or none if the slice is empty. // In other words, the first extended element of the slice won't be counted as sorted // if self was initially empty (sorted_len == 0). We adjust this by adding 1 if the // original slice was empty but became not empty after extend.
sorted_len += (sorted_len == 0 && !self.is_empty()) as usize;
// If everything was in order, we're done if sorted_len >= self.len() { return;
}
// Use stable sort to keep relative order of duplicates. self.sort_by(|a, b| a.0.cmp(&b.0)); // Deduplicate by keeping the last element of the run in the first slice. let (dedup, _merged_dup) = partition_dedup_by(self);
sorted_len = dedup.len(); self.truncate(sorted_len);
}
}
/// Moves all but the _last_ of consecutive elements to the end of the slice satisfying /// equality on K. /// /// Returns two slices. The first contains no consecutive repeated elements. /// The second contains all the duplicates in no specified order. /// /// This is based on std::slice::partition_dedup_by (currently unstable) but retains the /// _last_ element of the duplicate run in the first slice (instead of first). #[inline] #[allow(clippy::type_complexity)] fn partition_dedup_by<K: Eq, V>(v: &mut [(K, V)]) -> (&mut [(K, V)], &mut [(K, V)]) { // Although we have a mutable reference to `self`, we cannot make // *arbitrary* changes. The comparison could panic, so we // must ensure that the slice is in a valid state at all times. // // The way that we handle this is by using swaps; we iterate // over all the elements, swapping as we go so that at the end // the elements we wish to keep are in the front, and those we // wish to reject are at the back. We can then split the slice. // This operation is still `O(n)`. // // Example: // Assume (K, V) is (char, u8): // // We start in this state, where `r` represents "next // read" and `w` represents "next_write". // // r // | a,0 | b,0 | b,1 | c,0 | d,0 | d,1 | // w // // Comparing self[r] against self[w-1], this is not a duplicate, so // we swap self[r] and self[w] (no effect as r==w) and then increment both // r and w, leaving us with: // // r // | a,0 | b,0 | b,1 | c,0 | d,0 | d,0 | // w // // Comparing self[r] against self[w-1], this value is a duplicate, // we swap self[r] and self[w-1] and then increment `r`: // // r // | a,0 | b,1 | b,0 | c,0 | d,0 | d,1 | // w // // Comparing self[r] against self[w-1], this is not a duplicate, // so swap self[r] and self[w] and advance r and w: // // r // | a,0 | b,1 | c,0 | b,0 | d,0 | d,1 | // w // // Comparing self[r] against self[w-1], this is not a duplicate, // so swap self[r] and self[w] and advance r and w: // // r // | a,0 | b,1 | c,0 | d,0 | b,0 | d,1 | // w // // Comparing self[r] against self[w-1], this value is a duplicate, // we swap self[r] and self[w-1] and then increment `r`: // r // | a,0 | b,1 | c,0 | d,1 | b,0 | d,0 | // w // // End of slice, as r > len. Split at w.
whilelet Some((before_read, [read, ..])) = v.split_at_mut_checked(read_idx) { // First, `read_idx >= write_idx` is always true as `read_idx` is always incremented // whereas `write_idx` is only incremented when a distinct element is found. // Second, before_read is always at least 1 length due to read_idx being initialized to 1. // Thus it is safe to index before_read with `write_idx - 1`. #[allow(clippy::indexing_slicing)] let prev_write = &mut before_read[write_idx - 1]; if read.0 == prev_write.0 {
core::mem::swap(read, prev_write);
} else { // Equivalent to checking if write_idx == read_idx iflet Some(write) = before_read.get_mut(write_idx) {
core::mem::swap(read, write);
}
write_idx += 1;
}
read_idx += 1;
}
v.split_at_mut(write_idx)
}
impl<K: Ord, V> StoreFromIterable<K, V> for Vec<(K, V)> { fn lm_sort_from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self { letmut v = Self::new();
v.lm_extend(iter);
v
}
}
impl<'a, K: 'a, V: 'a> StoreIterable<'a, K, V> for Vec<(K, V)> { type KeyValueIter = core::iter::Map<core::slice::Iter<'a, (K, V)>, MapF<K, V>>;
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.