Partial work on ArrayishVec

This commit is contained in:
Lokathor
2020-01-07 23:10:38 -07:00
parent 662bade020
commit 7e47b7132d
7 changed files with 724 additions and 68 deletions
+7 -1
View File
@@ -12,8 +12,14 @@ categories = ["data-structures", "no-std"]
# not even std!
[features]
default = []
default = ["extern_crate_alloc"]
# Provide additional types and impls related to the `alloc` trait.
extern_crate_alloc = []
[badges]
appveyor = { repository = "Lokathor/tinyvec" }
travis-ci = { repository = "Lokathor/tinyvec" }
[package.metadata.docs.rs]
all-features = true
+13
View File
@@ -5,6 +5,19 @@
[![crates.io](https://img.shields.io/crates/v/tinyvec.svg)](https://crates.io/crates/tinyvec)
[![docs.rs](https://docs.rs/tinyvec/badge.svg)](https://docs.rs/tinyvec/)
![Unsafe-Zero-Percent](https://img.shields.io/badge/Unsafety-0%-green.svg)
# tinyvec
Just, really the littlest Vec you could need. So smol.
This is one of those crates where an initial small number of elements will be
kept on the stack, and then if you overflow that it will quietly transition
everything into being a totally normal `alloc::vec::Vec`.
What sets this crate apart from others like it is that it has
`#![forbid(unsafe_code)]` right at the top, and then requires that the element
type have a `Default` impl. This is a slight restriction compared to a normal
`Vec`, but that's still [a very large number of
types](https://doc.rust-lang.org/std/default/trait.Default.html#implementors)
that you can use.
+49
View File
@@ -0,0 +1,49 @@
/// A trait for types that can be the backing store of an [`ArrayishVec`].
///
/// You are not generally expected to need to implement this yourself. You can
/// if you want I guess. Impls are provided for arrays of length `0..=32`, 33,
/// and powers of 2 up to 4096. Additional lengths can probably be added upon
/// request.
///
/// ## Safety
///
/// As a reminder, the `Arrayish` trait is 100% safe so unsafe code **must not**
/// rely on an instance of the trait being correct.
pub trait Arrayish {
/// The type of the items in the thing.
type Item: Default;
/// The number of slots in the thing.
const CAPACITY: usize;
/// Gives a shared slice over the whole thing.
fn slice(&self) -> &[Self::Item];
/// Gives a unique slice over the whole thing.
fn slice_mut(&mut self) -> &mut [Self::Item];
}
macro_rules! impl_arrayish_for_len {
($($len:expr),+ $(,)?) => {
$(impl<T: Default> Arrayish for [T; $len] {
type Item = T;
const CAPACITY: usize = $len;
#[inline(always)]
fn slice(&self) -> &[T] {
&*self
}
#[inline(always)]
fn slice_mut(&mut self) -> &mut [T] {
&mut *self
}
})+
}
}
impl_arrayish_for_len! {
0, /* The oft-forgotten 0-length array! */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, /* for luck */
64, 128, 256, 512, 1024, 2048, 4096,
}
+535
View File
@@ -0,0 +1,535 @@
use super::*;
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct ArrayishVec<A: Arrayish> {
len: usize,
data: A,
}
impl<A: Arrayish> Deref for ArrayishVec<A> {
type Target = [A::Item];
#[inline(always)]
#[must_use]
fn deref(&self) -> &Self::Target {
&self.data.slice()[..self.len]
}
}
impl<A: Arrayish> DerefMut for ArrayishVec<A> {
#[inline(always)]
#[must_use]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data.slice_mut()[..self.len]
}
}
impl<A: Arrayish> Index<usize> for ArrayishVec<A> {
type Output = A::Item;
#[inline(always)]
#[must_use]
fn index(&self, index: usize) -> &Self::Output {
&self.deref()[index]
}
}
impl<A: Arrayish> IndexMut<usize> for ArrayishVec<A> {
#[inline(always)]
#[must_use]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.deref_mut()[index]
}
}
impl<A: Arrayish> ArrayishVec<A> {
// TODO(Vec): append
#[inline(always)]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut A::Item {
self.data.slice_mut().as_mut_ptr()
}
#[inline(always)]
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [A::Item] {
self.deref_mut()
}
#[inline(always)]
#[must_use]
pub fn as_ptr(&self) -> *const A::Item {
self.data.slice().as_ptr()
}
#[inline(always)]
#[must_use]
pub fn as_slice(&self) -> &[A::Item] {
self.deref()
}
#[inline(always)]
#[must_use]
pub fn capacity(&self) -> usize {
A::CAPACITY
}
#[inline(always)]
pub fn clear(&mut self) {
self.truncate(0)
}
// TODO(Vec): dedup
// TODO(Vec): dedup_by
// TODO(Vec): dedup_by_key
// TODO(Vec): drain
// TODO(Vec): drain_filter #nightly
// TODO(Vec): extend_from_slice
#[inline]
#[must_use]
pub fn from_array_len(data: A, len: usize) -> Self {
if len <= A::CAPACITY {
Self { data, len }
} else {
panic!(
"ArrayishVec: len {} is greater than capacity {}!",
len,
A::CAPACITY
);
}
}
// TODO(Vec): insert
#[inline(always)]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
#[must_use]
pub fn len(&self) -> usize {
self.len
}
#[inline(always)]
#[must_use]
pub fn new() -> Self
where
A: Default,
{
Self::default()
}
#[inline]
pub fn pop(&mut self) -> Option<A::Item> {
if self.len > 0 {
self.len -= 1;
let out =
replace(&mut self.data.slice_mut()[self.len], A::Item::default());
Some(out)
} else {
None
}
}
#[inline]
pub fn push(&mut self, val: A::Item) {
if self.len < A::CAPACITY {
replace(&mut self.data.slice_mut()[self.len], val);
self.len += 1;
} else {
panic!("ArrayVec: overflow!")
}
}
// TODO(Vec): remove
// TODO(Vec): remove_item
// TODO(Vec): resize
// TODO(Vec): resize_default
// TODO(Vec): resize_with
// TODO(Vec): retain
// TODO(Vec): splice
// TODO(Vec): split_off
// TODO(Vec): swap_remove
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if needs_drop::<A::Item>() {
while self.len > new_len {
self.pop();
}
} else {
self.len = new_len;
}
}
// TODO: try_from_array_len
// TODO: try_push
}
impl<A: Arrayish> AsMut<[A::Item]> for ArrayishVec<A> {
#[inline(always)]
#[must_use]
fn as_mut(&mut self) -> &mut [A::Item] {
&mut *self
}
}
impl<A: Arrayish> AsRef<[A::Item]> for ArrayishVec<A> {
#[inline(always)]
#[must_use]
fn as_ref(&self) -> &[A::Item] {
&*self
}
}
impl<A: Arrayish> Borrow<[A::Item]> for ArrayishVec<A> {
#[inline(always)]
#[must_use]
fn borrow(&self) -> &[A::Item] {
&*self
}
}
impl<A: Arrayish> BorrowMut<[A::Item]> for ArrayishVec<A> {
#[inline(always)]
#[must_use]
fn borrow_mut(&mut self) -> &mut [A::Item] {
&mut *self
}
}
// TODO(Vec): Extend<&'a T>
// TODO(Vec): Extend<T>
impl<A: Arrayish> From<A> for ArrayishVec<A> {
#[inline(always)]
#[must_use]
/// The output has a length equal to the full array.
fn from(data: A) -> Self {
Self { len: data.slice().len(), data }
}
}
// TODO(Vec): From<&'a [T]>
// TODO(Vec): From<&'a mut [T]>
// TODO(Vec): From<&'_ str>
// TODO(Vec): From<&'a Vec<T>>
// TODO(Vec): From<BinaryHeap<T>>
// TODO(Vec): From<Box<[T]>>
// TODO(Vec): From<Cow<'a, [T]>>
// TODO(Vec): From<String>
// TODO(Vec): From<Vec<T>>
// TODO(Vec): From<VecDeque<T>>
impl<A: Arrayish + Default> FromIterator<A::Item> for ArrayishVec<A> {
#[must_use]
fn from_iter<T: IntoIterator<Item = A::Item>>(iter: T) -> Self {
let mut av = Self::default();
for i in iter {
av.push(i)
}
av
}
}
// TODO(Vec): Index<I: SliceIndex>
// TODO(Vec): IndexMut<I: SliceIndex>
pub struct ArrayishVecIterator<A: Arrayish> {
base: usize,
len: usize,
data: A,
}
impl<A: Arrayish> Iterator for ArrayishVecIterator<A> {
type Item = A::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.base < self.len {
let out =
replace(&mut self.data.slice_mut()[self.base], A::Item::default());
self.base += 1;
Some(out)
} else {
None
}
}
#[inline(always)]
#[must_use]
fn size_hint(&self) -> (usize, Option<usize>) {
let s = self.len - self.base;
(s, Some(s))
}
#[inline(always)]
fn count(self) -> usize {
self.len - self.base
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
Some(replace(&mut self.data.slice_mut()[self.len], A::Item::default()))
}
#[inline]
fn nth(&mut self, n: usize) -> Option<A::Item> {
let i = self.base + (n - 1);
if i < self.len {
let out = replace(&mut self.data.slice_mut()[i], A::Item::default());
self.base = i + 1;
Some(out)
} else {
None
}
}
}
impl<A: Arrayish> IntoIterator for ArrayishVec<A> {
type Item = A::Item;
type IntoIter = ArrayishVecIterator<A>;
#[inline(always)]
#[must_use]
fn into_iter(self) -> Self::IntoIter {
ArrayishVecIterator { base: 0, len: self.len, data: self.data }
}
}
impl<A: Arrayish> PartialEq for ArrayishVec<A>
where
A::Item: PartialEq,
{
#[inline(always)]
#[must_use]
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl<A: Arrayish> Eq for ArrayishVec<A> where A::Item: Eq {}
impl<A: Arrayish> PartialEq<&A> for ArrayishVec<A>
where
A::Item: PartialEq,
{
#[inline(always)]
#[must_use]
fn eq(&self, other: &&A) -> bool {
self.deref() == other.slice()
}
}
impl<A: Arrayish> PartialEq<&[A::Item]> for ArrayishVec<A>
where
A::Item: PartialEq,
{
#[inline(always)]
#[must_use]
fn eq(&self, other: &&[A::Item]) -> bool {
self.deref() == *other
}
}
impl<A: Arrayish> PartialEq<&mut [A::Item]> for ArrayishVec<A>
where
A::Item: PartialEq,
{
#[inline(always)]
#[must_use]
fn eq(&self, other: &&mut [A::Item]) -> bool {
self.deref() == *other
}
}
// TODO: PartialOrd, Ord, Hash
// //
// Formatting impls
// //
impl<A: Arrayish> Binary for ArrayishVec<A>
where
A::Item: Binary,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
Binary::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> Debug for ArrayishVec<A>
where
A::Item: Debug,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
Debug::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> Display for ArrayishVec<A>
where
A::Item: Display,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
Display::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> LowerExp for ArrayishVec<A>
where
A::Item: LowerExp,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
LowerExp::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> LowerHex for ArrayishVec<A>
where
A::Item: LowerHex,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
LowerHex::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> Octal for ArrayishVec<A>
where
A::Item: Octal,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
Octal::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> Pointer for ArrayishVec<A>
where
A::Item: Pointer,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
Pointer::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> UpperExp for ArrayishVec<A>
where
A::Item: UpperExp,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
UpperExp::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
impl<A: Arrayish> UpperHex for ArrayishVec<A>
where
A::Item: UpperHex,
{
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
if self.len == 0 {
write!(f, "[]")
} else {
write!(f, "[")?;
let oxford = self.len - 1;
for (i, elem) in self.iter().enumerate() {
UpperHex::fmt(elem, f)?;
if i < oxford {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
+21 -2
View File
@@ -4,12 +4,29 @@
//! Just, really the littlest Vec you could need. So smol.
use core::{
borrow::{Borrow, BorrowMut},
cmp::PartialEq,
convert::AsMut,
default::Default,
fmt::{
Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, Pointer,
UpperExp, UpperHex,
},
iter::{FromIterator, IntoIterator, Iterator},
mem::{needs_drop, replace},
ops::{Deref, DerefMut},
ops::{Deref, DerefMut, Index, IndexMut},
};
#[cfg(feature = "extern_crate_alloc")]
extern crate alloc;
use alloc::vec::Vec;
mod arrayish;
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
@@ -118,3 +135,5 @@ impl<T: Default> TinyVec<T> {
}
}
}
*/
-65
View File
@@ -1,65 +0,0 @@
#![allow(bad_style)]
extern crate tinyvec;
use tinyvec::*;
extern crate core;
use core::ops::Deref;
#[test]
fn TinyVec_push_pop() {
let mut tv = TinyVec::new();
assert_eq!(tv.pop(), None);
tv.push(5_i32);
assert_eq!(tv.pop(), Some(5_i32));
assert_eq!(tv.len(), 0);
for i in 0..10 {
tv.push(i);
}
assert_eq!(tv.len(), 10);
assert_eq!(tv.pop(), Some(9));
assert_eq!(tv.pop(), Some(8));
assert_eq!(tv.pop(), Some(7));
assert_eq!(tv.pop(), Some(6));
assert_eq!(tv.pop(), Some(5));
assert_eq!(tv.pop(), Some(4));
assert_eq!(tv.pop(), Some(3));
assert_eq!(tv.pop(), Some(2));
assert_eq!(tv.pop(), Some(1));
assert_eq!(tv.pop(), Some(0));
assert_eq!(tv.pop(), None);
assert_eq!(tv.pop(), None);
assert_eq!(tv.pop(), None);
}
#[test]
fn TinyVec_truncate() {
// Truncating a five element vector to two elements
let mut tv = TinyVec::new();
tv.push(1_i32);
tv.push(2);
tv.push(3);
tv.push(4);
tv.push(5);
tv.truncate(2);
assert_eq!(tv.deref(), [1, 2]);
// No truncation occurs when len is greater than the vector's current length
let mut tv = TinyVec::new();
tv.push(1_i32);
tv.push(2);
tv.push(3);
tv.truncate(8);
assert_eq!(tv.deref(), [1, 2, 3]);
// Truncating when len == 0 is equivalent to calling the clear method.
let mut tv = TinyVec::new();
tv.push(1_i32);
tv.push(2);
tv.push(3);
tv.truncate(0);
assert_eq!(tv.deref(), []);
}
+99
View File
@@ -0,0 +1,99 @@
#![allow(bad_style)]
use tinyvec::*;
#[test]
fn ArrayishVec_push_pop() {
let mut av: ArrayishVec<[i32; 4]> = Default::default();
assert_eq!(av.len(), 0);
assert_eq!(av.pop(), None);
av.push(10_i32);
assert_eq!(av.len(), 1);
assert_eq!(av[0], 10);
assert_eq!(av.pop(), Some(10));
assert_eq!(av.len(), 0);
assert_eq!(av.pop(), None);
av.push(10);
av.push(11);
av.push(12);
av.push(13);
assert_eq!(av[0], 10);
assert_eq!(av[1], 11);
assert_eq!(av[2], 12);
assert_eq!(av[3], 13);
assert_eq!(av.len(), 4);
assert_eq!(av.pop(), Some(13));
assert_eq!(av.len(), 3);
assert_eq!(av.pop(), Some(12));
assert_eq!(av.len(), 2);
assert_eq!(av.pop(), Some(11));
assert_eq!(av.len(), 1);
assert_eq!(av.pop(), Some(10));
assert_eq!(av.len(), 0);
assert_eq!(av.pop(), None);
}
#[test]
#[should_panic]
fn ArrayishVec_push_overflow() {
let mut av: ArrayishVec<[i32; 0]> = Default::default();
av.push(7);
}
#[test]
fn ArrayishVec_formatting() {
// check that we get the comma placement correct
let mut av: ArrayishVec<[i32; 4]> = Default::default();
assert_eq!(format!("{:?}", av), "[]");
av.push(10);
assert_eq!(format!("{:?}", av), "[10]");
av.push(11);
assert_eq!(format!("{:?}", av), "[10, 11]");
av.push(12);
assert_eq!(format!("{:?}", av), "[10, 11, 12]");
// below here just asserts that the impls exist.
//
let av: ArrayishVec<[i32; 4]> = Default::default();
assert_eq!(format!("{:b}", av), "[]");
assert_eq!(format!("{:o}", av), "[]");
assert_eq!(format!("{:x}", av), "[]");
assert_eq!(format!("{:X}", av), "[]");
assert_eq!(format!("{}", av), "[]");
//
let av: ArrayishVec<[f32; 4]> = Default::default();
assert_eq!(format!("{:e}", av), "[]");
assert_eq!(format!("{:E}", av), "[]");
//
let av: ArrayishVec<[&'static str; 4]> = Default::default();
assert_eq!(format!("{:p}", av), "[]");
}
#[test]
fn ArrayishVec_iteration() {
let mut av: ArrayishVec<[i32; 4]> = Default::default();
av.push(10);
av.push(11);
av.push(12);
av.push(13);
let mut i = av.into_iter();
assert_eq!(i.next(), Some(10));
assert_eq!(i.next(), Some(11));
assert_eq!(i.next(), Some(12));
assert_eq!(i.next(), Some(13));
assert_eq!(i.next(), None);
let mut av: ArrayishVec<[i32; 4]> = Default::default();
av.push(10);
av.push(11);
av.push(12);
av.push(13);
let av2: ArrayishVec<[i32; 4]> = av.clone().into_iter().collect();
assert_eq!(av, av2);
}