Skip to content

Commit

Permalink
feat: added BumpBox<str>::split_off
Browse files Browse the repository at this point in the history
  • Loading branch information
bluurryy committed Dec 23, 2024
1 parent 22dcedf commit a2c83ac
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- **deprecated:** `extend_from_array` in favor of `append`
- **added:** `append` can now handle arrays, boxed arrays, boxed slices and trait objects
- **added:** implemented `OwnedSlice` for `owned_slice::{IntoIter, Drain}`
- **added:** `split_off` for `Fixed*` collections
- **added:** `split_off` for `Fixed*` collections and `BumpBox<str>`

## 0.14.0 (2024-12-12)
- **breaking:** fix `scoped_aligned`'s closure to take a `BumpScope` with `NEW_MIN_ALIGN` instead of `MIN_ALIGN`
Expand Down
57 changes: 57 additions & 0 deletions src/bump_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,63 @@ impl<'a> BumpBox<'a, str> {
self.len() == 0
}

/// Splits the string into two at the given byte index.
///
/// Returns a newly allocated `BumpString`. `self` contains bytes `[0, at)`, and
/// the returned `BumpString` contains bytes `[at, len)`. `at` must be on the
/// boundary of a UTF-8 code point.
///
/// [String]: alloc::string::String
/// [split_off]: alloc::string::String::split_off
///
/// # Panics
///
/// Panics if `at` is not on a `UTF-8` code point boundary, or if it is beyond the last
/// code point of the string.
///
/// # Examples
///
/// ```
/// # use bump_scope::Bump;
/// # let bump: Bump = Bump::new();
/// let mut string = bump.alloc_str("foobarbaz");
///
/// let foo = string.split_off(..3);
/// assert_eq!(foo, "foo");
/// assert_eq!(string, "barbaz");
///
/// let baz = string.split_off(3..);
/// assert_eq!(baz, "baz");
/// assert_eq!(string, "bar");
/// ```
#[inline]
#[allow(clippy::return_self_not_must_use)]
pub fn split_off(&mut self, range: impl OneSidedRange<usize>) -> Self {
let (direction, mid) = one_sided_range::direction(range, ..self.len());

assert!(self.is_char_boundary(mid));

let ptr = self.ptr.cast::<u8>();
let len = self.len();

let lhs = nonnull::slice_from_raw_parts(ptr, mid);
let rhs = nonnull::slice_from_raw_parts(unsafe { nonnull::add(ptr, mid) }, len - mid);

let lhs = nonnull::str_from_utf8(lhs);
let rhs = nonnull::str_from_utf8(rhs);

match direction {
one_sided_range::Direction::From => unsafe {
self.ptr = lhs;
Self::from_raw(rhs)
},
one_sided_range::Direction::To => unsafe {
self.ptr = rhs;
Self::from_raw(lhs)
},
}
}

/// Removes the last character from the string buffer and returns it.
///
/// Returns [`None`] if this string is empty.
Expand Down
3 changes: 0 additions & 3 deletions src/fixed_bump_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,6 @@ impl<'a> FixedBumpString<'a> {
///
/// The returned vector will have the excess capacity if any.
///
/// *This behavior is different to <code>[String]::[split_off]</code> which allocates a new vector
/// to store the split-off elements.*
///
/// [String]: alloc::string::String
/// [split_off]: alloc::string::String::split_off
///
Expand Down

0 comments on commit a2c83ac

Please sign in to comment.