diff --git a/Cargo.toml b/Cargo.toml index ccee8a1..18a2fd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,18 +5,23 @@ version = "0.0.1-alpha.0" authors = ["Lokathor "] edition = "2018" license = "Zlib" -keywords = ["vec", "no_std", "smol"] +keywords = ["vec", "no_std", "no-std", "smol"] categories = ["data-structures", "no-std"] [dependencies] # not even std! [features] -default = ["extern_crate_alloc"] +default = ["extern_crate_alloc", "nightly_slice_partition_dedup"] -# Provide additional types and impls related to the `alloc` trait. +# Provide additional types and impls related to the `alloc` crate. extern_crate_alloc = [] +# allow use of nightly feature `slice_partition_dedup`, +# will become useless once that is stabilized: +# https://github.com/rust-lang/rust/issues/54279 +nightly_slice_partition_dedup = [] + [badges] appveyor = { repository = "Lokathor/tinyvec" } travis-ci = { repository = "Lokathor/tinyvec" } diff --git a/src/arrayish_vec.rs b/src/arrayish_vec.rs index 9a98c2c..271d0a8 100644 --- a/src/arrayish_vec.rs +++ b/src/arrayish_vec.rs @@ -24,19 +24,19 @@ impl DerefMut for ArrayishVec { } } -impl Index for ArrayishVec { - type Output = A::Item; +impl> Index for ArrayishVec { + type Output = >::Output; #[inline(always)] #[must_use] - fn index(&self, index: usize) -> &Self::Output { + fn index(&self, index: I) -> &Self::Output { &self.deref()[index] } } -impl IndexMut for ArrayishVec { +impl> IndexMut for ArrayishVec { #[inline(always)] #[must_use] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { + fn index_mut(&mut self, index: I) -> &mut Self::Output { &mut self.deref_mut()[index] } } @@ -49,7 +49,8 @@ impl ArrayishVec { panic!("ArrayishVec: overflow!"); } let target_slice = &mut self.data.slice_mut()[self.len..final_len]; - for (target_mut, app_mut) in target_slice.iter_mut().zip(other.deref_mut()) { + for (target_mut, app_mut) in target_slice.iter_mut().zip(other.deref_mut()) + { replace(target_mut, replace(app_mut, A::Item::default())); } self.len = final_len; @@ -91,9 +92,38 @@ impl ArrayishVec { self.truncate(0) } - // TODO(Vec): dedup - // TODO(Vec): dedup_by - // TODO(Vec): dedup_by_key + #[cfg(feature = "nightly_slice_partition_dedup")] + #[inline(always)] + pub fn dedup(&mut self) + where + A::Item: PartialEq, + { + self.dedup_by(|a, b| a == b) + } + + #[cfg(feature = "nightly_slice_partition_dedup")] + #[inline(always)] + pub fn dedup_by(&mut self, same_bucket: F) + where + F: FnMut(&mut A::Item, &mut A::Item) -> bool, + { + let len = { + let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket); + dedup.len() + }; + self.truncate(len); + } + + #[cfg(feature = "nightly_slice_partition_dedup")] + #[inline(always)] + pub fn dedup_by_key(&mut self, mut key: F) + where + F: FnMut(&mut A::Item) -> K, + K: PartialEq, + { + self.dedup_by(|a, b| key(a) == key(b)) + } + // TODO(Vec): drain // TODO(Vec): drain_filter #nightly @@ -256,8 +286,13 @@ impl BorrowMut<[A::Item]> for ArrayishVec { } } -// TODO(Vec): Extend<&'a T> -// TODO(Vec): Extend +impl Extend for ArrayishVec { + fn extend>(&mut self, iter: T) { + for t in iter { + self.push(t) + } + } +} impl From for ArrayishVec { #[inline(always)] @@ -281,9 +316,6 @@ impl FromIterator for ArrayishVec { } } -// TODO(Vec): Index -// TODO(Vec): IndexMut - pub struct ArrayishVecIterator { base: usize, len: usize, @@ -343,19 +375,40 @@ impl PartialEq for ArrayishVec where A::Item: PartialEq, { - #[inline(always)] + #[inline] #[must_use] fn eq(&self, other: &Self) -> bool { - self.deref() == other.deref() + self.deref().eq(other.deref()) } } impl Eq for ArrayishVec where A::Item: Eq {} +impl PartialOrd for ArrayishVec +where + A::Item: PartialOrd, +{ + #[inline] + #[must_use] + fn partial_cmp(&self, other: &Self) -> Option { + self.deref().partial_cmp(other.deref()) + } +} +impl Ord for ArrayishVec +where + A::Item: Ord, +{ + #[inline] + #[must_use] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.deref().cmp(other.deref()) + } +} + impl PartialEq<&A> for ArrayishVec where A::Item: PartialEq, { - #[inline(always)] + #[inline] #[must_use] fn eq(&self, other: &&A) -> bool { self.deref() == other.slice() @@ -366,25 +419,31 @@ impl PartialEq<&[A::Item]> for ArrayishVec where A::Item: PartialEq, { - #[inline(always)] + #[inline] #[must_use] fn eq(&self, other: &&[A::Item]) -> bool { self.deref() == *other } } +/* + +I think, in retrospect, this is useless? + +The `&mut [A::Item]` should coerce to `&[A::Item]` and use the above impl. +I'll leave it here for now though since we already had it written out.. + impl PartialEq<&mut [A::Item]> for ArrayishVec where A::Item: PartialEq, { - #[inline(always)] + #[inline] #[must_use] fn eq(&self, other: &&mut [A::Item]) -> bool { self.deref() == *other } } - -// TODO: PartialOrd, Ord, Hash +*/ // // // Formatting impls diff --git a/src/lib.rs b/src/lib.rs index 4ce789d..9c36ea3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,9 @@ #![no_std] #![forbid(unsafe_code)] +#![cfg_attr( + feature = "nightly_slice_partition_dedup", + feature(slice_partition_dedup) +)] //! Just, really the littlest Vec you could need. So smol. @@ -12,9 +16,10 @@ use core::{ Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex, }, - iter::{FromIterator, IntoIterator, Iterator}, + iter::{Extend, FromIterator, IntoIterator, Iterator}, mem::{needs_drop, replace}, ops::{Deref, DerefMut, Index, IndexMut}, + slice::SliceIndex, }; #[cfg(feature = "extern_crate_alloc")] @@ -25,115 +30,3 @@ pub use arrayish::*; mod arrayish_vec; pub use arrayish_vec::*; - -/* - -// Note(Lokathor): We just want to hide the enum details away. Rust doesn't let -// you be an enum with private variants, so instead we make this be a private -// inner field of the public `TinyVec` type. -#[derive(Debug, Clone)] -enum Payload { - Inline { len: usize, data: [T; 8] }, - Heap(Vec), -} - -/// A `TinyVec` is like a `Vec`, but it will store up to 8 elements -/// "inline" on the stack before transitioning into being a normal `Vec`. -#[derive(Debug, Clone)] -#[repr(transparent)] -pub struct TinyVec(Payload); - -// TODO: impl a better Debug - -impl Default for TinyVec { - fn default() -> Self { - Self::new() - } -} - -impl Deref for TinyVec { - type Target = [T]; - fn deref(&self) -> &[T] { - match &self.0 { - Payload::Inline { len, data } => &data[..*len], - Payload::Heap(vec) => &vec, - } - } -} - -impl DerefMut for TinyVec { - fn deref_mut(&mut self) -> &mut [T] { - match &mut self.0 { - Payload::Inline { len, data } => &mut data[..*len], - Payload::Heap(ref mut vec) => &mut vec[..], - } - } -} - -impl TinyVec { - pub fn new() -> Self { - Self(Payload::Inline { - len: 0, - data: [ - T::default(), - T::default(), - T::default(), - T::default(), - T::default(), - T::default(), - T::default(), - T::default(), - ], - }) - } - - pub fn push(&mut self, val: T) { - match &mut self.0 { - Payload::Inline { len: 8, data } => { - let mut v = Vec::with_capacity(8 + 10); - for data_mut in data.iter_mut() { - v.push(replace(data_mut, T::default())); - } - v.push(val); - replace(&mut self.0, Payload::Heap(v)); - } - Payload::Inline { len, data } => { - debug_assert!(*len < 8, "push: illegal len: {}", len); - data[*len] = val; - *len += 1; - } - Payload::Heap(ref mut vec) => vec.push(val), - } - } - - pub fn pop(&mut self) -> Option { - match &mut self.0 { - Payload::Inline { len: 0, .. } => None, - Payload::Inline { len, data } => { - debug_assert!(*len > 0, "pop: illegal len: {}", len); - let out = replace(&mut data[*len - 1], T::default()); - *len -= 1; - Some(out) - } - Payload::Heap(ref mut vec) => vec.pop(), - } - } - - pub fn truncate(&mut self, new_len: usize) { - match &mut self.0 { - Payload::Inline { len, data } => { - if needs_drop::() { - while *len > new_len { - replace(&mut data[*len - 1], T::default()); - *len -= 1; - } - } else { - *len = (*len).min(new_len); - } - } - Payload::Heap(ref mut vec) => vec.truncate(new_len), - } - } -} - -*/