Skip to content

Commit

Permalink
feat: add shrink_to and shrink_to_fit
Browse files Browse the repository at this point in the history
  • Loading branch information
polazarus committed Aug 2, 2024
1 parent 5cffac8 commit 511429b
Show file tree
Hide file tree
Showing 11 changed files with 464 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Notable changes only.
- add `truncate`, `pop`, and `clear`
- add `concat` and `join`
- add `with_capacity`
- add `shrink_to_fit` and `shrink`

### Fixed

Expand Down
49 changes: 49 additions & 0 deletions src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,55 @@ where
HipByt(self.0.into_owned())
}

/// Shrinks the capacity of the vector as much as possible.
///
/// The capacity will remain at least as large as the actual length of the
/// vector.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The allocated representation may change to *inline* if the required
/// capacity is smaller thant the inline capacity.
///
/// # Examples
///
/// ```rust
/// # use hipstr::HipByt;
/// let mut s = HipByt::with_capacity(100);
/// s.push_slice(b"abc");
/// s.shrink_to_fit();
/// assert_eq!(s.capacity(), HipByt::inline_capacity());
/// ```
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to(self.len());
}

/// Shrinks the capacity of the vector with a lower bound.
///
/// The capacity will remain at least as large as the given bound and the
/// actual length of the vector.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The representation may change to inline if the required capacity is
/// smaller than the inline capacity.
///
/// # Examples
///
/// ```rust
/// # use hipstr::HipByt;
/// let mut s = HipByt::with_capacity(100);
/// s.shrink_to(4);
/// assert_eq!(s.capacity(), HipByt::inline_capacity());
/// ```
pub fn shrink_to(&mut self, min_capacity: usize) {
self.0.shrink_to(min_capacity)
}

pub(crate) fn take_vec(&mut self) -> Vec<u8> {
self.0.take_vec()
}
Expand Down
75 changes: 75 additions & 0 deletions src/bytes/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,81 @@ fn test_mutate_allocated() {
}
}

#[test]
fn test_shrink_to_fit() {
let mut h = H::borrowed(MEDIUM);
h.shrink_to_fit();
assert_eq!(h, MEDIUM);
assert!(core::ptr::eq(h.as_slice(), MEDIUM));

let mut h = H::from(MEDIUM);
h.truncate(INLINE_CAPACITY);
h.shrink_to_fit();
assert!(h.is_inline());
assert_eq!(h, &MEDIUM[..INLINE_CAPACITY]);

let mut h = H::from(MEDIUM);
let h2 = h.clone();
h.truncate(INLINE_CAPACITY + 1);
assert_eq!(h.as_ptr(), h2.as_ptr());
h.shrink_to_fit();
assert_ne!(h.as_ptr(), h2.as_ptr());
assert_eq!(h, &MEDIUM[..(INLINE_CAPACITY + 1)]);

let mut h = H::from(&MEDIUM[..INLINE_CAPACITY]);
assert!(h.is_inline());
h.shrink_to_fit();
assert!(!h.is_inline());
assert_eq!(h, &MEDIUM[..INLINE_CAPACITY]);
}

#[test]
fn test_shrink_to() {
// borrowed no-op
let mut h = H::borrowed(MEDIUM);
h.shrink_to(0);
assert_eq!(h, MEDIUM);
assert!(core::ptr::eq(h.as_slice(), MEDIUM));

// allocated with capacity < length
let mut h = H::from(MEDIUM);
h.shrink_to(0);
assert_eq!(h, MEDIUM);
assert!(h.capacity() >= MEDIUM.len());

// allocated with capacity > actual capacity
let mut h = H::from(MEDIUM);
let old_capacity = h.capacity();
h.shrink_to(1024);
assert_eq!(h, MEDIUM);
assert_eq!(h.capacity(), old_capacity);

// allocated that switches to inline
let mut h = H::from(MEDIUM);
h.truncate(INLINE_CAPACITY);
h.shrink_to(INLINE_CAPACITY);
assert!(h.is_inline());
assert_eq!(h, &MEDIUM[..INLINE_CAPACITY]);

// allocated that reallocates
let mut h = H::from(MEDIUM);
let h2 = h.clone();
h.truncate(INLINE_CAPACITY + 1);
assert_eq!(h.as_ptr(), h2.as_ptr());
assert!(h.capacity() >= INLINE_CAPACITY + 2);
h.shrink_to(INLINE_CAPACITY + 2);
assert_ne!(h.as_ptr(), h2.as_ptr());
assert!(h.capacity() >= INLINE_CAPACITY + 2);

// inline no-op
let mut h = H::from(&MEDIUM[..INLINE_CAPACITY]);
assert!(h.is_inline());
h.truncate(0);
h.shrink_to(INLINE_CAPACITY / 4);
assert!(h.is_inline());
assert_eq!(h.capacity(), INLINE_CAPACITY);
}

