summaryrefslogtreecommitdiffstats
path: root/vendor/zerovec/src/flexzerovec/owned.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/zerovec/src/flexzerovec/owned.rs')
-rw-r--r--vendor/zerovec/src/flexzerovec/owned.rs350
1 files changed, 350 insertions, 0 deletions
diff --git a/vendor/zerovec/src/flexzerovec/owned.rs b/vendor/zerovec/src/flexzerovec/owned.rs
new file mode 100644
index 000000000..1039c59ae
--- /dev/null
+++ b/vendor/zerovec/src/flexzerovec/owned.rs
@@ -0,0 +1,350 @@
+// 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 alloc::vec;
+use alloc::vec::Vec;
+use core::fmt;
+use core::iter::FromIterator;
+use core::ops::Deref;
+
+use super::FlexZeroSlice;
+use super::FlexZeroVec;
+
+/// The fully-owned variant of [`FlexZeroVec`]. Contains all mutation methods.
+// Safety invariant: the inner bytes must deref to a valid `FlexZeroSlice`
+#[derive(Clone, PartialEq, Eq)]
+pub struct FlexZeroVecOwned(Vec<u8>);
+
+impl FlexZeroVecOwned {
+ /// Creates a new [`FlexZeroVecOwned`] with zero elements.
+ pub fn new_empty() -> Self {
+ Self(vec![1])
+ }
+
+ /// Creates a [`FlexZeroVecOwned`] from a [`FlexZeroSlice`].
+ pub fn from_slice(other: &FlexZeroSlice) -> FlexZeroVecOwned {
+ // safety: the bytes originate from a valid FlexZeroSlice
+ Self(other.as_bytes().to_vec())
+ }
+
+ /// Obtains this [`FlexZeroVecOwned`] as a [`FlexZeroSlice`].
+ pub fn as_slice(&self) -> &FlexZeroSlice {
+ let slice: &[u8] = &*self.0;
+ unsafe {
+ // safety: the slice is known to come from a valid parsed FlexZeroSlice
+ FlexZeroSlice::from_byte_slice_unchecked(slice)
+ }
+ }
+
+ /// Mutably obtains this `FlexZeroVecOwned` as a [`FlexZeroSlice`].
+ pub(crate) fn as_mut_slice(&mut self) -> &mut FlexZeroSlice {
+ let slice: &mut [u8] = &mut *self.0;
+ unsafe {
+ // safety: the slice is known to come from a valid parsed FlexZeroSlice
+ FlexZeroSlice::from_byte_slice_mut_unchecked(slice)
+ }
+ }
+
+ /// Converts this `FlexZeroVecOwned` into a [`FlexZeroVec::Owned`].
+ #[inline]
+ pub fn into_flexzerovec(self) -> FlexZeroVec<'static> {
+ FlexZeroVec::Owned(self)
+ }
+
+ /// Clears all values out of this `FlexZeroVecOwned`.
+ #[inline]
+ pub fn clear(&mut self) {
+ *self = Self::new_empty()
+ }
+
+ /// Appends an item to the end of the vector.
+ ///
+ /// # Panics
+ ///
+ /// Panics if inserting the element would require allocating more than `usize::MAX` bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::vecs::FlexZeroVec;
+ ///
+ /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
+ /// zv.to_mut().push(33);
+ /// assert_eq!(zv.to_vec(), vec![22, 44, 66, 33]);
+ /// ```
+ pub fn push(&mut self, item: usize) {
+ let insert_info = self.get_insert_info(item);
+ self.0.resize(insert_info.new_bytes_len, 0);
+ let insert_index = insert_info.new_count - 1;
+ self.as_mut_slice().insert_impl(insert_info, insert_index);
+ }
+
+ /// Inserts an element into the middle of the vector.
+ ///
+ /// Caution: Both arguments to this function are of type `usize`. Please be careful to pass
+ /// the index first followed by the value second.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index > len`.
+ ///
+ /// Panics if inserting the element would require allocating more than `usize::MAX` bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::vecs::FlexZeroVec;
+ ///
+ /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
+ /// zv.to_mut().insert(2, 33);
+ /// assert_eq!(zv.to_vec(), vec![22, 44, 33, 66]);
+ /// ```
+ pub fn insert(&mut self, index: usize, item: usize) {
+ #[allow(clippy::panic)] // panic is documented in function contract
+ if index > self.len() {
+ panic!("index {} out of range {}", index, self.len());
+ }
+ let insert_info = self.get_insert_info(item);
+ self.0.resize(insert_info.new_bytes_len, 0);
+ self.as_mut_slice().insert_impl(insert_info, index);
+ }
+
+ /// Inserts an element into an ascending sorted vector
+ /// at a position that keeps the vector sorted.
+ ///
+ /// # Panics
+ ///
+ /// Panics if inserting the element would require allocating more than `usize::MAX` bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::vecs::FlexZeroVecOwned;
+ ///
+ /// let mut fzv = FlexZeroVecOwned::new_empty();
+ /// fzv.insert_sorted(10);
+ /// fzv.insert_sorted(5);
+ /// fzv.insert_sorted(8);
+ ///
+ /// assert!(Iterator::eq(fzv.iter(), [5, 8, 10].iter().copied()));
+ /// ```
+ pub fn insert_sorted(&mut self, item: usize) {
+ let index = match self.binary_search(item) {
+ Ok(i) => i,
+ Err(i) => i,
+ };
+ let insert_info = self.get_insert_info(item);
+ self.0.resize(insert_info.new_bytes_len, 0);
+ self.as_mut_slice().insert_impl(insert_info, index);
+ }
+
+ /// Removes and returns the element at the specified index.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index >= len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::vecs::FlexZeroVec;
+ ///
+ /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
+ /// let removed_item = zv.to_mut().remove(1);
+ /// assert_eq!(44, removed_item);
+ /// assert_eq!(zv.to_vec(), vec![22, 66]);
+ /// ```
+ pub fn remove(&mut self, index: usize) -> usize {
+ #[allow(clippy::panic)] // panic is documented in function contract
+ if index >= self.len() {
+ panic!("index {} out of range {}", index, self.len());
+ }
+ let remove_info = self.get_remove_info(index);
+ // Safety: `remove_index` is a valid index
+ let item = unsafe { self.get_unchecked(remove_info.remove_index) };
+ let new_bytes_len = remove_info.new_bytes_len;
+ self.as_mut_slice().remove_impl(remove_info);
+ self.0.truncate(new_bytes_len);
+ item
+ }
+
+ /// Removes and returns the last element from an ascending sorted vector.
+ ///
+ /// If the vector is not sorted, use [`FlexZeroVecOwned::remove()`] instead. Calling this
+ /// function would leave the FlexZeroVec in a safe, well-defined state; however, information
+ /// may be lost and/or the equality invariant might not hold.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self.is_empty()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use zerovec::vecs::FlexZeroVec;
+ ///
+ /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
+ /// let popped_item = zv.to_mut().pop_sorted();
+ /// assert_eq!(66, popped_item);
+ /// assert_eq!(zv.to_vec(), vec![22, 44]);
+ /// ```
+ ///
+ /// Calling this function on a non-ascending vector could cause surprising results:
+ ///
+ /// ```
+ /// use zerovec::vecs::FlexZeroVec;
+ ///
+ /// let mut zv1: FlexZeroVec = [444, 222, 111].iter().copied().collect();
+ /// let popped_item = zv1.to_mut().pop_sorted();
+ /// assert_eq!(111, popped_item);
+ ///
+ /// // Oops!
+ /// assert_eq!(zv1.to_vec(), vec![188, 222]);
+ /// ```
+ pub fn pop_sorted(&mut self) -> usize {
+ #[allow(clippy::panic)] // panic is documented in function contract
+ if self.is_empty() {
+ panic!("cannot pop from an empty vector");
+ }
+ let remove_info = self.get_sorted_pop_info();
+ // Safety: `remove_index` is a valid index
+ let item = unsafe { self.get_unchecked(remove_info.remove_index) };
+ let new_bytes_len = remove_info.new_bytes_len;
+ self.as_mut_slice().remove_impl(remove_info);
+ self.0.truncate(new_bytes_len);
+ item
+ }
+}
+
+impl Deref for FlexZeroVecOwned {
+ type Target = FlexZeroSlice;
+ fn deref(&self) -> &Self::Target {
+ self.as_slice()
+ }
+}
+
+impl fmt::Debug for FlexZeroVecOwned {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self.to_vec())
+ }
+}
+
+impl From<&FlexZeroSlice> for FlexZeroVecOwned {
+ fn from(other: &FlexZeroSlice) -> Self {
+ Self::from_slice(other)
+ }
+}
+
+impl FromIterator<usize> for FlexZeroVecOwned {
+ /// Creates a [`FlexZeroVecOwned`] from an iterator of `usize`.
+ fn from_iter<I>(iter: I) -> Self
+ where
+ I: IntoIterator<Item = usize>,
+ {
+ let mut result = FlexZeroVecOwned::new_empty();
+ for item in iter {
+ result.push(item);
+ }
+ result
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ fn check_contents(fzv: &FlexZeroSlice, expected: &[usize]) {
+ assert_eq!(
+ fzv.len(),
+ expected.len(),
+ "len: {:?} != {:?}",
+ fzv,
+ expected
+ );
+ assert_eq!(
+ fzv.is_empty(),
+ expected.is_empty(),
+ "is_empty: {:?} != {:?}",
+ fzv,
+ expected
+ );
+ assert_eq!(
+ fzv.first(),
+ expected.first().copied(),
+ "first: {:?} != {:?}",
+ fzv,
+ expected
+ );
+ assert_eq!(
+ fzv.last(),
+ expected.last().copied(),
+ "last: {:?} != {:?}",
+ fzv,
+ expected
+ );
+ for i in 0..(expected.len() + 1) {
+ assert_eq!(
+ fzv.get(i),
+ expected.get(i).copied(),
+ "@{}: {:?} != {:?}",
+ i,
+ fzv,
+ expected
+ );
+ }
+ }
+
+ #[test]
+ fn test_basic() {
+ let mut fzv = FlexZeroVecOwned::new_empty();
+ assert_eq!(fzv.get_width(), 1);
+ check_contents(&fzv, &[]);
+
+ fzv.push(42);
+ assert_eq!(fzv.get_width(), 1);
+ check_contents(&fzv, &[42]);
+
+ fzv.push(77);
+ assert_eq!(fzv.get_width(), 1);
+ check_contents(&fzv, &[42, 77]);
+
+ // Scale up
+ fzv.push(300);
+ assert_eq!(fzv.get_width(), 2);
+ check_contents(&fzv, &[42, 77, 300]);
+
+ // Does not need to be sorted
+ fzv.insert(1, 325);
+ assert_eq!(fzv.get_width(), 2);
+ check_contents(&fzv, &[42, 325, 77, 300]);
+
+ fzv.remove(3);
+ assert_eq!(fzv.get_width(), 2);
+ check_contents(&fzv, &[42, 325, 77]);
+
+ // Scale down
+ fzv.remove(1);
+ assert_eq!(fzv.get_width(), 1);
+ check_contents(&fzv, &[42, 77]);
+ }
+
+ #[test]
+ fn test_build_sorted() {
+ let nums: &[usize] = &[0, 50, 0, 77, 831, 29, 89182, 931, 0, 77, 712381];
+ let mut fzv = FlexZeroVecOwned::new_empty();
+
+ for num in nums {
+ fzv.insert_sorted(*num);
+ }
+ assert_eq!(fzv.get_width(), 3);
+ check_contents(&fzv, &[0, 0, 0, 29, 50, 77, 77, 831, 931, 89182, 712381]);
+
+ for num in nums {
+ let index = fzv.binary_search(*num).unwrap();
+ fzv.remove(index);
+ }
+ assert_eq!(fzv.get_width(), 1);
+ check_contents(&fzv, &[]);
+ }
+}