use crate::ReArr;
use alloc::{
string::{String, ToString},
vec::{IntoIter as VecIter, Vec},
};
use core::{
array::IntoIter as ArrayIter,
cmp::Ordering,
fmt::{Debug, Display, Formatter, Result as FmtResult},
hash::{Hash, Hasher},
iter::{Chain, Flatten},
ops,
};
#[macro_export]
macro_rules! combo_vec {
() => (
$crate::ComboVec::new()
);
($elem:expr; $n:expr) => (
$crate::ComboVec::from_arr([Some($elem); $n])
);
($($x:expr),+ $(,)?) => (
$crate::ComboVec::from_arr([$(Some($x)),+])
);
($($x:expr),+; $($rest:expr),* $(,)?) => (
$crate::ComboVec::from_arr_and_len(&[$(Some($x)),+, $($rest),*])
);
}
pub struct ComboVec<T, const N: usize> {
arr: ReArr<T, N>,
vec: Vec<T>,
}
impl<T: Clone, const N: usize> Clone for ComboVec<T, N> {
#[inline]
fn clone(&self) -> Self {
Self {
arr: self.arr.clone(),
vec: self.vec.clone(),
}
}
}
impl<T: PartialOrd, const N: usize> PartialOrd for ComboVec<T, N> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<T: Ord, const N: usize> Ord for ComboVec<T, N> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other.iter())
}
}
impl<T: PartialEq, const N: usize> PartialEq for ComboVec<T, N> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.iter().eq(other.iter())
}
}
impl<T: PartialEq + Eq, const N: usize> Eq for ComboVec<T, N> {}
impl<T: Hash, const N: usize> Hash for ComboVec<T, N> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.iter().for_each(|x| x.hash(state));
}
}
impl<T: Default, const N: usize> Default for ComboVec<T, N> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T: Copy, const N: usize> ComboVec<T, N> {
pub const fn from_arr_and_len(arr: &[Option<T>; N]) -> Self {
Self {
arr: ReArr::from_arr_and_len(arr),
vec: Vec::new(),
}
}
}
impl<T, const N: usize> ComboVec<T, N> {
#[inline]
#[must_use]
pub const fn new() -> Self {
Self {
arr: ReArr::new(),
vec: Vec::new(),
}
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.vec.reserve(additional);
}
#[must_use]
#[inline]
pub const fn from_arr(arr: [Option<T>; N]) -> Self {
Self {
arr: ReArr::from_arr(arr),
vec: Vec::new(),
}
}
#[inline]
pub fn push(&mut self, val: T) {
if self.len() < N {
self.arr.push(val);
} else {
self.vec.push(val);
}
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.vec.is_empty() {
self.arr.pop()
} else {
self.vec.pop()
}
}
#[must_use]
#[inline]
pub fn get(&self, idx: usize) -> Option<&T> {
if idx < N {
self.arr.get(idx)
} else {
self.vec.get(idx - N)
}
}
#[must_use]
#[inline]
pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
if idx < N {
self.arr.get_mut(idx)
} else {
self.vec.get_mut(idx - N)
}
}
#[inline]
pub fn spilled(&self) -> bool {
self.heap_len() > 0
}
#[inline]
pub const fn stack_len(&self) -> usize {
self.arr.len()
}
#[inline]
pub fn heap_len(&self) -> usize {
self.vec.len()
}
#[inline]
pub fn len(&self) -> usize {
self.stack_len() + self.heap_len()
}
#[inline]
pub const fn stack_capacity(&self) -> usize {
N
}
#[inline]
pub fn heap_capacity(&self) -> usize {
self.vec.capacity()
}
#[inline]
pub fn capacity(&self) -> usize {
self.stack_capacity() + self.heap_capacity()
}
#[inline]
pub fn truncate(&mut self, len: usize) {
if len > self.len() {
} else if len >= N {
self.vec.truncate(len - N);
} else {
self.arr.truncate(len);
self.vec.clear();
}
}
#[inline]
pub fn clear(&mut self) {
self.arr.clear();
self.vec.clear();
}
#[inline]
pub fn first(&self) -> Option<&T> {
if N == 0 {
self.vec.first()
} else {
self.arr.first()
}
}
#[inline]
pub fn first_mut(&mut self) -> Option<&mut T> {
if N == 0 {
self.vec.first_mut()
} else {
self.arr.first_mut()
}
}
#[inline]
pub fn last(&self) -> Option<&T> {
if N == 0 {
self.vec.last()
} else {
self.vec.last().or_else(|| self.arr.last())
}
}
#[inline]
pub fn last_mut(&mut self) -> Option<&mut T> {
if N == 0 {
self.vec.last_mut()
} else {
self.vec.last_mut().or_else(|| self.arr.last_mut())
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
self.arr.iter().chain(self.vec.iter())
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
self.arr.iter_mut().chain(self.vec.iter_mut())
}
#[inline]
pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
iter.into_iter().for_each(|x| self.push(x));
}
#[inline]
pub fn into_vec(self) -> Vec<T> {
self.into_iter().collect()
}
#[inline]
pub fn ref_vec(&self) -> Vec<&T> {
self.iter().collect()
}
}
impl<T: Clone, const N: usize> ComboVec<T, N> {
#[inline]
pub fn to_vec(&self) -> Vec<T> {
self.iter().cloned().collect()
}
pub fn resize(&mut self, new_len: usize, val: T) {
if new_len >= N {
if self.len() < N {
self.arr.resize(N, val.clone());
}
self.vec.resize(new_len - N, val);
} else {
self.arr.resize(new_len, val);
self.vec.clear();
}
}
pub fn resize_with<F: FnMut() -> T>(&mut self, new_len: usize, mut f: F) {
if new_len >= N {
for _ in self.len()..N {
self.arr.push(f());
}
self.vec.resize_with(new_len - N, f);
} else {
self.arr.resize_with(new_len, f);
self.vec.clear();
}
}
#[inline]
pub fn remove(&mut self, index: usize) -> T {
if index >= N {
self.vec.remove(index - N)
} else {
let val = self.arr.remove(index);
if !self.vec.is_empty() {
self.arr.push(self.vec.remove(0));
}
val
}
}
#[inline]
pub fn swap_remove(&mut self, index: usize) -> T {
if index >= N {
self.vec.swap_remove(index - N)
} else if self.len() <= N {
self.arr.swap_remove(index)
} else {
let last_value = self.vec.pop().unwrap();
self.arr.arr[index].replace(last_value).unwrap()
}
}
}
impl<T: ToString, const N: usize> ComboVec<T, N> {
pub fn join(&self, sep: &str) -> String {
self.iter()
.enumerate()
.fold(String::with_capacity(self.len()), |mut s, (i, item)| {
if i != 0 {
s.push_str(sep);
}
s.push_str(&item.to_string());
s
})
}
}
impl<T, const N: usize> ops::Index<usize> for ComboVec<T, N> {
type Output = T;
#[inline]
fn index(&self, idx: usize) -> &Self::Output {
if idx < N {
&self.arr[idx]
} else {
&self.vec[idx - N]
}
}
}
impl<T, const N: usize> ops::IndexMut<usize> for ComboVec<T, N> {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
if idx < N {
&mut self.arr[idx]
} else {
&mut self.vec[idx - N]
}
}
}
impl<T, const N: usize> IntoIterator for ComboVec<T, N> {
type Item = T;
type IntoIter = Chain<Flatten<ArrayIter<Option<T>, N>>, VecIter<T>>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.arr.into_iter().chain(self.vec)
}
}
impl<T> FromIterator<T> for ComboVec<T, 0> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self {
arr: ReArr::new(),
vec: iter.into_iter().collect(),
}
}
}
impl<T: Debug, const N: usize> Debug for ComboVec<T, N> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("ComboVec")
.field("arr", &self.arr)
.field("vec", &self.vec)
.finish()
}
}
impl<T: Debug, const N: usize> Display for ComboVec<T, N> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_list().entries(self.arr.iter()).entries(&self.vec).finish()
}
}