#[test]
fn test_truncate() {
let mut h = H::borrowed(MEDIUM);
Expand Down
51 changes: 51 additions & 0 deletions src/os_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,57 @@ where
// SAFETY
unsafe { Self(self.0.slice_ref_unchecked(slice.as_encoded_bytes())) }
}

/// Shrinks the capacity of the string as much as possible.
///
/// The capacity will remain at least as large as the actual length of the
/// string.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The allocated representation may change to *inline* if the required
/// capacity is smaller thant the inline capacity.
///
/// # Examples
///
/// ```rust
/// # use hipstr::HipOsStr;
/// let mut s = HipOsStr::with_capacity(100);
/// s.push("abc");
/// s.shrink_to_fit();
/// assert_eq!(s.capacity(), HipOsStr::inline_capacity());
/// ```
#[inline]
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}

/// Shrinks the capacity of the string with a lower bound.
///
/// The capacity will remain at least as large as the given lower bound and
/// the actual length of the string.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The allocated representation may change to *inline* if the required
/// capacity is smaller thant the inline capacity.
///
/// # Examples
///
/// ```rust
/// # use hipstr::HipOsStr;
/// let mut s = HipOsStr::with_capacity(100);
/// s.shrink_to(4);
/// assert_eq!(s.capacity(), HipOsStr::inline_capacity());
/// ```
#[inline]
pub fn shrink_to(&mut self, min_capacity: usize) {
self.0.shrink_to(min_capacity);
}
}

impl<B> HipOsStr<'static, B>
Expand Down
33 changes: 33 additions & 0 deletions src/os_string/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,3 +485,36 @@ fn test_slice_ref_panic() {
let a = HipOsStr::borrowed(&s);
let _ = a.slice_ref("abc".as_ref());
}

#[test]
fn test_shrink_to_fit() {
let mut h = H::with_capacity(INLINE_CAPACITY + 1);
h.shrink_to_fit();
assert_eq!(h.capacity(), INLINE_CAPACITY);

let mut h = H::from("abc");
h.shrink_to_fit();
assert_eq!(h.capacity(), INLINE_CAPACITY);

let mut h = H::from_static("abc");
h.shrink_to_fit();
assert_eq!(h.capacity(), 3);
}

#[test]
fn test_shrink_to() {
let mut h = H::with_capacity(INLINE_CAPACITY + 1);
h.push("a");
h.shrink_to(0);
assert_eq!(h.capacity(), INLINE_CAPACITY);
assert_eq!(h.len(), 1);

let mut h = H::from("abc");
h.shrink_to(4);
assert_eq!(h.capacity(), INLINE_CAPACITY);

let mut h = H::from_static("abc");
assert_eq!(h.capacity(), 3);
h.shrink_to(0);
assert_eq!(h.capacity(), 3);
}
54 changes: 54 additions & 0 deletions src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,60 @@ where
pub fn into_str(self) -> Result<HipStr<'borrow, B>, Self> {
self.0.into_str().map_err(Self)
}

