RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.
This commit is contained in:
227
zeroidc/vendor/itertools/src/kmerge_impl.rs
vendored
Normal file
227
zeroidc/vendor/itertools/src/kmerge_impl.rs
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
use crate::size_hint;
|
||||
use crate::Itertools;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use std::iter::FusedIterator;
|
||||
use std::mem::replace;
|
||||
use std::fmt;
|
||||
|
||||
/// Head element and Tail iterator pair
|
||||
///
|
||||
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
|
||||
/// first items (which are guaranteed to exist).
|
||||
///
|
||||
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
|
||||
/// `KMerge` into a min-heap.
|
||||
#[derive(Debug)]
|
||||
struct HeadTail<I>
|
||||
where I: Iterator
|
||||
{
|
||||
head: I::Item,
|
||||
tail: I,
|
||||
}
|
||||
|
||||
impl<I> HeadTail<I>
|
||||
where I: Iterator
|
||||
{
|
||||
/// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
|
||||
fn new(mut it: I) -> Option<HeadTail<I>> {
|
||||
let head = it.next();
|
||||
head.map(|h| {
|
||||
HeadTail {
|
||||
head: h,
|
||||
tail: it,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the next element and update `head`, returning the old head in `Some`.
|
||||
///
|
||||
/// Returns `None` when the tail is exhausted (only `head` then remains).
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
if let Some(next) = self.tail.next() {
|
||||
Some(replace(&mut self.head, next))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Hints at the size of the sequence, same as the `Iterator` method.
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
size_hint::add_scalar(self.tail.size_hint(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Clone for HeadTail<I>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone
|
||||
{
|
||||
clone_fields!(head, tail);
|
||||
}
|
||||
|
||||
/// Make `data` a heap (min-heap w.r.t the sorting).
|
||||
fn heapify<T, S>(data: &mut [T], mut less_than: S)
|
||||
where S: FnMut(&T, &T) -> bool
|
||||
{
|
||||
for i in (0..data.len() / 2).rev() {
|
||||
sift_down(data, i, &mut less_than);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
|
||||
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
|
||||
where S: FnMut(&T, &T) -> bool
|
||||
{
|
||||
debug_assert!(index <= heap.len());
|
||||
let mut pos = index;
|
||||
let mut child = 2 * pos + 1;
|
||||
// Require the right child to be present
|
||||
// This allows to find the index of the smallest child without a branch
|
||||
// that wouldn't be predicted if present
|
||||
while child + 1 < heap.len() {
|
||||
// pick the smaller of the two children
|
||||
// use aritmethic to avoid an unpredictable branch
|
||||
child += less_than(&heap[child+1], &heap[child]) as usize;
|
||||
|
||||
// sift down is done if we are already in order
|
||||
if !less_than(&heap[child], &heap[pos]) {
|
||||
return;
|
||||
}
|
||||
heap.swap(pos, child);
|
||||
pos = child;
|
||||
child = 2 * pos + 1;
|
||||
}
|
||||
// Check if the last (left) child was an only child
|
||||
// if it is then it has to be compared with the parent
|
||||
if child + 1 == heap.len() && less_than(&heap[child], &heap[pos]) {
|
||||
heap.swap(pos, child);
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
|
||||
/// If all base iterators are sorted (ascending), the result is sorted.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
///
|
||||
/// See [`.kmerge()`](crate::Itertools::kmerge) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub type KMerge<I> = KMergeBy<I, KMergeByLt>;
|
||||
|
||||
pub trait KMergePredicate<T> {
|
||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct KMergeByLt;
|
||||
|
||||
impl<T: PartialOrd> KMergePredicate<T> for KMergeByLt {
|
||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
|
||||
a < b
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
|
||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
|
||||
self(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an iterator that merges elements of the contained iterators using
|
||||
/// the ordering function.
|
||||
///
|
||||
/// Equivalent to `iterable.into_iter().kmerge()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::kmerge;
|
||||
///
|
||||
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
|
||||
where I: IntoIterator,
|
||||
I::Item: IntoIterator,
|
||||
<<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
|
||||
{
|
||||
kmerge_by(iterable, KMergeByLt)
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merges an abitrary number of base iterators
|
||||
/// according to an ordering function.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
///
|
||||
/// See [`.kmerge_by()`](crate::Itertools::kmerge_by) for more
|
||||
/// information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct KMergeBy<I, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
heap: Vec<HeadTail<I>>,
|
||||
less_than: F,
|
||||
}
|
||||
|
||||
impl<I, F> fmt::Debug for KMergeBy<I, F>
|
||||
where I: Iterator + fmt::Debug,
|
||||
I::Item: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(KMergeBy, heap);
|
||||
}
|
||||
|
||||
/// Create an iterator that merges elements of the contained iterators.
|
||||
///
|
||||
/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
|
||||
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
|
||||
-> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
|
||||
where I: IntoIterator,
|
||||
I::Item: IntoIterator,
|
||||
F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,
|
||||
{
|
||||
let iter = iterable.into_iter();
|
||||
let (lower, _) = iter.size_hint();
|
||||
let mut heap: Vec<_> = Vec::with_capacity(lower);
|
||||
heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
|
||||
heapify(&mut heap, |a, b| less_than.kmerge_pred(&a.head, &b.head));
|
||||
KMergeBy { heap, less_than }
|
||||
}
|
||||
|
||||
impl<I, F> Clone for KMergeBy<I, F>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
clone_fields!(heap, less_than);
|
||||
}
|
||||
|
||||
impl<I, F> Iterator for KMergeBy<I, F>
|
||||
where I: Iterator,
|
||||
F: KMergePredicate<I::Item>
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.heap.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let result = if let Some(next) = self.heap[0].next() {
|
||||
next
|
||||
} else {
|
||||
self.heap.swap_remove(0).head
|
||||
};
|
||||
let less_than = &mut self.less_than;
|
||||
sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head));
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.heap.iter()
|
||||
.map(|i| i.size_hint())
|
||||
.fold1(size_hint::add)
|
||||
.unwrap_or((0, Some(0)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, F> FusedIterator for KMergeBy<I, F>
|
||||
where I: Iterator,
|
||||
F: KMergePredicate<I::Item>
|
||||
{}
|
||||
Reference in New Issue
Block a user