Merge pull request #177 from bluss/length-32-bit
Use u32 for the length field in arrayvec
This commit is contained in:
+5
-1
@@ -10,7 +10,11 @@ Recent Changes (arrayvec)
|
|||||||
|
|
||||||
The New type syntax is `ArrayVec<T, CAP>` where `CAP` is the arrayvec capacity.
|
The New type syntax is `ArrayVec<T, CAP>` where `CAP` is the arrayvec capacity.
|
||||||
For arraystring the syntax is `ArrayString<CAP>`.
|
For arraystring the syntax is `ArrayString<CAP>`.
|
||||||
Change by @bluss.
|
|
||||||
|
Length is stored internally as u32; this limits the maximum capacity. The size
|
||||||
|
of the `ArrayVec` or `ArrayString` structs for the same capacity may grow
|
||||||
|
slightly compared with the previous version (depending on padding requirements
|
||||||
|
for the element type). Change by @bluss.
|
||||||
|
|
||||||
- Arrayvec's `.extend()` and `FromIterator`/`.collect()` to arrayvec now
|
- Arrayvec's `.extend()` and `FromIterator`/`.collect()` to arrayvec now
|
||||||
**panic** if the capacity of the arrayvec is exceeded. Change by @bluss.
|
**panic** if the capacity of the arrayvec is exceeded. Change by @bluss.
|
||||||
|
|||||||
+15
-6
@@ -12,15 +12,20 @@ use std::str::FromStr;
|
|||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
use crate::CapacityError;
|
use crate::CapacityError;
|
||||||
|
use crate::LenUint;
|
||||||
use crate::char::encode_utf8;
|
use crate::char::encode_utf8;
|
||||||
|
|
||||||
#[cfg(feature="serde")]
|
#[cfg(feature="serde")]
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
|
|
||||||
/// A string with a fixed capacity.
|
/// A string with a fixed capacity.
|
||||||
///
|
///
|
||||||
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
|
/// 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
|
/// The string is a contiguous value that you can store directly on the stack
|
||||||
/// if needed.
|
/// if needed.
|
||||||
@@ -28,7 +33,7 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
|||||||
pub struct ArrayString<const CAP: usize> {
|
pub struct ArrayString<const CAP: usize> {
|
||||||
// the `len` first elements of the array are initialized
|
// the `len` first elements of the array are initialized
|
||||||
xs: [MaybeUninit<u8>; CAP],
|
xs: [MaybeUninit<u8>; CAP],
|
||||||
len: usize,
|
len: LenUint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CAP: usize> Default for ArrayString<CAP>
|
impl<const CAP: usize> Default for ArrayString<CAP>
|
||||||
@@ -55,6 +60,7 @@ impl<const CAP: usize> ArrayString<CAP>
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature="unstable-const-fn"))]
|
#[cfg(not(feature="unstable-const-fn"))]
|
||||||
pub fn new() -> ArrayString<CAP> {
|
pub fn new() -> ArrayString<CAP> {
|
||||||
|
assert_capacity_limit!(CAP);
|
||||||
unsafe {
|
unsafe {
|
||||||
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||||
}
|
}
|
||||||
@@ -62,6 +68,7 @@ impl<const CAP: usize> ArrayString<CAP>
|
|||||||
|
|
||||||
#[cfg(feature="unstable-const-fn")]
|
#[cfg(feature="unstable-const-fn")]
|
||||||
pub const fn new() -> ArrayString<CAP> {
|
pub const fn new() -> ArrayString<CAP> {
|
||||||
|
assert_capacity_limit!(CAP);
|
||||||
unsafe {
|
unsafe {
|
||||||
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||||
}
|
}
|
||||||
@@ -69,7 +76,7 @@ impl<const CAP: usize> ArrayString<CAP>
|
|||||||
|
|
||||||
/// Return the length of the string.
|
/// Return the length of the string.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> usize { self.len }
|
pub fn len(&self) -> usize { self.len as usize }
|
||||||
|
|
||||||
/// Returns whether the string is empty.
|
/// Returns whether the string is empty.
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -347,8 +354,9 @@ impl<const CAP: usize> ArrayString<CAP>
|
|||||||
/// This method uses *debug assertions* to check the validity of `length`
|
/// This method uses *debug assertions* to check the validity of `length`
|
||||||
/// and may use other debug assertions.
|
/// and may use other debug assertions.
|
||||||
pub unsafe fn set_len(&mut self, length: usize) {
|
pub unsafe fn set_len(&mut self, length: usize) {
|
||||||
|
// type invariant that capacity always fits in LenUint
|
||||||
debug_assert!(length <= self.capacity());
|
debug_assert!(length <= self.capacity());
|
||||||
self.len = length;
|
self.len = length as LenUint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a string slice of the whole `ArrayString`.
|
/// Return a string slice of the whole `ArrayString`.
|
||||||
@@ -371,7 +379,7 @@ impl<const CAP: usize> Deref for ArrayString<CAP>
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &str {
|
fn deref(&self) -> &str {
|
||||||
unsafe {
|
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)
|
str::from_utf8_unchecked(sl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,7 +390,8 @@ impl<const CAP: usize> DerefMut for ArrayString<CAP>
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut str {
|
fn deref_mut(&mut self) -> &mut str {
|
||||||
unsafe {
|
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)
|
str::from_utf8_unchecked_mut(sl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-12
@@ -20,6 +20,7 @@ use std::mem::MaybeUninit;
|
|||||||
#[cfg(feature="serde")]
|
#[cfg(feature="serde")]
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
|
use crate::LenUint;
|
||||||
use crate::errors::CapacityError;
|
use crate::errors::CapacityError;
|
||||||
use crate::arrayvec_impl::ArrayVecImpl;
|
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
|
/// the number of initialized elements. The `ArrayVec<T, CAP>` is parameterized
|
||||||
/// by `T` for the element type and `CAP` for the maximum capacity.
|
/// 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 vector is a contiguous value (storing the elements inline) that you can store directly on
|
||||||
/// the stack if needed.
|
/// the stack if needed.
|
||||||
///
|
///
|
||||||
/// It offers a simple API but also dereferences to a slice, so
|
/// It offers a simple API but also dereferences to a slice, so that the full slice API is
|
||||||
/// that the full slice API is available.
|
/// available. The ArrayVec can be converted into a by value iterator.
|
||||||
///
|
|
||||||
/// ArrayVec can be converted into a by value iterator.
|
|
||||||
pub struct ArrayVec<T, const CAP: usize> {
|
pub struct ArrayVec<T, const CAP: usize> {
|
||||||
// the `len` first elements of the array are initialized
|
// the `len` first elements of the array are initialized
|
||||||
xs: [MaybeUninit<T>; CAP],
|
xs: [MaybeUninit<T>; CAP],
|
||||||
len: usize,
|
len: LenUint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const CAP: usize> Drop for ArrayVec<T, CAP> {
|
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"))]
|
#[cfg(not(feature="unstable-const-fn"))]
|
||||||
pub fn new() -> ArrayVec<T, CAP> {
|
pub fn new() -> ArrayVec<T, CAP> {
|
||||||
|
assert_capacity_limit!(CAP);
|
||||||
unsafe {
|
unsafe {
|
||||||
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
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")]
|
#[cfg(feature="unstable-const-fn")]
|
||||||
pub const fn new() -> ArrayVec<T, CAP> {
|
pub const fn new() -> ArrayVec<T, CAP> {
|
||||||
|
assert_capacity_limit!(CAP);
|
||||||
unsafe {
|
unsafe {
|
||||||
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
|
||||||
}
|
}
|
||||||
@@ -97,7 +101,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
|||||||
/// array.pop();
|
/// array.pop();
|
||||||
/// assert_eq!(array.len(), 2);
|
/// assert_eq!(array.len(), 2);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn len(&self) -> usize { self.len as usize }
|
pub fn len(&self) -> usize { self.len as usize }
|
||||||
|
|
||||||
/// Returns whether the `ArrayVec` is empty.
|
/// 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
|
/// This method uses *debug assertions* to check that `length` is
|
||||||
/// not greater than the capacity.
|
/// not greater than the capacity.
|
||||||
pub unsafe fn set_len(&mut self, length: usize) {
|
pub unsafe fn set_len(&mut self, length: usize) {
|
||||||
|
// type invariant that capacity always fits in LenUint
|
||||||
debug_assert!(length <= self.capacity());
|
debug_assert!(length <= self.capacity());
|
||||||
self.len = length;
|
self.len = length as LenUint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy all elements from the slice and append to the `ArrayVec`.
|
/// 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
|
// Calling `set_len` creates a fresh and thus unique mutable references, making all
|
||||||
// older aliases we created invalid. So we cannot call that function.
|
// older aliases we created invalid. So we cannot call that function.
|
||||||
self.len = start;
|
self.len = start as LenUint;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Drain {
|
Drain {
|
||||||
@@ -626,7 +631,7 @@ impl<T, const CAP: usize> ArrayVecImpl for ArrayVec<T, CAP> {
|
|||||||
|
|
||||||
unsafe fn set_len(&mut self, length: usize) {
|
unsafe fn set_len(&mut self, length: usize) {
|
||||||
debug_assert!(length <= CAP);
|
debug_assert!(length <= CAP);
|
||||||
self.len = length;
|
self.len = length as LenUint;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_ptr(&self) -> *const Self::Item {
|
fn as_ptr(&self) -> *const Self::Item {
|
||||||
@@ -769,7 +774,7 @@ impl<T, const CAP: usize> Iterator for IntoIter<T, CAP> {
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.index == self.v.len {
|
if self.index == self.v.len() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
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> {
|
impl<T, const CAP: usize> DoubleEndedIterator for IntoIter<T, CAP> {
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
if self.index == self.v.len {
|
if self.index == self.v.len() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -963,7 +968,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
|
|||||||
value: &mut self.len,
|
value: &mut self.len,
|
||||||
data: len,
|
data: len,
|
||||||
f: move |&len, self_len| {
|
f: move |&len, self_len| {
|
||||||
**self_len = len;
|
**self_len = len as LenUint;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut iter = iterable.into_iter();
|
let mut iter = iterable.into_iter();
|
||||||
|
|||||||
+15
-3
@@ -1,4 +1,4 @@
|
|||||||
//! **arrayvec** provides the types `ArrayVec` and `ArrayString`:
|
//! **arrayvec** provides the types [`ArrayVec`] and [`ArrayString`]:
|
||||||
//! array-backed vector and string types, which store their contents inline.
|
//! array-backed vector and string types, which store their contents inline.
|
||||||
//!
|
//!
|
||||||
//! The arrayvec package has the following cargo features:
|
//! The arrayvec package has the following cargo features:
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
//!
|
//!
|
||||||
//! This version of arrayvec requires Rust 1.51 or later.
|
//! This version of arrayvec requires Rust 1.51 or later.
|
||||||
//!
|
//!
|
||||||
#![doc(html_root_url="https://docs.rs/arrayvec/0.5/")]
|
#![doc(html_root_url="https://docs.rs/arrayvec/0.6/")]
|
||||||
#![cfg_attr(not(feature="std"), no_std)]
|
#![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")]
|
#[cfg(feature="serde")]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
@@ -31,6 +31,18 @@ extern crate serde;
|
|||||||
#[cfg(not(feature="std"))]
|
#[cfg(not(feature="std"))]
|
||||||
extern crate core as 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_impl;
|
||||||
mod arrayvec;
|
mod arrayvec;
|
||||||
mod array_string;
|
mod array_string;
|
||||||
|
|||||||
+19
-3
@@ -295,17 +295,17 @@ fn test_compact_size() {
|
|||||||
// 4 bytes + padding + length
|
// 4 bytes + padding + length
|
||||||
type ByteArray = ArrayVec<u8, 4>;
|
type ByteArray = ArrayVec<u8, 4>;
|
||||||
println!("{}", mem::size_of::<ByteArray>());
|
println!("{}", mem::size_of::<ByteArray>());
|
||||||
assert!(mem::size_of::<ByteArray>() <= 2 * mem::size_of::<usize>());
|
assert!(mem::size_of::<ByteArray>() <= 2 * mem::size_of::<u32>());
|
||||||
|
|
||||||
// just length
|
// just length
|
||||||
type EmptyArray = ArrayVec<u8, 0>;
|
type EmptyArray = ArrayVec<u8, 0>;
|
||||||
println!("{}", mem::size_of::<EmptyArray>());
|
println!("{}", mem::size_of::<EmptyArray>());
|
||||||
assert!(mem::size_of::<EmptyArray>() <= mem::size_of::<usize>());
|
assert!(mem::size_of::<EmptyArray>() <= mem::size_of::<u32>());
|
||||||
|
|
||||||
// 3 elements + padding + length
|
// 3 elements + padding + length
|
||||||
type QuadArray = ArrayVec<u32, 3>;
|
type QuadArray = ArrayVec<u32, 3>;
|
||||||
println!("{}", mem::size_of::<QuadArray>());
|
println!("{}", mem::size_of::<QuadArray>());
|
||||||
assert!(mem::size_of::<QuadArray>() <= 4 * 4 + mem::size_of::<usize>());
|
assert!(mem::size_of::<QuadArray>() <= 4 * 4 + mem::size_of::<u32>());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -711,3 +711,19 @@ fn test_try_from_argument() {
|
|||||||
let v = ArrayString::<16>::try_from(format_args!("Hello {}", 123)).unwrap();
|
let v = ArrayString::<16>::try_from(format_args!("Hello {}", 123)).unwrap();
|
||||||
assert_eq!(&v, "Hello 123");
|
assert_eq!(&v, "Hello 123");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn allow_max_capacity_arrayvec_type() {
|
||||||
|
// this type is allowed to be used (but can't be constructed)
|
||||||
|
let _v: ArrayVec<(), {usize::MAX}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[should_panic(expected="ArrayVec: largest supported")]
|
||||||
|
#[test]
|
||||||
|
fn deny_max_capacity_arrayvec_value() {
|
||||||
|
if mem::size_of::<usize>() <= mem::size_of::<u32>() {
|
||||||
|
panic!("This test does not work on this platform. 'ArrayVec: largest supported'");
|
||||||
|
}
|
||||||
|
// this type is allowed to be used (but can't be constructed)
|
||||||
|
let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user