|
@@ -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},
|
|
@@ -53,8 +57,13 @@ impl<T> CVec<T> {
|
|
|
}
|
|
|
unsafe fn resize(&mut self, cap: usize) -> Result<(), AllocError> {
|
|
|
let size = Self::check_mul(cap, mem::size_of::<T>())?;
|
|
|
- let ptr = NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T)
|
|
|
- .ok_or(AllocError)?;
|
|
|
+ let ptr = if cap == 0 {
|
|
|
+ NonNull::dangling()
|
|
|
+ } else if self.cap > 0 {
|
|
|
+ NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T).ok_or(AllocError)?
|
|
|
+ } else {
|
|
|
+ NonNull::new((platform::alloc(size)) as *mut T).ok_or(AllocError)?
|
|
|
+ };
|
|
|
self.ptr = ptr;
|
|
|
self.cap = cap;
|
|
|
Ok(())
|
|
@@ -67,14 +76,17 @@ impl<T> CVec<T> {
|
|
|
start = start.add(1);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // Push stuff
|
|
|
+
|
|
|
pub fn reserve(&mut self, required: usize) -> Result<(), AllocError> {
|
|
|
- let reserved_len = self
|
|
|
+ let required_len = self
|
|
|
.len
|
|
|
.checked_add(required)
|
|
|
.ok_or(AllocError)
|
|
|
.and_then(Self::check_bounds)?;
|
|
|
- let new_cap = cmp::min(reserved_len.next_power_of_two(), core::isize::MAX as usize);
|
|
|
- if new_cap > self.cap {
|
|
|
+ if required_len > self.cap {
|
|
|
+ let new_cap = cmp::min(required_len.next_power_of_two(), core::isize::MAX as usize);
|
|
|
unsafe {
|
|
|
self.resize(new_cap)?;
|
|
|
}
|
|
@@ -82,8 +94,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 +105,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 +143,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 +205,83 @@ 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(())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod tests {
|
|
|
+ use super::CVec;
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn push_pop() {
|
|
|
+ let mut vec = CVec::new();
|
|
|
+ vec.push(1).unwrap();
|
|
|
+ vec.push(2).unwrap();
|
|
|
+ vec.push(3).unwrap();
|
|
|
+ assert_eq!(&vec[..], &[1, 2, 3]);
|
|
|
+ assert_eq!(vec.pop().unwrap(), 3);
|
|
|
+ assert_eq!(&vec[..], &[1, 2]);
|
|
|
+ }
|
|
|
+ #[test]
|
|
|
+ fn extend_from_slice() {
|
|
|
+ use core_io::Write;
|
|
|
+
|
|
|
+ let mut vec = CVec::new();
|
|
|
+ vec.extend_from_slice(&[1, 2, 3]).unwrap();
|
|
|
+ vec.extend_from_slice(&[4, 5, 6]).unwrap();
|
|
|
+ assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6]);
|
|
|
+ assert_eq!(vec.write(&[7, 8, 9]).unwrap(), 3);
|
|
|
+ assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
|
+ }
|
|
|
+ #[test]
|
|
|
+ fn dropped() {
|
|
|
+ use alloc::rc::Rc;
|
|
|
+
|
|
|
+ let counter = Rc::new(());
|
|
|
+ let mut vec = CVec::with_capacity(3).unwrap();
|
|
|
+ vec.push(Rc::clone(&counter)).unwrap();
|
|
|
+ vec.push(Rc::clone(&counter)).unwrap();
|
|
|
+ vec.push(Rc::clone(&counter)).unwrap();
|
|
|
+ assert_eq!(Rc::strong_count(&counter), 4);
|
|
|
+
|
|
|
+ let popped = vec.pop().unwrap();
|
|
|
+ assert_eq!(Rc::strong_count(&counter), 4);
|
|
|
+ drop(popped);
|
|
|
+ assert_eq!(Rc::strong_count(&counter), 3);
|
|
|
+
|
|
|
+ vec.push(Rc::clone(&counter)).unwrap();
|
|
|
+ vec.push(Rc::clone(&counter)).unwrap();
|
|
|
+ vec.push(Rc::clone(&counter)).unwrap();
|
|
|
+
|
|
|
+ assert_eq!(vec.len(), 5);
|
|
|
+ assert_eq!(Rc::strong_count(&counter), 6);
|
|
|
+ vec.truncate(1);
|
|
|
+ assert_eq!(Rc::strong_count(&counter), 2);
|
|
|
+
|
|
|
+ drop(vec);
|
|
|
+ assert_eq!(Rc::strong_count(&counter), 1);
|
|
|
+ }
|
|
|
+}
|