#![no_std]
extern crate alloc;
#[cfg(feature = "diff")]
pub mod diff;
#[cfg(feature = "diff")]
pub use diff::{DiffCallback, diff_by_key};
use alloc::vec::Vec;
use core::hint::assert_unchecked;
pub fn lis<T, F>(items: &[T], mut is_less: F) -> Vec<usize>
where
F: FnMut(&T, &T) -> bool,
{
let len = items.len();
if len == 0 {
return Vec::new();
}
let mut tails: Vec<usize> = Vec::with_capacity(len);
let mut preds: Vec<usize> = Vec::with_capacity(len);
let tails_ptr = tails.as_mut_ptr();
let preds_ptr = preds.as_mut_ptr();
let items_ptr = items.as_ptr();
unsafe {
tails_ptr.write(0);
preds_ptr.write(usize::MAX);
let k = if len <= 2048 {
lis_inner_in_cache_search(len, items_ptr, tails_ptr, preds_ptr, &mut is_less)
} else {
lis_inner_partition_point(len, items_ptr, tails_ptr, preds_ptr, &mut is_less)
};
let lis_len = k + 1;
let mut result: Vec<usize> = Vec::with_capacity(lis_len);
let mut curr = *tails_ptr.add(k);
let mut res_ptr = result.as_mut_ptr().add(lis_len);
for _ in 0..lis_len {
res_ptr = res_ptr.sub(1);
res_ptr.write(curr);
curr = *preds_ptr.add(curr);
}
result.set_len(lis_len);
tails.set_len(lis_len);
preds.set_len(len);
result
}
}
pub fn lis_length<T, F>(items: &[T], mut is_less: F) -> usize
where
F: FnMut(&T, &T) -> bool,
{
let len = items.len();
if len <= 1 {
return len;
}
let mut tails: Vec<usize> = Vec::with_capacity(len);
let tails_ptr = tails.as_mut_ptr();
let items_ptr = items.as_ptr();
unsafe {
tails_ptr.write(0);
let k = if len <= 2048 {
lis_length_inner_in_cache_search(len, items_ptr, tails_ptr, &mut is_less)
} else {
lis_length_inner_partition_point(len, items_ptr, tails_ptr, &mut is_less)
};
k + 1
}
}
#[inline(always)]
unsafe fn lis_inner_in_cache_search<T, F>(
len: usize,
items_ptr: *const T,
tails_ptr: *mut usize,
preds_ptr: *mut usize,
is_less: &mut F,
) -> usize
where
F: FnMut(&T, &T) -> bool,
{
unsafe {
let mut k = 0;
for i in 1..len {
let last_tail = *tails_ptr.add(k);
assert_unchecked(last_tail < len);
let x = &*items_ptr.add(i);
if is_less(&*items_ptr.add(last_tail), x) {
k += 1;
tails_ptr.add(k).write(i);
preds_ptr.add(i).write(last_tail);
continue;
}
let mut lo = 0;
let mut hi = k;
while lo < hi {
let mid = (lo + hi) >> 1;
let t = *tails_ptr.add(mid);
assert_unchecked(t < len);
let less = is_less(&*items_ptr.add(t), x);
lo = if less { mid + 1 } else { lo };
hi = if less { hi } else { mid };
}
let p_idx = if lo > 0 { lo - 1 } else { 0 };
let p_val = *tails_ptr.add(p_idx);
let pred = if lo > 0 { p_val } else { usize::MAX };
preds_ptr.add(i).write(pred);
tails_ptr.add(lo).write(i);
}
k
}
}
#[inline(always)]
unsafe fn lis_inner_partition_point<T, F>(
len: usize,
items_ptr: *const T,
tails_ptr: *mut usize,
preds_ptr: *mut usize,
is_less: &mut F,
) -> usize
where
F: FnMut(&T, &T) -> bool,
{
unsafe {
let mut k = 0;
for i in 1..len {
let last_tail = *tails_ptr.add(k);
assert_unchecked(last_tail < len);
let x = &*items_ptr.add(i);
if is_less(&*items_ptr.add(last_tail), x) {
k += 1;
tails_ptr.add(k).write(i);
preds_ptr.add(i).write(last_tail);
continue;
}
let search_slice = core::slice::from_raw_parts(tails_ptr, k);
let pos = search_slice.partition_point(|&t| is_less(&*items_ptr.add(t), x));
let pred = if pos > 0 {
*tails_ptr.add(pos - 1)
} else {
usize::MAX
};
preds_ptr.add(i).write(pred);
tails_ptr.add(pos).write(i);
}
k
}
}
#[inline(always)]
unsafe fn lis_length_inner_in_cache_search<T, F>(
len: usize,
items_ptr: *const T,
tails_ptr: *mut usize,
is_less: &mut F,
) -> usize
where
F: FnMut(&T, &T) -> bool,
{
unsafe {
let mut k = 0;
for i in 1..len {
let last_tail = *tails_ptr.add(k);
assert_unchecked(last_tail < len);
let x = &*items_ptr.add(i);
if is_less(&*items_ptr.add(last_tail), x) {
k += 1;
tails_ptr.add(k).write(i);
continue;
}
let mut lo = 0;
let mut hi = k;
while lo < hi {
let mid = (lo + hi) >> 1;
let t = *tails_ptr.add(mid);
assert_unchecked(t < len);
let less = is_less(&*items_ptr.add(t), x);
lo = if less { mid + 1 } else { lo };
hi = if less { hi } else { mid };
}
tails_ptr.add(lo).write(i);
}
k
}
}
#[inline(always)]
unsafe fn lis_length_inner_partition_point<T, F>(
len: usize,
items_ptr: *const T,
tails_ptr: *mut usize,
is_less: &mut F,
) -> usize
where
F: FnMut(&T, &T) -> bool,
{
unsafe {
let mut k = 0;
for i in 1..len {
let last_tail = *tails_ptr.add(k);
assert_unchecked(last_tail < len);
let x = &*items_ptr.add(i);
if is_less(&*items_ptr.add(last_tail), x) {
k += 1;
tails_ptr.add(k).write(i);
continue;
}
let search_slice = core::slice::from_raw_parts(tails_ptr, k);
let pos = search_slice.partition_point(|&t| is_less(&*items_ptr.add(t), x));
tails_ptr.add(pos).write(i);
}
k
}
}
pub trait LisExt<T> {
fn lis_indices(&self) -> Vec<usize>
where
T: Ord;
fn lis_indices_by<F>(&self, is_less: F) -> Vec<usize>
where
F: FnMut(&T, &T) -> bool;
fn lis_indices_by_key<K, F>(&self, f: F) -> Vec<usize>
where
F: FnMut(&T) -> K,
K: Ord;
fn lis_values(&self) -> Vec<T>
where
T: Ord + Clone;
fn lis_values_by<F>(&self, is_less: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T, &T) -> bool;
fn lis_values_by_key<K, F>(&self, f: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T) -> K,
K: Ord;
fn lis_refs(&self) -> Vec<&T>
where
T: Ord;
fn lis_refs_by<F>(&self, is_less: F) -> Vec<&T>
where
F: FnMut(&T, &T) -> bool;
fn lis_refs_by_key<K, F>(&self, f: F) -> Vec<&T>
where
F: FnMut(&T) -> K,
K: Ord;
fn lis_length(&self) -> usize
where
T: Ord;
fn lis_length_by<F>(&self, is_less: F) -> usize
where
F: FnMut(&T, &T) -> bool;
fn lis_length_by_key<K, F>(&self, f: F) -> usize
where
F: FnMut(&T) -> K,
K: Ord;
fn lis_indices_by_cached_key<K, F>(&self, f: F) -> Vec<usize>
where
F: FnMut(&T) -> K,
K: Ord;
fn lis_values_by_cached_key<K, F>(&self, f: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T) -> K,
K: Ord;
fn lis_refs_by_cached_key<K, F>(&self, f: F) -> Vec<&T>
where
F: FnMut(&T) -> K,
K: Ord;
fn lis_length_by_cached_key<K, F>(&self, f: F) -> usize
where
F: FnMut(&T) -> K,
K: Ord;
fn lds_values(&self) -> Vec<T>
where
T: Ord + Clone;
fn lnds_values(&self) -> Vec<T>
where
T: Ord + Clone;
fn lnis_values(&self) -> Vec<T>
where
T: Ord + Clone;
}
impl<T> LisExt<T> for [T] {
#[inline]
fn lis_indices(&self) -> Vec<usize>
where
T: Ord,
{
lis(self, |a, b| a < b)
}
#[inline]
fn lis_indices_by<F>(&self, is_less: F) -> Vec<usize>
where
F: FnMut(&T, &T) -> bool,
{
lis(self, is_less)
}
#[inline]
fn lis_indices_by_key<K, F>(&self, mut f: F) -> Vec<usize>
where
F: FnMut(&T) -> K,
K: Ord,
{
lis(self, |a, b| f(a) < f(b))
}
#[inline]
fn lis_values(&self) -> Vec<T>
where
T: Ord + Clone,
{
self.lis_indices()
.into_iter()
.map(|i| self[i].clone())
.collect()
}
#[inline]
fn lis_values_by<F>(&self, is_less: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T, &T) -> bool,
{
self.lis_indices_by(is_less)
.into_iter()
.map(|i| self[i].clone())
.collect()
}
#[inline]
fn lis_values_by_key<K, F>(&self, f: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T) -> K,
K: Ord,
{
self.lis_indices_by_key(f)
.into_iter()
.map(|i| self[i].clone())
.collect()
}
#[inline]
fn lis_refs(&self) -> Vec<&T>
where
T: Ord,
{
self.lis_indices().into_iter().map(|i| &self[i]).collect()
}
#[inline]
fn lis_refs_by<F>(&self, is_less: F) -> Vec<&T>
where
F: FnMut(&T, &T) -> bool,
{
self.lis_indices_by(is_less)
.into_iter()
.map(|i| &self[i])
.collect()
}
#[inline]
fn lis_refs_by_key<K, F>(&self, f: F) -> Vec<&T>
where
F: FnMut(&T) -> K,
K: Ord,
{
self.lis_indices_by_key(f)
.into_iter()
.map(|i| &self[i])
.collect()
}
#[inline]
fn lis_length(&self) -> usize
where
T: Ord,
{
lis_length(self, |a, b| a < b)
}
#[inline]
fn lis_length_by<F>(&self, is_less: F) -> usize
where
F: FnMut(&T, &T) -> bool,
{
lis_length(self, is_less)
}
#[inline]
fn lis_length_by_key<K, F>(&self, mut f: F) -> usize
where
F: FnMut(&T) -> K,
K: Ord,
{
lis_length(self, |a, b| f(a) < f(b))
}
#[inline]
fn lds_values(&self) -> Vec<T>
where
T: Ord + Clone,
{
self.lis_values_by(|a, b| a > b)
}
#[inline]
fn lnds_values(&self) -> Vec<T>
where
T: Ord + Clone,
{
self.lis_values_by(|a, b| a <= b)
}
#[inline]
fn lnis_values(&self) -> Vec<T>
where
T: Ord + Clone,
{
self.lis_values_by(|a, b| a >= b)
}
#[inline]
fn lis_indices_by_cached_key<K, F>(&self, mut f: F) -> Vec<usize>
where
F: FnMut(&T) -> K,
K: Ord,
{
let keys: Vec<K> = self.iter().map(&mut f).collect();
lis(&keys, |a, b| a < b)
}
#[inline]
fn lis_values_by_cached_key<K, F>(&self, f: F) -> Vec<T>
where
T: Clone,
F: FnMut(&T) -> K,
K: Ord,
{
self.lis_indices_by_cached_key(f)
.into_iter()
.map(|i| self[i].clone())
.collect()
}
#[inline]
fn lis_refs_by_cached_key<K, F>(&self, f: F) -> Vec<&T>
where
F: FnMut(&T) -> K,
K: Ord,
{
self.lis_indices_by_cached_key(f)
.into_iter()
.map(|i| &self[i])
.collect()
}
#[inline]
fn lis_length_by_cached_key<K, F>(&self, mut f: F) -> usize
where
F: FnMut(&T) -> K,
K: Ord,
{
let keys: Vec<K> = self.iter().map(&mut f).collect();
lis_length(&keys, |a, b| a < b)
}
}
pub trait IteratorLisExt: Iterator {
fn lis(self) -> Vec<Self::Item>
where
Self: Sized,
Self::Item: Ord,
{
let mut items: Vec<Self::Item> = self.collect();
let indices = items.lis_indices();
for (dest, &src) in indices.iter().enumerate() {
items.swap(dest, src);
}
items.truncate(indices.len());
items
}
fn lis_by<F>(self, is_less: F) -> Vec<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item, &Self::Item) -> bool,
{
let mut items: Vec<Self::Item> = self.collect();
let indices = items.lis_indices_by(is_less);
for (dest, &src) in indices.iter().enumerate() {
items.swap(dest, src);
}
items.truncate(indices.len());
items
}
fn lis_by_key<K, F>(self, f: F) -> Vec<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item) -> K,
K: Ord,
{
let mut items: Vec<Self::Item> = self.collect();
let indices = items.lis_indices_by_key(f);
for (dest, &src) in indices.iter().enumerate() {
items.swap(dest, src);
}
items.truncate(indices.len());
items
}
fn lis_by_cached_key<K, F>(self, f: F) -> Vec<Self::Item>
where
Self: Sized,
F: FnMut(&Self::Item) -> K,
K: Ord,
{
let mut items: Vec<Self::Item> = self.collect();
let indices = items.lis_indices_by_cached_key(f);
for (dest, &src) in indices.iter().enumerate() {
items.swap(dest, src);
}
items.truncate(indices.len());
items
}
fn lis_length(self) -> usize
where
Self: Sized,
Self::Item: Ord,
{
let items: Vec<Self::Item> = self.collect();
items.lis_length()
}
fn lis_length_by<F>(self, is_less: F) -> usize
where
Self: Sized,
F: FnMut(&Self::Item, &Self::Item) -> bool,
{
let items: Vec<Self::Item> = self.collect();
items.lis_length_by(is_less)
}
fn lis_length_by_key<K, F>(self, f: F) -> usize
where
Self: Sized,
F: FnMut(&Self::Item) -> K,
K: Ord,
{
let items: Vec<Self::Item> = self.collect();
items.lis_length_by_key(f)
}
fn lis_length_by_cached_key<K, F>(self, f: F) -> usize
where
Self: Sized,
F: FnMut(&Self::Item) -> K,
K: Ord,
{
let items: Vec<Self::Item> = self.collect();
items.lis_length_by_cached_key(f)
}
}
impl<I: Iterator> IteratorLisExt for I {}