Replace AllocStringWriter with CVec
This commit is contained in:
+54
-5
@@ -1,6 +1,10 @@
|
||||
use crate::platform::{self, types::*};
|
||||
use crate::{
|
||||
io::{self, Write},
|
||||
platform::{self, WriteByte, types::*},
|
||||
};
|
||||
use core::{
|
||||
cmp,
|
||||
fmt,
|
||||
iter::IntoIterator,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
@@ -67,6 +71,9 @@ impl<T> CVec<T> {
|
||||
start = start.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Push stuff
|
||||
|
||||
pub fn reserve(&mut self, required: usize) -> Result<(), AllocError> {
|
||||
let reserved_len = self
|
||||
.len
|
||||
@@ -82,8 +89,8 @@ impl<T> CVec<T> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn push(&mut self, elem: T) -> Result<(), AllocError> {
|
||||
self.reserve(1)?;
|
||||
unsafe {
|
||||
self.reserve(1)?;
|
||||
ptr::write(self.ptr.as_ptr().add(self.len), elem);
|
||||
}
|
||||
self.len += 1; // no need to bounds check, as new len <= cap
|
||||
@@ -93,21 +100,26 @@ impl<T> CVec<T> {
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
self.reserve(elems.len())?;
|
||||
unsafe {
|
||||
self.reserve(elems.len())?;
|
||||
ptr::copy_nonoverlapping(elems.as_ptr(), self.ptr.as_ptr().add(self.len), elems.len());
|
||||
}
|
||||
self.len += elems.len(); // no need to bounds check, as new len <= cap
|
||||
Ok(())
|
||||
}
|
||||
pub fn append(&mut self, other: &mut Self) -> Result<(), AllocError> {
|
||||
let len = other.len;
|
||||
other.len = 0; // move
|
||||
self.reserve(len)?;
|
||||
unsafe {
|
||||
self.reserve(other.len())?;
|
||||
ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), other.len());
|
||||
ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), len);
|
||||
}
|
||||
self.len += other.len(); // no need to bounds check, as new len <= cap
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Pop stuff
|
||||
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
if len < self.len {
|
||||
unsafe {
|
||||
@@ -126,6 +138,18 @@ impl<T> CVec<T> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let elem = unsafe { ptr::read(self.as_ptr().add(self.len - 1)) };
|
||||
self.len -= 1;
|
||||
Some(elem)
|
||||
}
|
||||
}
|
||||
|
||||
// Misc stuff
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.cap
|
||||
}
|
||||
@@ -176,3 +200,28 @@ impl<'a, T> IntoIterator for &'a mut CVec<T> {
|
||||
<&mut [T]>::into_iter(&mut *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for CVec<u8> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.extend_from_slice(buf).map_err(|err| io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"AllocStringWriter::write failed to allocate",
|
||||
))?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl fmt::Write for CVec<u8> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write(s.as_bytes()).map_err(|_| fmt::Error)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl WriteByte for CVec<u8> {
|
||||
fn write_u8(&mut self, byte: u8) -> fmt::Result {
|
||||
self.write(&[byte]).map_err(|_| fmt::Error)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use core::{
|
||||
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
c_vec::CVec,
|
||||
fs::File,
|
||||
header::{
|
||||
errno::{self, STR_ERROR},
|
||||
@@ -1021,9 +1022,11 @@ pub unsafe extern "C" fn vasprintf(
|
||||
format: *const c_char,
|
||||
ap: va_list,
|
||||
) -> c_int {
|
||||
let mut alloc_writer = platform::AllocStringWriter(ptr::null_mut(), 0);
|
||||
let mut alloc_writer = CVec::new();
|
||||
let ret = printf::printf(&mut alloc_writer, format, ap);
|
||||
*strp = alloc_writer.0 as *mut c_char;
|
||||
alloc_writer.push(0).unwrap();
|
||||
alloc_writer.shrink_to_fit().unwrap();
|
||||
*strp = alloc_writer.leak() as *mut c_char;
|
||||
ret
|
||||
}
|
||||
|
||||
|
||||
+7
-43
@@ -104,45 +104,6 @@ impl Read for FileReader {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AllocStringWriter(pub *mut u8, pub usize);
|
||||
impl Write for AllocStringWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let ptr = unsafe { realloc(self.0 as *mut c_void, self.1 + buf.len() + 1) as *mut u8 };
|
||||
if ptr.is_null() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"AllocStringWriter::write failed to allocate",
|
||||
));
|
||||
}
|
||||
self.0 = ptr;
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(buf.as_ptr(), self.0.add(self.1), buf.len());
|
||||
self.1 += buf.len();
|
||||
*self.0.add(self.1) = 0;
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl fmt::Write for AllocStringWriter {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
// can't fail
|
||||
self.write(s.as_bytes()).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl WriteByte for AllocStringWriter {
|
||||
fn write_u8(&mut self, byte: u8) -> fmt::Result {
|
||||
// can't fail
|
||||
self.write(&[byte]).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StringWriter(pub *mut u8, pub usize);
|
||||
impl Write for StringWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
@@ -155,11 +116,14 @@ impl Write for StringWriter {
|
||||
self.0 = self.0.add(copy_size);
|
||||
*self.0 = 0;
|
||||
}
|
||||
|
||||
Ok(copy_size)
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
// Pretend the entire slice was written. This is because many functions
|
||||
// (like snprintf) expects a return value that reflects how many bytes
|
||||
// *would have* been written. So keeping track of this information is
|
||||
// good, and then if we want the *actual* written size we can just go
|
||||
// `cmp::min(written, maxlen)`.
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user