Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor VZV code to center on (and Deref to) VarZeroSlice; make VZVBorrowed private #1418

Merged
merged 19 commits into from
Dec 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions components/plurals/src/rules/runtime/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ mod serde {
let string: String = self.to_string();
serializer.serialize_str(&string)
} else {
serializer.serialize_bytes(self.0.as_encoded_bytes())
serializer.serialize_bytes(self.0.as_bytes())
}
}
}
Expand Down Expand Up @@ -634,7 +634,7 @@ mod test {
let relations = alloc::vec![relation];
let vzv = VarZeroVec::from(relations.as_slice());
assert_eq!(
vzv.as_encoded_bytes(),
vzv.as_bytes(),
&[1, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]
);
}
Expand Down
10 changes: 5 additions & 5 deletions utils/zerovec/benches/vzv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn overview_bench(c: &mut Criterion) {
// Same as vzv/char_count/vzv but with different inputs
let seed = 42;
let (string_vec, _) = random_alphanums(2..=10, 100, seed);
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_encoded_bytes();
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();

c.bench_function("vzv/overview", |b| {
Expand Down Expand Up @@ -73,7 +73,7 @@ fn overview_bench(c: &mut Criterion) {
fn char_count_benches(c: &mut Criterion) {
let seed = 2021;
let (string_vec, _) = random_alphanums(2..=20, 100, seed);
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_encoded_bytes();
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();

// *** Count chars in vec of 100 strings ***
Expand All @@ -100,7 +100,7 @@ fn binary_search_benches(c: &mut Criterion) {
let seed = 2021;
let (string_vec, seed) = random_alphanums(2..=20, 500, seed);
let (needles, _) = random_alphanums(2..=20, 10, seed);
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_encoded_bytes();
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();
let single_needle = "lmnop".to_string();

Expand Down Expand Up @@ -165,9 +165,9 @@ fn vzv_precompute_bench(c: &mut Criterion) {
let seed = 2021;
let (string_vec, seed) = random_alphanums(2..=20, 500, seed);
let (needles, _) = random_alphanums(2..=20, 10, seed);
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_encoded_bytes();
let bytes: Vec<u8> = VarZeroVec::<str>::from(&string_vec).into_bytes();
let vzv = VarZeroVec::<str>::parse_byte_slice(black_box(bytes.as_slice())).unwrap();
let borrowed = vzv.as_borrowed();
let borrowed = vzv.as_components();
let slice = vzv.as_slice();
let single_needle = "lmnop".to_string();

Expand Down
31 changes: 14 additions & 17 deletions utils/zerovec/src/map/vecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

use crate::ule::*;
use crate::varzerovec::owned::VarZeroVecOwned;
use crate::varzerovec::VarZeroVecBorrowed;
use crate::VarZeroVec;
use crate::{VarZeroSlice, VarZeroVec};
use crate::{ZeroSlice, ZeroVec};
use alloc::boxed::Box;
use alloc::vec::Vec;
Expand Down Expand Up @@ -283,25 +282,24 @@ where
}
}

impl<'a, T> ZeroVecLike<'a, T> for VarZeroVecBorrowed<'a, T>
impl<'a, T> ZeroVecLike<'a, T> for &'a VarZeroSlice<T>
where
T: VarULE,
T: Ord,
T: ?Sized,
{
type GetType = T;
fn zvl_new() -> Self {
Self::new()
VarZeroSlice::new_empty()
}
fn zvl_binary_search(&self, k: &T) -> Result<usize, usize> {
Self::binary_search(self, k)
self.binary_search(k)
}
fn zvl_get(&self, index: usize) -> Option<&T> {
// using UFCS to avoid accidental recursion
Self::get(*self, index)
self.get(index)
}
fn zvl_len(&self) -> usize {
Self::len(*self)
self.len()
}
fn zvl_is_ascending(&self) -> bool {
if !self.is_empty() {
Expand All @@ -326,15 +324,14 @@ where
}
}

impl<'a, T> BorrowedZeroVecLike<'a, T> for VarZeroVecBorrowed<'a, T>
impl<'a, T> BorrowedZeroVecLike<'a, T> for &'a VarZeroSlice<T>
where
T: VarULE,
T: Ord,
T: ?Sized,
{
fn zvl_get_borrowed(&self, index: usize) -> Option<&'a T> {
// using UFCS to avoid accidental recursion
Self::get(*self, index)
self.get(index)
}
}

Expand All @@ -345,7 +342,7 @@ where
T: ?Sized,
{
type OwnedType = Box<T>;
type BorrowedVariant = VarZeroVecBorrowed<'a, T>;
type BorrowedVariant = &'a VarZeroSlice<T>;
fn zvl_insert(&mut self, index: usize, value: &T) {
self.make_mut().insert(index, value)
}
Expand Down Expand Up @@ -374,18 +371,18 @@ where
fn zvl_reserve(&mut self, addl: usize) {
self.make_mut().reserve(addl)
}
fn zvl_as_borrowed(&'a self) -> VarZeroVecBorrowed<'a, T> {
self.as_borrowed()
fn zvl_as_borrowed(&'a self) -> &'a VarZeroSlice<T> {
self.as_slice()
}
fn zvl_as_borrowed_inner(&self) -> Option<VarZeroVecBorrowed<'a, T>> {
fn zvl_as_borrowed_inner(&self) -> Option<&'a VarZeroSlice<T>> {
if let VarZeroVec::Borrowed(b) = *self {
Some(b)
} else {
None
}
}
fn zvl_from_borrowed(b: VarZeroVecBorrowed<'a, T>) -> Self {
VarZeroVec::Borrowed(b)
fn zvl_from_borrowed(b: &'a VarZeroSlice<T>) -> Self {
b.as_varzerovec()
}

fn owned_as_t(o: &Self::OwnedType) -> &T {
Expand Down
10 changes: 5 additions & 5 deletions utils/zerovec/src/ule/custom/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,11 @@ where

fn encode_var_ule_len(&self) -> usize {
// TODO(#1410): Rethink length errors in VZV.
crate::varzerovec::borrowed::compute_serializable_len(self).unwrap() as usize
crate::varzerovec::components::compute_serializable_len(self).unwrap() as usize
}

fn encode_var_ule_write(&self, dst: &mut [u8]) {
crate::varzerovec::borrowed::write_serializable_bytes(self, dst)
crate::varzerovec::components::write_serializable_bytes(self, dst)
}
}

Expand Down Expand Up @@ -228,13 +228,13 @@ where

#[inline]
fn encode_var_ule_len(&self) -> usize {
self.as_encoded_bytes().len()
self.as_bytes().len()
}

#[inline]
fn encode_var_ule_write(&self, dst: &mut [u8]) {
debug_assert_eq!(self.as_encoded_bytes().len(), dst.len());
dst.copy_from_slice(self.as_encoded_bytes());
debug_assert_eq!(self.as_bytes().len(), dst.len());
dst.copy_from_slice(self.as_bytes());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@ fn usizeify(x: RawBytesULE<4>) -> usize {
u32::from_unaligned(x) as usize
}

/// A fully-borrowed [`VarZeroVec`]. This type has the same internal buffer representation
/// of [`VarZeroVec`], making it cheaply convertible to [`VarZeroVec`] and [`VarZeroVecOwned`];
/// however, unlike those two, it cannot be mutated.
/// A more parsed version of `VarZeroSlice`. This type is where most of the VarZeroVec
/// internal representation code lies.
///
/// This is *basically* an `&'a [u8]` to a zero copy buffer, but split out into
/// the buffer components. Logically this is capable of behaving as
/// a `&'a [T::VarULE]`, but since `T::VarULE` is unsized that type does not actually
/// exist.
///
/// See [`VarZeroVecBorrowed::parse_byte_slice()`] for information on the internal invariants involved
pub struct VarZeroVecBorrowed<'a, T: ?Sized> {
/// See [`VarZeroVecComponents::parse_byte_slice()`] for information on the internal invariants involved
pub struct VarZeroVecComponents<'a, T: ?Sized> {
/// The list of indices into the `things` slice
indices: &'a [RawBytesULE<4>],
/// The contiguous list of `T::VarULE`s
Expand All @@ -37,10 +36,10 @@ pub struct VarZeroVecBorrowed<'a, T: ?Sized> {

// #[derive()] won't work here since we do not want it to be
// bound on T: Copy
impl<'a, T: ?Sized> Copy for VarZeroVecBorrowed<'a, T> {}
impl<'a, T: ?Sized> Clone for VarZeroVecBorrowed<'a, T> {
impl<'a, T: ?Sized> Copy for VarZeroVecComponents<'a, T> {}
impl<'a, T: ?Sized> Clone for VarZeroVecComponents<'a, T> {
fn clone(&self) -> Self {
VarZeroVecBorrowed {
VarZeroVecComponents {
indices: self.indices,
things: self.things,
entire_slice: self.entire_slice,
Expand All @@ -49,27 +48,14 @@ impl<'a, T: ?Sized> Clone for VarZeroVecBorrowed<'a, T> {
}
}

impl<'a, T: VarULE + ?Sized> Default for VarZeroVecBorrowed<'a, T> {
impl<'a, T: VarULE + ?Sized> Default for VarZeroVecComponents<'a, T> {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
/// Creates a new, empty `VarZeroVecBorrowed<T>`.
///
/// Note: Since [`VarZeroVecBorrowed`] is not mutable, the return value will be a stub unless
/// wrapped in [`VarZeroVec::Borrowed`].
///
/// # Examples
///
/// ```
/// use zerovec::varzerovec::VarZeroVecBorrowed;
///
/// let vzv: VarZeroVecBorrowed<str> = VarZeroVecBorrowed::new();
/// assert!(vzv.is_empty());
/// ```
impl<'a, T: VarULE + ?Sized> VarZeroVecComponents<'a, T> {
#[inline]
pub fn new() -> Self {
Self {
Expand All @@ -80,7 +66,7 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
}
}

/// Construct a new VarZeroVecBorrowed, checking invariants about the overall buffer size:
/// Construct a new VarZeroVecComponents, checking invariants about the overall buffer size:
///
/// - There must be either zero or at least four bytes (if four, this is the "length" parsed as a usize)
/// - There must be at least `4*length + 4` bytes total, to form the the array `indices` of indices
Expand All @@ -91,7 +77,7 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
#[inline]
pub fn parse_byte_slice(slice: &'a [u8]) -> Result<Self, ZeroVecError> {
if slice.is_empty() {
return Ok(VarZeroVecBorrowed {
return Ok(VarZeroVecComponents {
indices: &[],
things: &[],
entire_slice: slice,
Expand All @@ -113,7 +99,7 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
.get(4 * len + 4..)
.ok_or(ZeroVecError::VarZeroVecFormatError)?;

let borrowed = VarZeroVecBorrowed {
let borrowed = VarZeroVecComponents {
indices,
things,
entire_slice: slice,
Expand All @@ -127,17 +113,17 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
Ok(borrowed)
}

/// Construct a [`VarZeroVecBorrowed`] from a byte slice that has previously
/// successfully returned a [`VarZeroVecBorrowed`] when passed to
/// [`VarZeroVecBorrowed::parse_byte_slice()`]. Will return the same
/// object as one would get from calling [`VarZeroVecBorrowed::parse_byte_slice()`].
/// Construct a [`VarZeroVecComponents`] from a byte slice that has previously
/// successfully returned a [`VarZeroVecComponents`] when passed to
/// [`VarZeroVecComponents::parse_byte_slice()`]. Will return the same
/// object as one would get from calling [`VarZeroVecComponents::parse_byte_slice()`].
///
/// # Safety
/// The bytes must have previously successfully run through
/// [`VarZeroVecBorrowed::parse_byte_slice()`]
/// [`VarZeroVecComponents::parse_byte_slice()`]
pub unsafe fn from_bytes_unchecked(slice: &'a [u8]) -> Self {
if slice.is_empty() {
return VarZeroVecBorrowed {
return VarZeroVecComponents {
indices: &[],
things: &[],
entire_slice: slice,
Expand All @@ -152,7 +138,7 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
let indices = RawBytesULE::<4>::from_byte_slice_unchecked(indices_bytes);
let things = slice.get_unchecked(4 * len + 4..);

VarZeroVecBorrowed {
VarZeroVecComponents {
indices,
things,
entire_slice: slice,
Expand All @@ -172,12 +158,6 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
self.indices.is_empty()
}

/// Get a reference to the entire backing buffer of this vector
#[inline]
pub fn as_encoded_bytes(self) -> &'a [u8] {
self.entire_slice
}

/// Get the idx'th element out of this slice. Returns `None` if out of bounds.
#[inline]
pub fn get(self, idx: usize) -> Option<&'a T> {
Expand All @@ -204,15 +184,15 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
T::from_byte_slice_unchecked(things_slice)
}

/// Create an iterator over the Ts contained in VarZeroVecBorrowed, checking internal invariants:
/// Create an iterator over the Ts contained in VarZeroVecComponents, checking internal invariants:
///
/// - `indices[i]..indices[i+1]` must index into a valid section of
/// `things`, such that it parses to a `T::VarULE`
/// - `indices[len - 1]..things.len()` must index into a valid section of
/// `things`, such that it parses to a `T::VarULE`
/// - `indices` is monotonically increasing
///
/// This method is NOT allowed to call any other methods on VarZeroVecBorrowed since all other methods
/// This method is NOT allowed to call any other methods on VarZeroVecComponents since all other methods
/// assume that the slice has been passed through iter_checked
#[inline]
fn iter_checked(self) -> impl Iterator<Item = Result<&'a T, ZeroVecError>> {
Expand Down Expand Up @@ -244,7 +224,7 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
.map(|s| s.and_then(|s| T::parse_byte_slice(s)))
}

/// Create an iterator over the Ts contained in VarZeroVecBorrowed
/// Create an iterator over the Ts contained in VarZeroVecComponents
#[inline]
pub fn iter(self) -> impl Iterator<Item = &'a T> {
let last = iter::from_fn(move || {
Expand Down Expand Up @@ -281,17 +261,17 @@ impl<'a, T: VarULE + ?Sized> VarZeroVecBorrowed<'a, T> {
.copied()
.map(u32::from_unaligned)
.collect::<Vec<_>>();
format!("VarZeroVecBorrowed {{ indices: {:?} }}", indices)
format!("VarZeroVecComponents {{ indices: {:?} }}", indices)
}
}

impl<'a, T> VarZeroVecBorrowed<'a, T>
impl<'a, T> VarZeroVecComponents<'a, T>
where
T: VarULE,
T: ?Sized,
T: Ord,
{
/// Binary searches a sorted `VarZeroVecBorrowed<T>` for the given element. For more information, see
/// Binary searches a sorted `VarZeroVecComponents<T>` for the given element. For more information, see
/// the primitive function [`binary_search`](slice::binary_search).
pub fn binary_search(&self, needle: &T) -> Result<usize, usize> {
// This code is an absolute atrocity. This code is not a place of honor. This
Expand Down
Loading