#![cfg_attr(not(feature = "std"), no_std)]
use core::{
any::TypeId,
cell::{Cell, RefCell},
cmp::min,
marker::PhantomData,
num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
},
ops::Deref,
pin::Pin,
};
#[cfg(feature = "alloc")]
extern crate alloc;
use core::{cmp::Ordering, time::Duration};
use utils::{LexicographicTracker, ResultTracker};
use Ordering::*;
pub mod utils;
pub trait Tracker {
const IS_NOOP: bool;
fn new() -> Self;
}
impl Tracker for () {
const IS_NOOP: bool = true;
fn new() -> Self {}
}
pub trait TreeOrd<Rhs = Self>
where
Self: Ord,
Rhs: ?Sized,
{
type Tracker: Tracker;
fn tree_cmp(&self, rhs: &Rhs, tracker: &mut Self::Tracker) -> Ordering;
}
impl TreeOrd<Self> for () {
type Tracker = ();
#[inline]
fn tree_cmp(&self, rhs: &Self, _: &mut Self::Tracker) -> Ordering {
self.cmp(rhs)
}
}
macro_rules! impl_simple_tree_ord {
($($t:ident)*) => {
$(
impl TreeOrd<Self> for $t {
type Tracker = ();
#[inline]
fn tree_cmp(&self, rhs: &Self, _: &mut Self::Tracker) -> Ordering {
self.cmp(rhs)
}
}
)*
};
}
impl_simple_tree_ord!(
usize u8 u16 u32 u64 u128 NonZeroUsize NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128
isize i8 i16 i32 i64 i128 NonZeroIsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128
bool char
Ordering TypeId Duration
);
#[derive(PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct OrdToTreeOrd<T: Ord>(pub T);
impl<T: Ord> TreeOrd<Self> for OrdToTreeOrd<T> {
type Tracker = ();
#[inline]
fn tree_cmp(&self, rhs: &Self, _: &mut Self::Tracker) -> Ordering {
self.0.cmp(&rhs.0)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct TreeOrdReverse<T: TreeOrd>(pub T);
impl<T: TreeOrd> TreeOrd<Self> for TreeOrdReverse<T> {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.0.tree_cmp(&rhs.0, tracker).reverse()
}
}
impl<T: TreeOrd> TreeOrd<Self> for &T {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrd::tree_cmp(*self, *rhs, tracker)
}
}
impl<T: TreeOrd> TreeOrd<Self> for &mut T {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrd::tree_cmp(*self, *rhs, tracker)
}
}
impl<T: TreeOrd + Copy> TreeOrd<Self> for Cell<T> {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrd::tree_cmp(&self.get(), &rhs.get(), tracker)
}
}
impl<T: TreeOrd + ?Sized> TreeOrd<Self> for RefCell<T> {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.borrow().tree_cmp(&*rhs.borrow(), tracker)
}
}
impl<T: ?Sized> TreeOrd<Self> for PhantomData<T> {
type Tracker = ();
#[inline]
fn tree_cmp(&self, _: &Self, _: &mut Self::Tracker) -> Ordering {
Ordering::Equal
}
}
#[cfg(feature = "alloc")]
impl<T: TreeOrd + ?Sized> TreeOrd<Self> for alloc::boxed::Box<T> {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrd::tree_cmp(self.as_ref(), rhs.as_ref(), tracker)
}
}
#[cfg(feature = "alloc")]
impl<T: TreeOrd + ?Sized> TreeOrd<Self> for alloc::rc::Rc<T> {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrd::tree_cmp(self.as_ref(), rhs.as_ref(), tracker)
}
}
#[cfg(feature = "alloc")]
impl<T: TreeOrd + ?Sized> TreeOrd<Self> for alloc::sync::Arc<T> {
type Tracker = T::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrd::tree_cmp(self.as_ref(), rhs.as_ref(), tracker)
}
}
impl<P> TreeOrd<Self> for Pin<P>
where
P: Deref,
<P as Deref>::Target: TreeOrd,
{
type Tracker = <<P as Deref>::Target as TreeOrd>::Tracker;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.deref().tree_cmp(rhs.deref(), tracker)
}
}
impl<T: TreeOrd> TreeOrd<Self> for Option<T> {
type Tracker = T::Tracker;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
match (self, rhs) {
(None, None) => Equal,
(None, Some(_)) => Less,
(Some(_), None) => Greater,
(Some(lhs), Some(rhs)) => lhs.tree_cmp(rhs, tracker),
}
}
}
impl<T: TreeOrd, E: TreeOrd> TreeOrd<Self> for Result<T, E> {
type Tracker = ResultTracker<T, E>;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
match (self, rhs) {
(Ok(lhs), Ok(rhs)) => lhs.tree_cmp(rhs, &mut tracker.t),
(Ok(_), Err(_)) => Less,
(Err(_), Ok(_)) => Greater,
(Err(lhs), Err(rhs)) => lhs.tree_cmp(rhs, &mut tracker.e),
}
}
}
impl<T: TreeOrd> TreeOrd<Self> for [T] {
type Tracker = LexicographicTracker<T>;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
let not_noop = !<T as TreeOrd>::Tracker::IS_NOOP;
let start = min(tracker.min_eq_len, tracker.max_eq_len);
let end = min(self.len(), rhs.len());
if start >= end {
return self.len().cmp(&rhs.len())
}
let len = end.wrapping_sub(start);
let x = &self[start..end];
let y = &rhs[start..end];
let i = start;
if not_noop && (i != tracker.subtracker_i) {
tracker.subtracker = <T as TreeOrd>::Tracker::new();
tracker.subtracker_i = i;
}
match x[0].tree_cmp(&y[0], &mut tracker.subtracker) {
Less => return Less,
Equal => (),
Greater => return Greater,
}
for j in 1..len {
let i = j.wrapping_add(start);
match x[j].cmp(&y[j]) {
Less => {
tracker.max_eq_len = i;
return Less
}
Equal => (),
Greater => {
tracker.min_eq_len = i;
return Greater
}
}
}
self.len().cmp(&rhs.len())
}
}
impl TreeOrd<Self> for str {
type Tracker = <[u8] as TreeOrd>::Tracker;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.as_bytes().tree_cmp(rhs.as_bytes(), tracker)
}
}
impl<T: TreeOrd, const N: usize> TreeOrd<Self> for [T; N] {
type Tracker = <[T] as TreeOrd>::Tracker;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.as_slice().tree_cmp(rhs.as_slice(), tracker)
}
}
#[cfg(feature = "alloc")]
impl<T: TreeOrd> TreeOrd<Self> for alloc::vec::Vec<T> {
type Tracker = <[T] as TreeOrd>::Tracker;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.as_slice().tree_cmp(rhs.as_slice(), tracker)
}
}
#[cfg(feature = "alloc")]
impl TreeOrd<Self> for alloc::string::String {
type Tracker = <[u8] as TreeOrd>::Tracker;
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
self.as_bytes().tree_cmp(rhs.as_bytes(), tracker)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TreeOrdBytes<'a>(pub &'a [u8]);
impl<'a> TreeOrd<Self> for TreeOrdBytes<'a> {
type Tracker = LexicographicTracker<u8>;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
const CHUNK_LEN: usize = 32;
let start_chunks = min(tracker.min_eq_len, tracker.max_eq_len);
let start_bytes = start_chunks.wrapping_mul(CHUNK_LEN);
let end_bytes = min(self.0.len(), rhs.0.len());
let end_chunks = end_bytes.wrapping_div(CHUNK_LEN);
if start_chunks >= end_chunks {
if start_bytes >= end_bytes {
return self.0.len().cmp(&rhs.0.len())
} else {
let x = &self.0[start_bytes..];
let y = &rhs.0[start_bytes..];
return x.cmp(y)
}
}
let len_chunks = end_chunks.wrapping_sub(start_chunks);
for i in 0..len_chunks {
let start = start_chunks.wrapping_add(i).wrapping_mul(CHUNK_LEN);
let end = start.wrapping_add(CHUNK_LEN);
let x = &self.0[start..end];
let y = &rhs.0[start..end];
match x.cmp(y) {
Less => {
tracker.max_eq_len = i;
return Less
}
Equal => (),
Greater => {
tracker.min_eq_len = i;
return Greater
}
}
}
let extra_start = end_chunks.wrapping_mul(CHUNK_LEN);
self.0[extra_start..].cmp(&rhs.0[extra_start..])
}
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TreeOrdVec(pub alloc::vec::Vec<u8>);
#[cfg(feature = "alloc")]
impl TreeOrd<Self> for TreeOrdVec {
type Tracker = LexicographicTracker<u8>;
#[inline]
fn tree_cmp(&self, rhs: &Self, tracker: &mut Self::Tracker) -> Ordering {
TreeOrdBytes(&self.0).tree_cmp(&TreeOrdBytes(&rhs.0), tracker)
}
}