use std::fmt::Debug;
use num::{traits::AsPrimitive, FromPrimitive, Integer};
use smallvec::{Array, SmallVec};
use crate::SearchResult;
pub trait Mergable<Cfg = ()> {
fn is_mergable(&self, _other: &Self, _conf: &Cfg) -> bool
where
Self: Sized,
{
false
}
fn merge(&mut self, _other: &Self, _conf: &Cfg)
where
Self: Sized,
{
unreachable!()
}
}
pub trait Sliceable {
fn slice(&self, from: usize, to: usize) -> Self;
}
#[derive(Debug, Clone, Copy)]
pub struct Slice<'a, T> {
pub value: &'a T,
pub start: usize,
pub end: usize,
}
impl<T: Sliceable> Slice<'_, T> {
pub fn into_inner(&self) -> T {
self.value.slice(self.start, self.end)
}
}
#[allow(clippy::len_without_is_empty)]
pub trait HasLength {
fn content_len(&self) -> usize;
fn atom_len(&self) -> usize {
self.content_len()
}
}
pub trait Rle<Cfg = ()>: HasLength + Sliceable + Mergable<Cfg> + Debug + Clone {}
pub trait ZeroElement {
fn zero_element() -> Self;
}
impl<T: Default> ZeroElement for T {
fn zero_element() -> Self {
Default::default()
}
}
impl<T: HasLength + Sliceable + Mergable<Cfg> + Debug + Clone, Cfg> Rle<Cfg> for T {}
pub trait HasIndex: HasLength {
type Int: GlobalIndex;
fn get_start_index(&self) -> Self::Int;
#[inline]
fn get_end_index(&self) -> Self::Int {
self.get_start_index() + Self::Int::from_usize(self.atom_len()).unwrap()
}
}
pub trait GlobalIndex:
Debug + Integer + Copy + Default + FromPrimitive + AsPrimitive<usize>
{
}
impl<T: Debug + Integer + Copy + Default + FromPrimitive + AsPrimitive<usize>> GlobalIndex for T {}
impl HasLength for String {
fn content_len(&self) -> usize {
self.len()
}
}
impl<T> HasLength for Vec<T> {
fn content_len(&self) -> usize {
self.len()
}
}
impl<T: Clone> Sliceable for Vec<T> {
fn slice(&self, from: usize, to: usize) -> Self {
self[from..to].to_vec()
}
}
impl Sliceable for String {
fn slice(&self, from: usize, to: usize) -> Self {
self[from..to].to_string()
}
}
pub trait RlePush<T> {
fn push_rle_element(&mut self, element: T);
}
pub trait RleCollection<T: HasIndex> {
fn start(&self) -> <T as HasIndex>::Int;
fn end(&self) -> <T as HasIndex>::Int;
fn sum_atom_len(&self) -> <T as HasIndex>::Int;
fn search_atom_index(&self, index: <T as HasIndex>::Int) -> usize;
fn get_by_atom_index(
&self,
index: <T as HasIndex>::Int,
) -> Option<SearchResult<'_, T, <T as HasIndex>::Int>>;
}
impl<T: Mergable> RlePush<T> for Vec<T> {
fn push_rle_element(&mut self, element: T) {
match self.last_mut() {
Some(last) if last.is_mergable(&element, &()) => {
last.merge(&element, &());
}
_ => {
self.push(element);
}
}
}
}
impl<T: Mergable + HasIndex + HasLength> RleCollection<T> for Vec<T> {
fn search_atom_index(&self, index: <T as HasIndex>::Int) -> usize {
let mut start = 0;
let mut end = self.len() - 1;
while start < end {
let mid = (start + end) / 2;
match self[mid].get_start_index().cmp(&index) {
std::cmp::Ordering::Equal => {
start = mid;
break;
}
std::cmp::Ordering::Less => {
start = mid + 1;
}
std::cmp::Ordering::Greater => {
end = mid;
}
}
}
if index < self[start].get_start_index() {
start -= 1;
}
start
}
fn get_by_atom_index(
&self,
index: <T as HasIndex>::Int,
) -> Option<SearchResult<'_, T, <T as HasIndex>::Int>> {
if index > self.end() {
return None;
}
let merged_index = self.search_atom_index(index);
let value = &self[merged_index];
Some(SearchResult {
merged_index,
element: value,
offset: index - self[merged_index].get_start_index(),
})
}
fn start(&self) -> <T as HasIndex>::Int {
self.first()
.map(|x| x.get_start_index())
.unwrap_or_default()
}
fn end(&self) -> <T as HasIndex>::Int {
self.last().map(|x| x.get_end_index()).unwrap_or_default()
}
fn sum_atom_len(&self) -> <T as HasIndex>::Int {
self.end() - self.start()
}
}
impl<A: Array> RlePush<A::Item> for SmallVec<A>
where
A::Item: Mergable,
{
fn push_rle_element(&mut self, element: A::Item) {
match self.last_mut() {
Some(last) if last.is_mergable(&element, &()) => {
last.merge(&element, &());
}
_ => {
self.push(element);
}
}
}
}