#![cfg_attr(feature = "rayon", doc = "[`rayon::slice`]")]
#![cfg_attr(not(feature = "rayon"), doc = "`rayon::slice`")]
#![deny(
missing_docs,
rustdoc::broken_intra_doc_links,
rustdoc::missing_crate_level_docs
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(miri, feature(maybe_uninit_slice))]
#[inline(always)]
fn maybe_grow<R, F: FnOnce() -> R>(callback: F) -> R {
#[cfg(feature = "stacker")]
{
stacker::maybe_grow(32 * 1_024, 1_024 * 1_024, callback)
}
#[cfg(not(feature = "stacker"))]
{
callback()
}
}
mod heap_sort;
mod insertion_sort;
mod merge_sort;
mod partition;
mod partition_dedup;
mod quick_sort;
mod stable_sort;
#[cfg(feature = "rayon")]
mod par;
#[cfg(feature = "rayon")]
use par::{
merge_sort::par_merge_sort, partition::par_partition_at_indices, quick_sort::par_quick_sort,
};
#[cfg(feature = "alloc")]
use crate::stable_sort::stable_sort;
use crate::{
partition::{is_sorted, partition_at_index, partition_at_indices, reverse},
partition_dedup::partition_dedup,
quick_sort::quick_sort,
};
use core::cmp::Ordering::{self, Equal, Greater, Less};
use ndarray::{ArrayBase, ArrayViewMut1, Data, DataMut, Ix1};
pub use ndarray;
#[cfg_attr(feature = "rayon", doc = "[`rayon::slice`].")]
#[cfg_attr(not(feature = "rayon"), doc = "`rayon::slice`.")]
pub trait Slice1Ext<A, S>
where
S: Data<Elem = A>,
{
#[cfg(feature = "rayon")]
fn par_sort(&mut self)
where
A: Ord + Send,
S: DataMut;
#[cfg(feature = "rayon")]
fn par_sort_by<F>(&mut self, compare: F)
where
A: Send,
F: Fn(&A, &A) -> Ordering + Sync,
S: DataMut;
#[cfg(feature = "rayon")]
fn par_sort_by_key<K, F>(&mut self, f: F)
where
A: Send,
K: Ord,
F: Fn(&A) -> K + Sync,
S: DataMut;
#[cfg(feature = "rayon")]
fn par_sort_by_cached_key<K, F>(&mut self, f: F)
where
A: Send + Sync,
F: Fn(&A) -> K + Sync,
K: Ord + Send,
S: DataMut;
#[cfg(feature = "alloc")]
fn sort(&mut self)
where
A: Ord,
S: DataMut;
#[cfg(feature = "alloc")]
fn sort_by<F>(&mut self, compare: F)
where
F: FnMut(&A, &A) -> Ordering,
S: DataMut;
#[cfg_attr(
feature = "std",
doc = "\
For expensive key functions (e.g. functions that are not simple property accesses or
basic operations), [`sort_by_cached_key`](Slice1Ext::sort_by_cached_key) is likely to be
significantly faster, as it does not recompute element keys."
)]
#[cfg(feature = "alloc")]
fn sort_by_key<K, F>(&mut self, f: F)
where
K: Ord,
F: FnMut(&A) -> K,
S: DataMut;
#[cfg(feature = "std")]
fn sort_by_cached_key<K, F>(&mut self, f: F)
where
F: FnMut(&A) -> K,
K: Ord,
S: DataMut;
#[cfg(feature = "rayon")]
fn par_sort_unstable(&mut self)
where
A: Ord + Send,
S: DataMut;
#[cfg(feature = "rayon")]
fn par_sort_unstable_by<F>(&mut self, compare: F)
where
A: Send,
F: Fn(&A, &A) -> Ordering + Sync,
S: DataMut;
#[cfg(feature = "rayon")]
fn par_sort_unstable_by_key<K, F>(&mut self, f: F)
where
A: Send,
K: Ord,
F: Fn(&A) -> K + Sync,
S: DataMut;
fn sort_unstable(&mut self)
where
A: Ord,
S: DataMut;
fn sort_unstable_by<F>(&mut self, compare: F)
where
F: FnMut(&A, &A) -> Ordering,
S: DataMut;
fn sort_unstable_by_key<K, F>(&mut self, f: F)
where
K: Ord,
F: FnMut(&A) -> K,
S: DataMut;
#[must_use]
fn is_sorted(&self) -> bool
where
A: PartialOrd;
#[must_use]
fn is_sorted_by<F>(&self, compare: F) -> bool
where
F: FnMut(&A, &A) -> bool;
#[must_use]
fn is_sorted_by_key<F, K>(&self, f: F) -> bool
where
F: FnMut(&A) -> K,
K: PartialOrd;
#[cfg(feature = "rayon")]
fn par_select_many_nth_unstable<'a, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut Vec<&'a mut A>,
) where
A: Ord + Send,
S: DataMut,
S2: Data<Elem = usize> + Sync;
#[cfg(feature = "rayon")]
fn par_select_many_nth_unstable_by<'a, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut Vec<&'a mut A>,
compare: F,
) where
A: Send,
F: Fn(&A, &A) -> Ordering + Sync,
S: DataMut,
S2: Data<Elem = usize> + Sync;
#[cfg(feature = "rayon")]
fn par_select_many_nth_unstable_by_key<'a, K, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut Vec<&'a mut A>,
f: F,
) where
A: Send,
K: Ord,
F: Fn(&A) -> K + Sync,
S: DataMut,
S2: Data<Elem = usize> + Sync;
fn select_many_nth_unstable<'a, E, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut E,
) where
A: Ord + 'a,
E: Extend<(usize, &'a mut A)>,
S: DataMut,
S2: Data<Elem = usize>;
fn select_many_nth_unstable_by<'a, E, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut E,
compare: F,
) where
A: 'a,
E: Extend<(usize, &'a mut A)>,
F: FnMut(&A, &A) -> Ordering,
S: DataMut,
S2: Data<Elem = usize>;
fn select_many_nth_unstable_by_key<'a, E, K, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut E,
f: F,
) where
A: 'a,
E: Extend<(usize, &'a mut A)>,
K: Ord,
F: FnMut(&A) -> K,
S: DataMut,
S2: Data<Elem = usize>;
#[must_use]
fn select_nth_unstable(
&mut self,
index: usize,
) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
where
A: Ord,
S: DataMut;
#[must_use]
fn select_nth_unstable_by<F>(
&mut self,
index: usize,
compare: F,
) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
where
F: FnMut(&A, &A) -> Ordering,
S: DataMut;
#[must_use]
fn select_nth_unstable_by_key<K, F>(
&mut self,
index: usize,
f: F,
) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
where
K: Ord,
F: FnMut(&A) -> K,
S: DataMut;
#[must_use]
fn partition_point<P>(&self, pred: P) -> usize
where
P: FnMut(&A) -> bool;
#[must_use]
fn contains(&self, x: &A) -> bool
where
A: PartialEq;
fn binary_search(&self, x: &A) -> Result<usize, usize>
where
A: Ord;
fn binary_search_by<F>(&self, f: F) -> Result<usize, usize>
where
F: FnMut(&A) -> Ordering;
#[cfg_attr(
feature = "alloc",
doc = "\
Assumes that the array is sorted by the key, for instance with
[`sort_by_key`] using the same key extraction function."
)]
#[cfg_attr(
feature = "alloc",
doc = "\
[`sort_by_key`]: Slice1Ext::sort_by_key"
)]
fn binary_search_by_key<B, F>(&self, b: &B, f: F) -> Result<usize, usize>
where
F: FnMut(&A) -> B,
B: Ord;
fn partition_dedup(&mut self) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
where
A: PartialEq,
S: DataMut;
fn partition_dedup_by<F>(
&mut self,
same_bucket: F,
) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
where
F: FnMut(&mut A, &mut A) -> bool,
S: DataMut;
fn partition_dedup_by_key<K, F>(
&mut self,
key: F,
) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
where
F: FnMut(&mut A) -> K,
K: PartialEq,
S: DataMut;
fn reverse(&mut self)
where
S: DataMut;
}
impl<A, S> Slice1Ext<A, S> for ArrayBase<S, Ix1>
where
S: Data<Elem = A>,
{
#[cfg(feature = "rayon")]
#[inline]
fn par_sort(&mut self)
where
A: Ord + Send,
S: DataMut,
{
par_merge_sort(self.view_mut(), A::lt);
}
#[cfg(feature = "rayon")]
#[inline]
fn par_sort_by<F>(&mut self, compare: F)
where
A: Send,
F: Fn(&A, &A) -> Ordering + Sync,
S: DataMut,
{
par_merge_sort(self.view_mut(), |a: &A, b: &A| compare(a, b) == Less)
}
#[cfg(feature = "rayon")]
#[inline]
fn par_sort_by_key<K, F>(&mut self, f: F)
where
A: Send,
K: Ord,
F: Fn(&A) -> K + Sync,
S: DataMut,
{
par_merge_sort(self.view_mut(), |a: &A, b: &A| f(a).lt(&f(b)))
}
#[cfg(feature = "rayon")]
fn par_sort_by_cached_key<K, F>(&mut self, f: F)
where
A: Send + Sync,
F: Fn(&A) -> K + Sync,
K: Ord + Send,
S: DataMut,
{
use core::mem;
use rayon::{
iter::{ParallelBridge, ParallelIterator},
slice::ParallelSliceMut,
};
let len = self.len();
if len < 2 {
return;
}
macro_rules! sort_by_key {
($t:ty) => {{
let mut indices: Vec<_> = self
.iter()
.enumerate()
.par_bridge()
.map(|(i, x)| (f(&*x), i as $t))
.collect();
indices.par_sort_unstable();
for i in 0..len {
let mut index = indices[i].1;
while (index as usize) < i {
index = indices[index as usize].1;
}
indices[i].1 = index;
self.swap(i, index as usize);
}
}};
}
let sz_u8 = mem::size_of::<(K, u8)>();
let sz_u16 = mem::size_of::<(K, u16)>();
let sz_u32 = mem::size_of::<(K, u32)>();
let sz_usize = mem::size_of::<(K, usize)>();
if sz_u8 < sz_u16 && len <= (u8::MAX as usize) {
return sort_by_key!(u8);
}
if sz_u16 < sz_u32 && len <= (u16::MAX as usize) {
return sort_by_key!(u16);
}
if sz_u32 < sz_usize && len <= (u32::MAX as usize) {
return sort_by_key!(u32);
}
sort_by_key!(usize)
}
#[cfg(feature = "alloc")]
#[inline]
fn sort(&mut self)
where
A: Ord,
S: DataMut,
{
stable_sort(self.view_mut(), A::lt);
}
#[cfg(feature = "alloc")]
#[inline]
fn sort_by<F>(&mut self, mut compare: F)
where
F: FnMut(&A, &A) -> Ordering,
S: DataMut,
{
stable_sort(self.view_mut(), &mut |a: &A, b: &A| compare(a, b) == Less)
}
#[cfg(feature = "alloc")]
#[inline]
fn sort_by_key<K, F>(&mut self, mut f: F)
where
K: Ord,
F: FnMut(&A) -> K,
S: DataMut,
{
stable_sort(self.view_mut(), &mut |a: &A, b: &A| f(a).lt(&f(b)))
}
#[cfg(feature = "std")]
fn sort_by_cached_key<K, F>(&mut self, f: F)
where
F: FnMut(&A) -> K,
K: Ord,
S: DataMut,
{
use core::mem;
macro_rules! sort_by_key {
($t:ty, $array:ident, $f:ident) => {{
let mut indices: Vec<_> = $array
.iter()
.map($f)
.enumerate()
.map(|(i, k)| (k, i as $t))
.collect();
indices.sort_unstable();
for i in 0..$array.len() {
let mut index = indices[i].1;
while (index as usize) < i {
index = indices[index as usize].1;
}
indices[i].1 = index;
$array.swap(i, index as usize);
}
}};
}
let sz_u8 = mem::size_of::<(K, u8)>();
let sz_u16 = mem::size_of::<(K, u16)>();
let sz_u32 = mem::size_of::<(K, u32)>();
let sz_usize = mem::size_of::<(K, usize)>();
let len = self.len();
if len < 2 {
return;
}
if sz_u8 < sz_u16 && len <= (u8::MAX as usize) {
return sort_by_key!(u8, self, f);
}
if sz_u16 < sz_u32 && len <= (u16::MAX as usize) {
return sort_by_key!(u16, self, f);
}
if sz_u32 < sz_usize && len <= (u32::MAX as usize) {
return sort_by_key!(u32, self, f);
}
sort_by_key!(usize, self, f)
}
#[cfg(feature = "rayon")]
#[inline]
fn par_sort_unstable(&mut self)
where
A: Ord + Send,
S: DataMut,
{
par_quick_sort(self.view_mut(), A::lt);
}
#[cfg(feature = "rayon")]
#[inline]
fn par_sort_unstable_by<F>(&mut self, compare: F)
where
A: Send,
F: Fn(&A, &A) -> Ordering + Sync,
S: DataMut,
{
par_quick_sort(self.view_mut(), |a: &A, b: &A| compare(a, b) == Less)
}
#[cfg(feature = "rayon")]
#[inline]
fn par_sort_unstable_by_key<K, F>(&mut self, f: F)
where
A: Send,
K: Ord,
F: Fn(&A) -> K + Sync,
S: DataMut,
{
par_quick_sort(self.view_mut(), |a: &A, b: &A| f(a).lt(&f(b)))
}
#[inline]
fn sort_unstable(&mut self)
where
A: Ord,
S: DataMut,
{
quick_sort(self.view_mut(), A::lt);
}
#[inline]
fn sort_unstable_by<F>(&mut self, mut compare: F)
where
F: FnMut(&A, &A) -> Ordering,
S: DataMut,
{
quick_sort(self.view_mut(), &mut |a: &A, b: &A| compare(a, b) == Less)
}
#[inline]
fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
where
K: Ord,
F: FnMut(&A) -> K,
S: DataMut,
{
quick_sort(self.view_mut(), &mut |a: &A, b: &A| f(a).lt(&f(b)))
}
#[inline]
fn is_sorted(&self) -> bool
where
A: PartialOrd,
{
is_sorted(self.view(), |a, b| a <= b)
}
#[inline]
fn is_sorted_by<F>(&self, compare: F) -> bool
where
F: FnMut(&A, &A) -> bool,
{
is_sorted(self.view(), compare)
}
#[inline]
fn is_sorted_by_key<F, K>(&self, mut f: F) -> bool
where
F: FnMut(&A) -> K,
K: PartialOrd,
{
is_sorted(self.view(), |a, b| f(a) <= f(b))
}
#[cfg(feature = "rayon")]
#[inline]
fn par_select_many_nth_unstable<'a, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut Vec<&'a mut A>,
) where
A: Ord + Send,
S: DataMut,
S2: Data<Elem = usize> + Sync,
{
collection.reserve_exact(indices.len());
let values = collection.spare_capacity_mut();
par_partition_at_indices(self.view_mut(), 0, indices.view(), values, &A::lt);
unsafe { collection.set_len(collection.len() + indices.len()) };
}
#[cfg(feature = "rayon")]
#[inline]
fn par_select_many_nth_unstable_by<'a, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut Vec<&'a mut A>,
compare: F,
) where
A: Send,
F: Fn(&A, &A) -> Ordering + Sync,
S: DataMut,
S2: Data<Elem = usize> + Sync,
{
collection.reserve_exact(indices.len());
let values = collection.spare_capacity_mut();
par_partition_at_indices(
self.view_mut(),
0,
indices.view(),
values,
&|a: &A, b: &A| compare(a, b) == Less,
);
unsafe { collection.set_len(collection.len() + indices.len()) };
}
#[cfg(feature = "rayon")]
#[inline]
fn par_select_many_nth_unstable_by_key<'a, K, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut Vec<&'a mut A>,
f: F,
) where
A: Send,
K: Ord,
F: Fn(&A) -> K + Sync,
S: DataMut,
S2: Data<Elem = usize> + Sync,
{
collection.reserve_exact(indices.len());
let values = collection.spare_capacity_mut();
par_partition_at_indices(
self.view_mut(),
0,
indices.view(),
values,
&|a: &A, b: &A| f(a).lt(&f(b)),
);
unsafe { collection.set_len(collection.len() + indices.len()) };
}
#[inline]
fn select_many_nth_unstable<'a, E, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut E,
) where
A: Ord + 'a,
E: Extend<(usize, &'a mut A)>,
S: DataMut,
S2: Data<Elem = usize>,
{
partition_at_indices(self.view_mut(), 0, indices.view(), collection, &mut A::lt);
}
#[inline]
fn select_many_nth_unstable_by<'a, E, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut E,
mut compare: F,
) where
A: 'a,
E: Extend<(usize, &'a mut A)>,
F: FnMut(&A, &A) -> Ordering,
S: DataMut,
S2: Data<Elem = usize>,
{
partition_at_indices(
self.view_mut(),
0,
indices.view(),
collection,
&mut |a: &A, b: &A| compare(a, b) == Less,
);
}
#[inline]
fn select_many_nth_unstable_by_key<'a, E, K, F, S2>(
&'a mut self,
indices: &ArrayBase<S2, Ix1>,
collection: &mut E,
mut f: F,
) where
A: 'a,
E: Extend<(usize, &'a mut A)>,
K: Ord,
F: FnMut(&A) -> K,
S: DataMut,
S2: Data<Elem = usize>,
{
partition_at_indices(
self.view_mut(),
0,
indices.view(),
collection,
&mut |a: &A, b: &A| f(a).lt(&f(b)),
);
}
#[inline]
fn select_nth_unstable(
&mut self,
index: usize,
) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
where
A: Ord,
S: DataMut,
{
partition_at_index(self.view_mut(), index, &mut A::lt)
}
#[inline]
fn select_nth_unstable_by<F>(
&mut self,
index: usize,
mut compare: F,
) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
where
F: FnMut(&A, &A) -> Ordering,
S: DataMut,
{
partition_at_index(self.view_mut(), index, &mut |a: &A, b: &A| {
compare(a, b) == Less
})
}
#[inline]
fn select_nth_unstable_by_key<K, F>(
&mut self,
index: usize,
mut f: F,
) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
where
K: Ord,
F: FnMut(&A) -> K,
S: DataMut,
{
partition_at_index(self.view_mut(), index, &mut |a: &A, b: &A| f(a).lt(&f(b)))
}
#[inline]
fn partition_point<P>(&self, mut pred: P) -> usize
where
P: FnMut(&A) -> bool,
{
self.binary_search_by(|x| if pred(x) { Less } else { Greater })
.unwrap_or_else(|i| i)
}
#[inline]
fn contains(&self, x: &A) -> bool
where
A: PartialEq,
{
self.iter().any(|a| a == x)
}
#[inline]
fn binary_search(&self, x: &A) -> Result<usize, usize>
where
A: Ord,
{
self.binary_search_by(|p| p.cmp(x))
}
fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize>
where
F: FnMut(&A) -> Ordering,
{
let mut size = self.len();
let mut left = 0;
let mut right = size;
while left < right {
let mid = left + size / 2;
let cmp = f(unsafe { self.uget(mid) });
left = if cmp == Less { mid + 1 } else { left };
right = if cmp == Greater { mid } else { right };
if cmp == Equal {
debug_assert!(mid < self.len());
return Ok(mid);
}
size = right - left;
}
debug_assert!(left <= self.len());
Err(left)
}
#[inline]
fn binary_search_by_key<B, F>(&self, b: &B, mut f: F) -> Result<usize, usize>
where
F: FnMut(&A) -> B,
B: Ord,
{
self.binary_search_by(|k| f(k).cmp(b))
}
#[inline]
fn partition_dedup(&mut self) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
where
A: PartialEq,
S: DataMut,
{
self.partition_dedup_by(|a, b| a == b)
}
#[inline]
fn partition_dedup_by<F>(
&mut self,
same_bucket: F,
) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
where
F: FnMut(&mut A, &mut A) -> bool,
S: DataMut,
{
partition_dedup(self.view_mut(), same_bucket)
}
#[inline]
fn partition_dedup_by_key<K, F>(
&mut self,
mut key: F,
) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
where
F: FnMut(&mut A) -> K,
K: PartialEq,
S: DataMut,
{
self.partition_dedup_by(|a, b| key(a) == key(b))
}
#[inline]
fn reverse(&mut self)
where
S: DataMut,
{
reverse(self.view_mut());
}
}