`SmallString<SIZE>`: Added `extend_from_str()`: Shunts to heap when needed. `impl Extend<impl AsRef<str>> for SmallString<SIZE>`: Extends N strings.

Fortune for stack-str's current commit: Future small blessing − 末小吉
master
Avril 2 years ago
parent 1714fea6b8
commit 42e85234fb
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -59,7 +59,14 @@ impl HeapString {
slice::from_raw_parts(self.data.as_ptr() as *const u8, self.len)
}
}
#[inline(always)]
pub fn as_mut_str(&mut self) -> &mut str
{
unsafe {
std::str::from_utf8_unchecked_mut(self.as_bytes_mut())
}
}
#[inline(always)]
pub fn as_str(&self) -> &str
{
@ -297,6 +304,27 @@ impl<const SIZE: usize> SmallString<SIZE>
current
}
/// Shunt the stack-allocated to heap along with 1 or more `strs`
///
/// # Safety
/// * The caller must guarantee that the current invariant is `inner.stack`.
/// * the caller must recognise that the invariant after this function returns is `inner.heap`.
/// * the `fill_ptr` will be updated automacitally. The caller must guarantee that is is `> SIZE` when this function returns.
#[inline(always)]
unsafe fn shunt_to_heap_with_unchecked<'i, I>(&'i mut self, strings: I) -> &'i mut HeapString
where I: IntoIterator<Item = &'i str>,
{
let string = {
let mut string: String = self.inner.stack.as_str().into();
string.extend(strings);
string.into_boxed_str()
};
let heap = &mut self.inner.heap;
*heap = ManuallyDrop::new(HeapString::new(string));
heap
}
/// Extends the memory inside `self` to fit more `bytes`.
/// The data is moved to the heap first if `self.len() + bytes.len() > SIZE`.
///
@ -309,7 +337,7 @@ impl<const SIZE: usize> SmallString<SIZE>
unsafe fn extend_from_bytes_unchecked<'i>(&'i mut self, bytes: &[u8]) -> &'i mut [u8]
{
let len = self.len();
if bytes.len() + len > SIZE {
if !self.inner.is_heap() && bytes.len() + len > SIZE {
return self.shunt_to_heap_unchecked().extend_from_bytes_unchecked(bytes);
}
match self.inner.get_stack_mut() {
@ -325,7 +353,30 @@ impl<const SIZE: usize> SmallString<SIZE>
}
}
}
//TODO: extend_from_str()
#[inline]
pub fn extend_from_str<'i, 'a: 'i>(&'i mut self, s: &'a str) -> &'i mut str
{
if self.inner.is_heap() {
// Append to heap.
unsafe {
std::str::from_utf8_unchecked_mut((&mut *(self.inner.heap)).extend_from_bytes_unchecked(s.as_bytes()))
}
} else {
// Attempt to append to stack
let appended_stack = (unsafe { &mut self.inner.stack }).append_from_str(s);
if appended_stack != s.len() {
// Shunt to heap, along with the rest of `s`.
let s = &s[appended_stack..];
unsafe {
self.shunt_to_heap_with_unchecked(std::iter::once(s)).as_mut_str()
}
} else {
// Fits in stack, return that.
(unsafe {&mut self.inner.stack}).as_mut_str()
}
}
}
}
impl<const SIZE: usize> Borrow<str> for SmallString<SIZE>
@ -414,4 +465,15 @@ impl<const SIZE: usize> fmt::Display for SmallString<SIZE>
}
}
impl<const SIZE: usize, T: AsRef<str>> Extend<T> for SmallString<SIZE>
{
#[inline]
fn extend<U: IntoIterator<Item = T>>(&mut self, iter: U) {
for s in iter {
//XXX: There's gotta be a more efficient way for this, like we have in `shunt_with_unchecked<I>()`.
self.extend_from_str(s.as_ref());
}
}
}
//TODO: SmallString: fmt::Write, io::Write impls when extending functions have been written

Loading…
Cancel
Save