FEAT: Use u32 for the length field in arrayvec
Store the length as u32 internally. This is to shrink the size of the ArrayVec value (when possible, depending on element type). Inline storage vectors larger than u32::MAX are very unlikely to be useful - for these cases, prefer using Vec instead. It's not possible to have the CAP type parameter be of type u32 (missing features in const evaluation/const generics). We also have to panic at runtime instead of having a static assertion for capacity, for similar reasons.
This commit is contained in:
+15
-6
@@ -12,15 +12,20 @@ use std::str::FromStr;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use crate::CapacityError;
|
||||
use crate::LenUint;
|
||||
use crate::char::encode_utf8;
|
||||
|
||||
#[cfg(feature="serde")]
|
||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
|
||||
|
||||
/// A string with a fixed capacity.
|
||||
///
|
||||
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
|
||||
/// of its length.
|
||||
/// of its length, and is parameterized by `CAP` for the maximum capacity.
|
||||
///
|
||||
/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger
|
||||
/// arrayvecs with larger capacity will panic.
|
||||
///
|
||||
/// The string is a contiguous value that you can store directly on the stack
|
||||
/// if needed.
|
||||
@@ -28,7 +33,7 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
pub struct ArrayString<const CAP: usize> {
|
||||
// the `len` first elements of the array are initialized
|
||||
xs: [MaybeUninit<u8>; CAP],
|
||||
len: usize,
|
||||
len: LenUint,
|
||||
}
|
||||
|
||||
impl<const CAP: usize> Default for ArrayString<CAP>
|
||||
@@ -55,6 +60,7 @@ impl<const CAP: usize> ArrayString<CAP>
|
||||
/// ```
|
||||
#[cfg(not(feature="unstable-const-fn"))]
|
||||
pub fn new() -> ArrayString<CAP> {
|
||||
assert_capacity_limit!(CAP);
|
||||
unsafe {
|
||||
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||
}
|
||||
@@ -62,6 +68,7 @@ impl<const CAP: usize> ArrayString<CAP>
|
||||
|
||||
#[cfg(feature="unstable-const-fn")]
|
||||
pub const fn new() -> ArrayString<CAP> {
|
||||
assert_capacity_limit!(CAP);
|
||||
unsafe {
|
||||
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||
}
|
||||
@@ -69,7 +76,7 @@ impl<const CAP: usize> ArrayString<CAP>
|
||||
|
||||
/// Return the length of the string.
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.len }
|
||||
pub fn len(&self) -> usize { self.len as usize }
|
||||
|
||||
/// Returns whether the string is empty.
|
||||
#[inline]
|
||||
@@ -347,8 +354,9 @@ impl<const CAP: usize> ArrayString<CAP>
|
||||
/// This method uses *debug assertions* to check the validity of `length`
|
||||
/// and may use other debug assertions.
|
||||
pub unsafe fn set_len(&mut self, length: usize) {
|
||||
// type invariant that capacity always fits in LenUint
|
||||
debug_assert!(length <= self.capacity());
|
||||
self.len = length;
|
||||
self.len = length as LenUint;
|
||||
}
|
||||
|
||||
/// Return a string slice of the whole `ArrayString`.
|
||||
@@ -371,7 +379,7 @@ impl<const CAP: usize> Deref for ArrayString<CAP>
|
||||
#[inline]
|
||||
fn deref(&self) -> &str {
|
||||
unsafe {
|
||||
let sl = slice::from_raw_parts(self.as_ptr(), self.len);
|
||||
let sl = slice::from_raw_parts(self.as_ptr(), self.len());
|
||||
str::from_utf8_unchecked(sl)
|
||||
}
|
||||
}
|
||||
@@ -382,7 +390,8 @@ impl<const CAP: usize> DerefMut for ArrayString<CAP>
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut str {
|
||||
unsafe {
|
||||
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), self.len);
|
||||
let len = self.len();
|
||||
let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), len);
|
||||
str::from_utf8_unchecked_mut(sl)
|
||||
}
|
||||
}
|
||||
|
||||
+17
-12
@@ -20,6 +20,7 @@ use std::mem::MaybeUninit;
|
||||
#[cfg(feature="serde")]
|
||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
|
||||
use crate::LenUint;
|
||||
use crate::errors::CapacityError;
|
||||
use crate::arrayvec_impl::ArrayVecImpl;
|
||||
|
||||
@@ -29,17 +30,18 @@ use crate::arrayvec_impl::ArrayVecImpl;
|
||||
/// the number of initialized elements. The `ArrayVec<T, CAP>` is parameterized
|
||||
/// by `T` for the element type and `CAP` for the maximum capacity.
|
||||
///
|
||||
/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger
|
||||
/// arrayvecs with larger capacity will panic.
|
||||
///
|
||||
/// The vector is a contiguous value (storing the elements inline) that you can store directly on
|
||||
/// the stack if needed.
|
||||
///
|
||||
/// It offers a simple API but also dereferences to a slice, so
|
||||
/// that the full slice API is available.
|
||||
///
|
||||
/// ArrayVec can be converted into a by value iterator.
|
||||
/// It offers a simple API but also dereferences to a slice, so that the full slice API is
|
||||
/// available. The ArrayVec can be converted into a by value iterator.
|
||||
pub struct ArrayVec<T, const CAP: usize> {
|
||||
// the `len` first elements of the array are initialized
|
||||
xs: [MaybeUninit<T>; CAP],
|
||||
len: usize,
|
||||
len: LenUint,
|
||||
}
|
||||
|
||||
impl<T, const CAP: usize> Drop for ArrayVec<T, CAP> {
|
||||
@@ -76,6 +78,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
||||
/// ```
|
||||
#[cfg(not(feature="unstable-const-fn"))]
|
||||
pub fn new() -> ArrayVec<T, CAP> {
|
||||
assert_capacity_limit!(CAP);
|
||||
unsafe {
|
||||
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||
}
|
||||
@@ -83,6 +86,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
||||
|
||||
#[cfg(feature="unstable-const-fn")]
|
||||
pub const fn new() -> ArrayVec<T, CAP> {
|
||||
assert_capacity_limit!(CAP);
|
||||
unsafe {
|
||||
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||
}
|
||||
@@ -97,7 +101,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
||||
/// array.pop();
|
||||
/// assert_eq!(array.len(), 2);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize { self.len as usize }
|
||||
|
||||
/// Returns whether the `ArrayVec` is empty.
|
||||
@@ -475,8 +479,9 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
||||
/// This method uses *debug assertions* to check that `length` is
|
||||
/// not greater than the capacity.
|
||||
pub unsafe fn set_len(&mut self, length: usize) {
|
||||
// type invariant that capacity always fits in LenUint
|
||||
debug_assert!(length <= self.capacity());
|
||||
self.len = length;
|
||||
self.len = length as LenUint;
|
||||
}
|
||||
|
||||
/// Copy all elements from the slice and append to the `ArrayVec`.
|
||||
@@ -569,7 +574,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
||||
|
||||
// Calling `set_len` creates a fresh and thus unique mutable references, making all
|
||||
// older aliases we created invalid. So we cannot call that function.
|
||||
self.len = start;
|
||||
self.len = start as LenUint;
|
||||
|
||||
unsafe {
|
||||
Drain {
|
||||
@@ -626,7 +631,7 @@ impl<T, const CAP: usize> ArrayVecImpl for ArrayVec<T, CAP> {
|
||||
|
||||
unsafe fn set_len(&mut self, length: usize) {
|
||||
debug_assert!(length <= CAP);
|
||||
self.len = length;
|
||||
self.len = length as LenUint;
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> *const Self::Item {
|
||||
@@ -769,7 +774,7 @@ impl<T, const CAP: usize> Iterator for IntoIter<T, CAP> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index == self.v.len {
|
||||
if self.index == self.v.len() {
|
||||
None
|
||||
} else {
|
||||
unsafe {
|
||||
@@ -788,7 +793,7 @@ impl<T, const CAP: usize> Iterator for IntoIter<T, CAP> {
|
||||
|
||||
impl<T, const CAP: usize> DoubleEndedIterator for IntoIter<T, CAP> {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.index == self.v.len {
|
||||
if self.index == self.v.len() {
|
||||
None
|
||||
} else {
|
||||
unsafe {
|
||||
@@ -963,7 +968,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
||||
value: &mut self.len,
|
||||
data: len,
|
||||
f: move |&len, self_len| {
|
||||
**self_len = len;
|
||||
**self_len = len as LenUint;
|
||||
}
|
||||
};
|
||||
let mut iter = iterable.into_iter();
|
||||
|
||||
+13
-1
@@ -23,7 +23,7 @@
|
||||
//!
|
||||
#![doc(html_root_url="https://docs.rs/arrayvec/0.5/")]
|
||||
#![cfg_attr(not(feature="std"), no_std)]
|
||||
#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init))]
|
||||
#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init, const_panic))]
|
||||
|
||||
#[cfg(feature="serde")]
|
||||
extern crate serde;
|
||||
@@ -31,6 +31,18 @@ extern crate serde;
|
||||
#[cfg(not(feature="std"))]
|
||||
extern crate core as std;
|
||||
|
||||
pub(crate) type LenUint = u32;
|
||||
|
||||
macro_rules! assert_capacity_limit {
|
||||
($cap:expr) => {
|
||||
if std::mem::size_of::<usize>() > std::mem::size_of::<LenUint>() {
|
||||
if CAP > LenUint::MAX as usize {
|
||||
panic!("ArrayVec: largest supported capacity is u32::MAX")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod arrayvec_impl;
|
||||
mod arrayvec;
|
||||
mod array_string;
|
||||
|
||||
Reference in New Issue
Block a user