| // This file is part of ICU4X. For terms of use, please see the file |
| // called LICENSE at the top level of the ICU4X source tree |
| // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
| |
| use crate::ule::*; |
| use crate::varzerovec::owned::VarZeroVecOwned; |
| use crate::vecs::{FlexZeroSlice, FlexZeroVec, FlexZeroVecOwned, VarZeroVecFormat}; |
| use crate::{VarZeroSlice, VarZeroVec}; |
| use crate::{ZeroSlice, ZeroVec}; |
| use alloc::boxed::Box; |
| use alloc::vec::Vec; |
| use core::cmp::Ordering; |
| use core::mem; |
| use core::ops::Range; |
| |
| /// Trait abstracting over [`ZeroVec`] and [`VarZeroVec`], for use in [`ZeroMap`](super::ZeroMap). **You |
| /// should not be implementing or calling this trait directly.** |
| /// |
| /// The T type is the type received by [`Self::zvl_binary_search()`], as well as the one used |
| /// for human-readable serialization. |
| /// |
| /// Methods are prefixed with `zvl_*` to avoid clashes with methods on the types themselves |
| pub trait ZeroVecLike<T: ?Sized> { |
| /// The type returned by `Self::get()` |
| type GetType: ?Sized + 'static; |
| /// A fully borrowed version of this |
| type SliceVariant: ZeroVecLike<T, GetType = Self::GetType> + ?Sized; |
| |
| /// Create a new, empty borrowed variant |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant; |
| |
| /// Search for a key in a sorted vector, returns `Ok(index)` if found, |
| /// returns `Err(insert_index)` if not found, where `insert_index` is the |
| /// index where it should be inserted to maintain sort order. |
| fn zvl_binary_search(&self, k: &T) -> Result<usize, usize> |
| where |
| T: Ord; |
| /// Search for a key within a certain range in a sorted vector. |
| /// Returns `None` if the range is out of bounds, and |
| /// `Ok` or `Err` in the same way as `zvl_binary_search`. |
| /// Indices are returned relative to the start of the range. |
| fn zvl_binary_search_in_range( |
| &self, |
| k: &T, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> |
| where |
| T: Ord; |
| |
| /// Search for a key in a sorted vector by a predicate, returns `Ok(index)` if found, |
| /// returns `Err(insert_index)` if not found, where `insert_index` is the |
| /// index where it should be inserted to maintain sort order. |
| fn zvl_binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize>; |
| /// Search for a key within a certain range in a sorted vector by a predicate. |
| /// Returns `None` if the range is out of bounds, and |
| /// `Ok` or `Err` in the same way as `zvl_binary_search`. |
| /// Indices are returned relative to the start of the range. |
| fn zvl_binary_search_in_range_by( |
| &self, |
| predicate: impl FnMut(&T) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>>; |
| |
| /// Get element at `index` |
| fn zvl_get(&self, index: usize) -> Option<&Self::GetType>; |
| /// The length of this vector |
| fn zvl_len(&self) -> usize; |
| /// Check if this vector is in ascending order according to `T`s `Ord` impl |
| fn zvl_is_ascending(&self) -> bool |
| where |
| T: Ord, |
| { |
| if let Some(first) = self.zvl_get(0) { |
| let mut prev = first; |
| for i in 1..self.zvl_len() { |
| #[allow(clippy::unwrap_used)] // looping over the valid indices |
| let curr = self.zvl_get(i).unwrap(); |
| if Self::get_cmp_get(prev, curr) != Ordering::Less { |
| return false; |
| } |
| prev = curr; |
| } |
| } |
| true |
| } |
| /// Check if this vector is empty |
| fn zvl_is_empty(&self) -> bool { |
| self.zvl_len() == 0 |
| } |
| |
| /// Construct a borrowed variant by borrowing from `&self`. |
| /// |
| /// This function behaves like `&'b self -> Self::SliceVariant<'b>`, |
| /// where `'b` is the lifetime of the reference to this object. |
| /// |
| /// Note: We rely on the compiler recognizing `'a` and `'b` as covariant and |
| /// casting `&'b Self<'a>` to `&'b Self<'b>` when this gets called, which works |
| /// out for `ZeroVec` and `VarZeroVec` containers just fine. |
| fn zvl_as_borrowed(&self) -> &Self::SliceVariant; |
| |
| /// Compare this type with a `Self::GetType`. This must produce the same result as |
| /// if `g` were converted to `Self` |
| #[inline] |
| fn t_cmp_get(t: &T, g: &Self::GetType) -> Ordering |
| where |
| T: Ord, |
| { |
| Self::zvl_get_as_t(g, |g| t.cmp(g)) |
| } |
| |
| /// Compare two values of `Self::GetType`. This must produce the same result as |
| /// if both `a` and `b` were converted to `Self` |
| #[inline] |
| fn get_cmp_get(a: &Self::GetType, b: &Self::GetType) -> Ordering |
| where |
| T: Ord, |
| { |
| Self::zvl_get_as_t(a, |a| Self::zvl_get_as_t(b, |b| a.cmp(b))) |
| } |
| |
| /// Obtain a reference to T, passed to a closure |
| /// |
| /// This uses a callback because it's not possible to return owned-or-borrowed |
| /// types without GATs |
| /// |
| /// Impls should guarantee that the callback function is be called exactly once. |
| fn zvl_get_as_t<R>(g: &Self::GetType, f: impl FnOnce(&T) -> R) -> R; |
| } |
| |
| /// Trait abstracting over [`ZeroVec`] and [`VarZeroVec`], for use in [`ZeroMap`](super::ZeroMap). **You |
| /// should not be implementing or calling this trait directly.** |
| /// |
| /// This trait augments [`ZeroVecLike`] with methods allowing for mutation of the underlying |
| /// vector for owned vector types. |
| /// |
| /// Methods are prefixed with `zvl_*` to avoid clashes with methods on the types themselves |
| pub trait MutableZeroVecLike<'a, T: ?Sized>: ZeroVecLike<T> { |
| /// The type returned by `Self::remove()` and `Self::replace()` |
| type OwnedType; |
| |
| /// Insert an element at `index` |
| fn zvl_insert(&mut self, index: usize, value: &T); |
| /// Remove the element at `index` (panicking if nonexistant) |
| fn zvl_remove(&mut self, index: usize) -> Self::OwnedType; |
| /// Replace the element at `index` with another one, returning the old element |
| fn zvl_replace(&mut self, index: usize, value: &T) -> Self::OwnedType; |
| /// Push an element to the end of this vector |
| fn zvl_push(&mut self, value: &T); |
| /// Create a new, empty vector, with given capacity |
| fn zvl_with_capacity(cap: usize) -> Self; |
| /// Remove all elements from the vector |
| fn zvl_clear(&mut self); |
| /// Reserve space for `addl` additional elements |
| fn zvl_reserve(&mut self, addl: usize); |
| /// Applies the permutation such that `before.zvl_get(permutation[i]) == after.zvl_get(i)`. |
| /// |
| /// # Panics |
| /// If `permutation` is not a valid permutation of length `zvl_len()`. |
| fn zvl_permute(&mut self, permutation: &mut [usize]); |
| |
| /// Convert an owned value to a borrowed T |
| fn owned_as_t(o: &Self::OwnedType) -> &T; |
| |
| /// Construct from the borrowed version of the type |
| /// |
| /// These are useful to ensure serialization parity between borrowed and owned versions |
| fn zvl_from_borrowed(b: &'a Self::SliceVariant) -> Self; |
| /// Extract the inner borrowed variant if possible. Returns `None` if the data is owned. |
| /// |
| /// This function behaves like `&'_ self -> Self::SliceVariant<'a>`, |
| /// where `'a` is the lifetime of this object's borrowed data. |
| /// |
| /// This function is similar to matching the `Borrowed` variant of `ZeroVec` |
| /// or `VarZeroVec`, returning the inner borrowed type. |
| fn zvl_as_borrowed_inner(&self) -> Option<&'a Self::SliceVariant>; |
| } |
| |
| impl<'a, T> ZeroVecLike<T> for ZeroVec<'a, T> |
| where |
| T: 'a + AsULE + Copy, |
| { |
| type GetType = T::ULE; |
| type SliceVariant = ZeroSlice<T>; |
| |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant { |
| ZeroSlice::<T>::new_empty() |
| } |
| fn zvl_binary_search(&self, k: &T) -> Result<usize, usize> |
| where |
| T: Ord, |
| { |
| ZeroSlice::binary_search(self, k) |
| } |
| fn zvl_binary_search_in_range(&self, k: &T, range: Range<usize>) -> Option<Result<usize, usize>> |
| where |
| T: Ord, |
| { |
| let zs: &ZeroSlice<T> = self; |
| zs.zvl_binary_search_in_range(k, range) |
| } |
| fn zvl_binary_search_by( |
| &self, |
| mut predicate: impl FnMut(&T) -> Ordering, |
| ) -> Result<usize, usize> { |
| ZeroSlice::binary_search_by(self, |probe| predicate(&probe)) |
| } |
| fn zvl_binary_search_in_range_by( |
| &self, |
| predicate: impl FnMut(&T) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| let zs: &ZeroSlice<T> = self; |
| zs.zvl_binary_search_in_range_by(predicate, range) |
| } |
| fn zvl_get(&self, index: usize) -> Option<&T::ULE> { |
| self.get_ule_ref(index) |
| } |
| fn zvl_len(&self) -> usize { |
| ZeroSlice::len(self) |
| } |
| fn zvl_as_borrowed(&self) -> &ZeroSlice<T> { |
| self |
| } |
| #[inline] |
| fn zvl_get_as_t<R>(g: &Self::GetType, f: impl FnOnce(&T) -> R) -> R { |
| f(&T::from_unaligned(*g)) |
| } |
| } |
| |
| impl<T> ZeroVecLike<T> for ZeroSlice<T> |
| where |
| T: AsULE + Copy, |
| { |
| type GetType = T::ULE; |
| type SliceVariant = ZeroSlice<T>; |
| |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant { |
| ZeroSlice::<T>::new_empty() |
| } |
| fn zvl_binary_search(&self, k: &T) -> Result<usize, usize> |
| where |
| T: Ord, |
| { |
| ZeroSlice::binary_search(self, k) |
| } |
| fn zvl_binary_search_in_range(&self, k: &T, range: Range<usize>) -> Option<Result<usize, usize>> |
| where |
| T: Ord, |
| { |
| let subslice = self.get_subslice(range)?; |
| Some(ZeroSlice::binary_search(subslice, k)) |
| } |
| fn zvl_binary_search_by( |
| &self, |
| mut predicate: impl FnMut(&T) -> Ordering, |
| ) -> Result<usize, usize> { |
| ZeroSlice::binary_search_by(self, |probe| predicate(&probe)) |
| } |
| fn zvl_binary_search_in_range_by( |
| &self, |
| mut predicate: impl FnMut(&T) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| let subslice = self.get_subslice(range)?; |
| Some(ZeroSlice::binary_search_by(subslice, |probe| { |
| predicate(&probe) |
| })) |
| } |
| fn zvl_get(&self, index: usize) -> Option<&T::ULE> { |
| self.get_ule_ref(index) |
| } |
| fn zvl_len(&self) -> usize { |
| ZeroSlice::len(self) |
| } |
| fn zvl_as_borrowed(&self) -> &ZeroSlice<T> { |
| self |
| } |
| |
| #[inline] |
| fn zvl_get_as_t<R>(g: &Self::GetType, f: impl FnOnce(&T) -> R) -> R { |
| f(&T::from_unaligned(*g)) |
| } |
| } |
| |
| impl<'a, T> MutableZeroVecLike<'a, T> for ZeroVec<'a, T> |
| where |
| T: AsULE + Copy + 'static, |
| { |
| type OwnedType = T; |
| fn zvl_insert(&mut self, index: usize, value: &T) { |
| self.with_mut(|v| v.insert(index, value.to_unaligned())) |
| } |
| fn zvl_remove(&mut self, index: usize) -> T { |
| T::from_unaligned(self.with_mut(|v| v.remove(index))) |
| } |
| fn zvl_replace(&mut self, index: usize, value: &T) -> T { |
| #[allow(clippy::indexing_slicing)] |
| let unaligned = self.with_mut(|vec| { |
| debug_assert!(index < vec.len()); |
| mem::replace(&mut vec[index], value.to_unaligned()) |
| }); |
| T::from_unaligned(unaligned) |
| } |
| fn zvl_push(&mut self, value: &T) { |
| self.with_mut(|v| v.push(value.to_unaligned())) |
| } |
| fn zvl_with_capacity(cap: usize) -> Self { |
| if cap == 0 { |
| ZeroVec::new() |
| } else { |
| ZeroVec::new_owned(Vec::with_capacity(cap)) |
| } |
| } |
| fn zvl_clear(&mut self) { |
| self.with_mut(|v| v.clear()) |
| } |
| fn zvl_reserve(&mut self, addl: usize) { |
| self.with_mut(|v| v.reserve(addl)) |
| } |
| |
| fn owned_as_t(o: &Self::OwnedType) -> &T { |
| o |
| } |
| |
| fn zvl_from_borrowed(b: &'a ZeroSlice<T>) -> Self { |
| b.as_zerovec() |
| } |
| fn zvl_as_borrowed_inner(&self) -> Option<&'a ZeroSlice<T>> { |
| self.as_maybe_borrowed() |
| } |
| |
| #[allow(clippy::indexing_slicing)] // documented panic |
| fn zvl_permute(&mut self, permutation: &mut [usize]) { |
| assert_eq!(permutation.len(), self.zvl_len()); |
| |
| let vec = self.to_mut_slice(); |
| |
| for cycle_start in 0..permutation.len() { |
| let mut curr = cycle_start; |
| let mut next = permutation[curr]; |
| |
| while next != cycle_start { |
| vec.swap(curr, next); |
| // Make curr a self-cycle so we don't use it as a cycle_start later |
| permutation[curr] = curr; |
| curr = next; |
| next = permutation[next]; |
| } |
| permutation[curr] = curr; |
| } |
| } |
| } |
| |
| impl<'a, T, F> ZeroVecLike<T> for VarZeroVec<'a, T, F> |
| where |
| T: VarULE, |
| T: ?Sized, |
| F: VarZeroVecFormat, |
| { |
| type GetType = T; |
| type SliceVariant = VarZeroSlice<T, F>; |
| |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant { |
| VarZeroSlice::<T, F>::new_empty() |
| } |
| fn zvl_binary_search(&self, k: &T) -> Result<usize, usize> |
| where |
| T: Ord, |
| { |
| self.binary_search(k) |
| } |
| fn zvl_binary_search_in_range(&self, k: &T, range: Range<usize>) -> Option<Result<usize, usize>> |
| where |
| T: Ord, |
| { |
| self.binary_search_in_range(k, range) |
| } |
| fn zvl_binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize> { |
| self.binary_search_by(predicate) |
| } |
| fn zvl_binary_search_in_range_by( |
| &self, |
| predicate: impl FnMut(&T) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| self.binary_search_in_range_by(predicate, range) |
| } |
| fn zvl_get(&self, index: usize) -> Option<&T> { |
| self.get(index) |
| } |
| fn zvl_len(&self) -> usize { |
| self.len() |
| } |
| |
| fn zvl_as_borrowed(&self) -> &VarZeroSlice<T, F> { |
| self.as_slice() |
| } |
| |
| #[inline] |
| fn zvl_get_as_t<R>(g: &Self::GetType, f: impl FnOnce(&T) -> R) -> R { |
| f(g) |
| } |
| } |
| |
| impl<T, F> ZeroVecLike<T> for VarZeroSlice<T, F> |
| where |
| T: VarULE, |
| T: ?Sized, |
| F: VarZeroVecFormat, |
| { |
| type GetType = T; |
| type SliceVariant = VarZeroSlice<T, F>; |
| |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant { |
| VarZeroSlice::<T, F>::new_empty() |
| } |
| fn zvl_binary_search(&self, k: &T) -> Result<usize, usize> |
| where |
| T: Ord, |
| { |
| self.binary_search(k) |
| } |
| fn zvl_binary_search_in_range(&self, k: &T, range: Range<usize>) -> Option<Result<usize, usize>> |
| where |
| T: Ord, |
| { |
| self.binary_search_in_range(k, range) |
| } |
| fn zvl_binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize> { |
| self.binary_search_by(predicate) |
| } |
| fn zvl_binary_search_in_range_by( |
| &self, |
| predicate: impl FnMut(&T) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| self.binary_search_in_range_by(predicate, range) |
| } |
| fn zvl_get(&self, index: usize) -> Option<&T> { |
| self.get(index) |
| } |
| fn zvl_len(&self) -> usize { |
| self.len() |
| } |
| |
| fn zvl_as_borrowed(&self) -> &VarZeroSlice<T, F> { |
| self |
| } |
| |
| #[inline] |
| fn zvl_get_as_t<R>(g: &Self::GetType, f: impl FnOnce(&T) -> R) -> R { |
| f(g) |
| } |
| } |
| |
| impl<'a, T, F> MutableZeroVecLike<'a, T> for VarZeroVec<'a, T, F> |
| where |
| T: VarULE, |
| T: ?Sized, |
| F: VarZeroVecFormat, |
| { |
| type OwnedType = Box<T>; |
| fn zvl_insert(&mut self, index: usize, value: &T) { |
| self.make_mut().insert(index, value) |
| } |
| fn zvl_remove(&mut self, index: usize) -> Box<T> { |
| let vec = self.make_mut(); |
| debug_assert!(index < vec.len()); |
| #[allow(clippy::unwrap_used)] |
| let old = vec.get(index).unwrap().to_boxed(); |
| vec.remove(index); |
| old |
| } |
| fn zvl_replace(&mut self, index: usize, value: &T) -> Box<T> { |
| let vec = self.make_mut(); |
| debug_assert!(index < vec.len()); |
| #[allow(clippy::unwrap_used)] |
| let old = vec.get(index).unwrap().to_boxed(); |
| vec.replace(index, value); |
| old |
| } |
| fn zvl_push(&mut self, value: &T) { |
| let len = self.len(); |
| self.make_mut().insert(len, value) |
| } |
| fn zvl_with_capacity(cap: usize) -> Self { |
| if cap == 0 { |
| VarZeroVec::new() |
| } else { |
| VarZeroVec::Owned(VarZeroVecOwned::with_capacity(cap)) |
| } |
| } |
| fn zvl_clear(&mut self) { |
| self.make_mut().clear() |
| } |
| fn zvl_reserve(&mut self, addl: usize) { |
| self.make_mut().reserve(addl) |
| } |
| |
| fn owned_as_t(o: &Self::OwnedType) -> &T { |
| o |
| } |
| |
| fn zvl_from_borrowed(b: &'a VarZeroSlice<T, F>) -> Self { |
| b.as_varzerovec() |
| } |
| fn zvl_as_borrowed_inner(&self) -> Option<&'a VarZeroSlice<T, F>> { |
| if let VarZeroVec::Borrowed(b) = *self { |
| Some(b) |
| } else { |
| None |
| } |
| } |
| |
| #[allow(clippy::unwrap_used)] // documented panic |
| fn zvl_permute(&mut self, permutation: &mut [usize]) { |
| assert_eq!(permutation.len(), self.zvl_len()); |
| |
| let mut result = VarZeroVecOwned::new(); |
| for &i in permutation.iter() { |
| result.push(self.get(i).unwrap()); |
| } |
| *self = VarZeroVec::Owned(result); |
| } |
| } |
| |
| impl<'a> ZeroVecLike<usize> for FlexZeroVec<'a> { |
| type GetType = [u8]; |
| type SliceVariant = FlexZeroSlice; |
| |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant { |
| FlexZeroSlice::new_empty() |
| } |
| fn zvl_binary_search(&self, k: &usize) -> Result<usize, usize> { |
| FlexZeroSlice::binary_search(self, *k) |
| } |
| fn zvl_binary_search_in_range( |
| &self, |
| k: &usize, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| FlexZeroSlice::binary_search_in_range(self, *k, range) |
| } |
| fn zvl_binary_search_by( |
| &self, |
| mut predicate: impl FnMut(&usize) -> Ordering, |
| ) -> Result<usize, usize> { |
| FlexZeroSlice::binary_search_by(self, |probe| predicate(&probe)) |
| } |
| fn zvl_binary_search_in_range_by( |
| &self, |
| mut predicate: impl FnMut(&usize) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| FlexZeroSlice::binary_search_in_range_by(self, |probe| predicate(&probe), range) |
| } |
| fn zvl_get(&self, index: usize) -> Option<&[u8]> { |
| self.get_chunk(index) |
| } |
| fn zvl_len(&self) -> usize { |
| FlexZeroSlice::len(self) |
| } |
| |
| fn zvl_as_borrowed(&self) -> &FlexZeroSlice { |
| self |
| } |
| |
| #[inline] |
| fn zvl_get_as_t<R>(g: &[u8], f: impl FnOnce(&usize) -> R) -> R { |
| f(&crate::chunk_to_usize(g, g.len())) |
| } |
| } |
| |
| impl ZeroVecLike<usize> for FlexZeroSlice { |
| type GetType = [u8]; |
| type SliceVariant = FlexZeroSlice; |
| |
| fn zvl_new_borrowed() -> &'static Self::SliceVariant { |
| FlexZeroSlice::new_empty() |
| } |
| fn zvl_binary_search(&self, k: &usize) -> Result<usize, usize> { |
| FlexZeroSlice::binary_search(self, *k) |
| } |
| fn zvl_binary_search_in_range( |
| &self, |
| k: &usize, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| FlexZeroSlice::binary_search_in_range(self, *k, range) |
| } |
| fn zvl_binary_search_by( |
| &self, |
| mut predicate: impl FnMut(&usize) -> Ordering, |
| ) -> Result<usize, usize> { |
| FlexZeroSlice::binary_search_by(self, |probe| predicate(&probe)) |
| } |
| fn zvl_binary_search_in_range_by( |
| &self, |
| mut predicate: impl FnMut(&usize) -> Ordering, |
| range: Range<usize>, |
| ) -> Option<Result<usize, usize>> { |
| FlexZeroSlice::binary_search_in_range_by(self, |probe| predicate(&probe), range) |
| } |
| fn zvl_get(&self, index: usize) -> Option<&[u8]> { |
| self.get_chunk(index) |
| } |
| fn zvl_len(&self) -> usize { |
| FlexZeroSlice::len(self) |
| } |
| |
| fn zvl_as_borrowed(&self) -> &FlexZeroSlice { |
| self |
| } |
| |
| #[inline] |
| fn zvl_get_as_t<R>(g: &Self::GetType, f: impl FnOnce(&usize) -> R) -> R { |
| f(&crate::chunk_to_usize(g, g.len())) |
| } |
| } |
| |
| impl<'a> MutableZeroVecLike<'a, usize> for FlexZeroVec<'a> { |
| type OwnedType = usize; |
| fn zvl_insert(&mut self, index: usize, value: &usize) { |
| self.to_mut().insert(index, *value) |
| } |
| fn zvl_remove(&mut self, index: usize) -> usize { |
| self.to_mut().remove(index) |
| } |
| fn zvl_replace(&mut self, index: usize, value: &usize) -> usize { |
| // TODO(#2028): Make this a single operation instead of two operations. |
| let mutable = self.to_mut(); |
| let old_value = mutable.remove(index); |
| mutable.insert(index, *value); |
| old_value |
| } |
| fn zvl_push(&mut self, value: &usize) { |
| self.to_mut().push(*value) |
| } |
| fn zvl_with_capacity(_cap: usize) -> Self { |
| // There is no `FlexZeroVec::with_capacity()` because it is variable-width |
| FlexZeroVec::Owned(FlexZeroVecOwned::new_empty()) |
| } |
| fn zvl_clear(&mut self) { |
| self.to_mut().clear() |
| } |
| fn zvl_reserve(&mut self, _addl: usize) { |
| // There is no `FlexZeroVec::reserve()` because it is variable-width |
| } |
| |
| fn owned_as_t(o: &Self::OwnedType) -> &usize { |
| o |
| } |
| |
| fn zvl_from_borrowed(b: &'a FlexZeroSlice) -> Self { |
| b.as_flexzerovec() |
| } |
| fn zvl_as_borrowed_inner(&self) -> Option<&'a FlexZeroSlice> { |
| if let FlexZeroVec::Borrowed(b) = *self { |
| Some(b) |
| } else { |
| None |
| } |
| } |
| |
| #[allow(clippy::unwrap_used)] // documented panic |
| fn zvl_permute(&mut self, permutation: &mut [usize]) { |
| assert_eq!(permutation.len(), self.zvl_len()); |
| *self = permutation.iter().map(|&i| self.get(i).unwrap()).collect(); |
| } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| |
| #[test] |
| fn test_zerovec_binary_search_in_range() { |
| let zv: ZeroVec<u16> = ZeroVec::from_slice_or_alloc(&[11, 22, 33, 44, 55, 66, 77]); |
| |
| // Full range search |
| assert_eq!(zv.zvl_binary_search_in_range(&11, 0..7), Some(Ok(0))); |
| assert_eq!(zv.zvl_binary_search_in_range(&12, 0..7), Some(Err(1))); |
| assert_eq!(zv.zvl_binary_search_in_range(&44, 0..7), Some(Ok(3))); |
| assert_eq!(zv.zvl_binary_search_in_range(&45, 0..7), Some(Err(4))); |
| assert_eq!(zv.zvl_binary_search_in_range(&77, 0..7), Some(Ok(6))); |
| assert_eq!(zv.zvl_binary_search_in_range(&78, 0..7), Some(Err(7))); |
| |
| // Out-of-range search |
| assert_eq!(zv.zvl_binary_search_in_range(&44, 0..2), Some(Err(2))); |
| assert_eq!(zv.zvl_binary_search_in_range(&44, 5..7), Some(Err(0))); |
| |
| // Offset search |
| assert_eq!(zv.zvl_binary_search_in_range(&44, 2..5), Some(Ok(1))); |
| assert_eq!(zv.zvl_binary_search_in_range(&45, 2..5), Some(Err(2))); |
| |
| // Out-of-bounds |
| assert_eq!(zv.zvl_binary_search_in_range(&44, 0..100), None); |
| assert_eq!(zv.zvl_binary_search_in_range(&44, 100..200), None); |
| } |
| |
| #[test] |
| fn test_permute() { |
| let mut zv: ZeroVec<u16> = ZeroVec::from_slice_or_alloc(&[11, 22, 33, 44, 55, 66, 77]); |
| let mut permutation = vec![3, 2, 1, 0, 6, 5, 4]; |
| zv.zvl_permute(&mut permutation); |
| assert_eq!(&zv, &[44, 33, 22, 11, 77, 66, 55]); |
| |
| let mut vzv: VarZeroVec<str> = VarZeroVec::Owned( |
| VarZeroVecOwned::try_from_elements(&["11", "22", "33", "44", "55", "66", "77"]) |
| .unwrap(), |
| ); |
| let mut permutation = vec![3, 2, 1, 0, 6, 5, 4]; |
| vzv.zvl_permute(&mut permutation); |
| assert_eq!(&vzv, &["44", "33", "22", "11", "77", "66", "55"]); |
| |
| let mut fzv: FlexZeroVec = [11, 22, 33, 44, 55, 66, 77].into_iter().collect(); |
| let mut permutation = vec![3, 2, 1, 0, 6, 5, 4]; |
| fzv.zvl_permute(&mut permutation); |
| assert_eq!( |
| fzv.iter().collect::<Vec<_>>(), |
| [44, 33, 22, 11, 77, 66, 55].into_iter().collect::<Vec<_>>() |
| ); |
| } |
| } |