/// Shrinks the capacity of the string as much as possible.
///
/// The capacity will remain at least as large as the actual length of the
/// string.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The allocated representation may change to *inline* if the required
/// capacity is smaller thant the inline capacity.
///
/// # Examples
///
/// ```rust
/// # use hipstr::{HipOsStr, HipPath};
/// let mut s = HipOsStr::with_capacity(100);
/// s.push("abc");
/// let mut p = HipPath::from(s);
/// assert!(p.capacity() >= 100);
/// p.shrink_to_fit();
/// assert_eq!(p.capacity(), HipPath::inline_capacity());
/// ```
#[inline]
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}

/// Shrinks the capacity of the string with a lower bound.
///
/// The capacity will remain at least as large as the given lower bound and
/// the actual length of the string.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The allocated representation may change to *inline* if the required
/// capacity is smaller thant the inline capacity.
///
/// # Examples
///
/// ```rust
/// # use hipstr::{HipOsStr, HipPath};
/// let s = HipOsStr::with_capacity(100);
/// let mut p = HipPath::from(s);
/// p.shrink_to(4);
/// assert_eq!(p.capacity(), HipPath::inline_capacity());
/// ```
#[inline]
pub fn shrink_to(&mut self, min_capacity: usize) {
self.0.shrink_to(min_capacity);
}
}

impl<B> HipPath<'static, B>
Expand Down
36 changes: 36 additions & 0 deletions src/path/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::Path;

use crate::alloc::format;
use crate::alloc::string::String;
use crate::os_string::HipOsStr;
use crate::HipPath;

const INLINE_CAPACITY: usize = HipPath::inline_capacity();
Expand Down Expand Up @@ -316,3 +317,38 @@ fn test_to_owned() {
let a = a.into_owned();
assert_eq!(a.0.as_ptr(), p);
}

#[test]
fn test_shrink_to_fit() {
let h = HipOsStr::with_capacity(INLINE_CAPACITY + 1);
let mut h = HipPath::from(h);
h.shrink_to_fit();
assert_eq!(h.capacity(), INLINE_CAPACITY);

let mut h = HipPath::from("abc");
h.shrink_to_fit();
assert_eq!(h.capacity(), INLINE_CAPACITY);

let mut h = HipPath::from_static("abc");
h.shrink_to_fit();
assert_eq!(h.capacity(), 3);
}

#[test]
fn test_shrink_to() {
let mut h = HipOsStr::with_capacity(INLINE_CAPACITY + 1);
h.push("a");
let mut h = HipPath::from(h);
h.shrink_to(0);
assert_eq!(h.capacity(), INLINE_CAPACITY);
assert_eq!(h.as_os_str().len(), 1);

let mut h = HipPath::from("abc");
h.shrink_to(4);
assert_eq!(h.capacity(), INLINE_CAPACITY);

let mut h = HipPath::from_static("abc");
assert_eq!(h.capacity(), 3);
h.shrink_to(0);
assert_eq!(h.capacity(), 3);
}
26 changes: 26 additions & 0 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,11 +783,37 @@ impl<'borrow, B: Backend> Raw<'borrow, B> {
unsafe { Self::inline_unchecked(self.as_slice().get_unchecked(..new_len)) };
*self = new;
} else {
// SAFETY: `new_len` is checked above
unsafe { self.set_len(new_len) }
}
}
debug_assert!(self.is_normalized());
}

/// Shrinks the capacity of the vector with a lower bound.
///
/// The capacity will remain at least as large as the given bound and the
/// given length.
///
/// No-op if the representation is not allocated.
///
/// # Representation stability
///
/// The representation may change to inline if the required capacity is
/// smaller than the inline capacity.
pub fn shrink_to(&mut self, min_capacity: usize) {
if self.is_allocated() {
let min_capacity = min_capacity.max(self.len());

if min_capacity > INLINE_CAPACITY {
let allocated = unsafe { &mut self.union_mut().allocated };
allocated.shrink_to(min_capacity);
} else {
let new = unsafe { Self::inline_unchecked(self.as_slice()) };
*self = new;
}
}
}
}

impl<'borrow, B: Backend> Drop for Raw<'borrow, B> {
Expand Down
Loading

0 comments on commit 511429b

Please sign in to comment.