Skip to content

Commit

Permalink
Refactor VZV code to center on (and Deref to) VarZeroSlice; make VZVB…
Browse files Browse the repository at this point in the history
…orrowed private (#1418)
  • Loading branch information
Manishearth authored Dec 20, 2021
1 parent 988f246 commit 66b2081
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 398 deletions.
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

0 comments on commit 66b2081

Please sign in to comment.