Created
November 7, 2018 10:30
-
-
Save ca7023/4c7527b2cc78c695da1091fbf7f340bb to your computer and use it in GitHub Desktop.
Toy Vec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(ptr_internals, alloc)] | |
use std::ops::{Deref, DerefMut}; | |
use std::ptr::{self, Unique}; | |
use std::{alloc, marker::PhantomData, mem}; | |
struct RawVec<T> { | |
ptr: Unique<T>, | |
cap: usize, | |
} | |
impl<T> RawVec<T> { | |
pub fn new() -> Self { | |
let cap = [0, !0][(mem::size_of::<T>() == 0) as usize]; | |
RawVec { | |
ptr: Unique::empty(), | |
cap, | |
} | |
} | |
fn grow(&mut self) { | |
unsafe { | |
let elem_size = mem::size_of::<T>(); | |
assert!(elem_size != 0, "capacity overflow"); | |
let align = mem::align_of::<T>(); | |
let layout = alloc::Layout::new::<T>(); | |
let (cap, ptr) = if self.cap == 0 { | |
let ptr = alloc::alloc(layout); | |
if ptr.is_null() { | |
alloc::handle_alloc_error(layout); | |
} | |
(1, ptr) | |
} else { | |
let new_cap = self.cap * 2; | |
let old_num_bytes = elem_size * self.cap; | |
assert!( | |
old_num_bytes <= (::std::isize::MAX as usize) / 2, | |
"capacity overflow" | |
); | |
let new_num_bytes = old_num_bytes * 2; | |
let layout = alloc::Layout::from_size_align_unchecked(old_num_bytes, align); | |
let ptr = alloc::realloc(self.ptr.as_ptr() as *mut _, layout, new_num_bytes); | |
if ptr.is_null() { | |
alloc::handle_alloc_error(layout); | |
} | |
(new_cap, ptr) | |
}; | |
self.cap = cap; | |
self.ptr = Unique::new(ptr as *mut _).unwrap(); | |
} | |
} | |
} | |
impl<T> Drop for RawVec<T> { | |
fn drop(&mut self) { | |
let elem_size = mem::size_of::<T>(); | |
if self.cap != 0 && elem_size != 0 { | |
unsafe { | |
let layout = alloc::Layout::from_size_align_unchecked( | |
self.cap * mem::size_of::<T>(), | |
mem::align_of::<T>(), | |
); | |
alloc::dealloc(self.ptr.as_ptr() as *mut _, layout); | |
} | |
} | |
} | |
} | |
pub struct Vec<T> { | |
buf: RawVec<T>, | |
len: usize, | |
} | |
impl<T> Default for Vec<T> { | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
impl<T> IntoIterator for Vec<T> { | |
type Item = T; | |
type IntoIter = IntoIter<T>; | |
fn into_iter(self) -> Self::IntoIter { | |
unsafe { | |
let buf = ptr::read(&self.buf); | |
let iter = RawValIter::new(&self); | |
mem::forget(self); | |
IntoIter { iter, _buf: buf } | |
} | |
} | |
} | |
impl<T> Vec<T> { | |
fn ptr(&self) -> *mut T { | |
self.buf.ptr.as_ptr() | |
} | |
fn cap(&self) -> usize { | |
self.buf.cap | |
} | |
pub fn new() -> Self { | |
Vec { | |
buf: RawVec::new(), | |
len: 0, | |
} | |
} | |
pub fn push(&mut self, elem: T) { | |
if self.len == self.cap() { | |
self.buf.grow(); | |
} | |
unsafe { | |
ptr::write(self.ptr().add(self.len), elem); | |
} | |
self.len += 1; | |
} | |
pub fn pop(&mut self) -> Option<T> { | |
if self.len == 0 { | |
None | |
} else { | |
self.len -= 1; | |
unsafe { Some(ptr::read(self.ptr().add(self.len))) } | |
} | |
} | |
pub fn insert(&mut self, index: usize, elem: T) { | |
assert!(index <= self.len, "index out of bounds"); | |
if self.len == self.cap() { | |
self.buf.grow(); | |
} | |
unsafe { | |
if index < self.len { | |
ptr::copy( | |
self.ptr().add(index), | |
self.ptr().add(index + 1), | |
self.len - index, | |
); | |
} | |
ptr::write(self.ptr().add(index), elem); | |
self.len += 1; | |
} | |
} | |
pub fn remove(&mut self, index: usize) -> T { | |
assert!(index < self.len, "index out of bounds"); | |
unsafe { | |
self.len -= 1; | |
let result = ptr::read(self.ptr().add(index)); | |
ptr::copy( | |
self.ptr().add(index + 1), | |
self.ptr().add(index), | |
self.len - index, | |
); | |
result | |
} | |
} | |
pub fn drain(&mut self) -> Drain<T> { | |
unsafe { | |
let iter = RawValIter::new(&self); | |
self.len = 0; | |
Drain { | |
iter, | |
vec: PhantomData, | |
} | |
} | |
} | |
} | |
impl<T> Drop for Vec<T> { | |
fn drop(&mut self) { | |
if self.buf.cap != 0 { | |
eprintln!("Dropping cap: {}", self.buf.cap); | |
while let Some(_) = self.pop() {} | |
} | |
} | |
} | |
impl<T> Deref for Vec<T> { | |
type Target = [T]; | |
fn deref(&self) -> &[T] { | |
unsafe { ::std::slice::from_raw_parts(self.ptr(), self.len) } | |
} | |
} | |
impl<T> DerefMut for Vec<T> { | |
fn deref_mut(&mut self) -> &mut [T] { | |
unsafe { ::std::slice::from_raw_parts_mut(self.ptr(), self.len) } | |
} | |
} | |
struct RawValIter<T> { | |
start: *const T, | |
end: *const T, | |
} | |
impl<T> RawValIter<T> { | |
unsafe fn new(slice: &[T]) -> Self { | |
RawValIter { | |
start: slice.as_ptr(), | |
end: if mem::size_of::<T>() == 0 { | |
(slice.as_ptr() as usize + slice.len()) as *const _ | |
} else if slice.is_empty() { | |
slice.as_ptr() | |
} else { | |
slice.as_ptr().add(slice.len()) | |
}, | |
} | |
} | |
} | |
impl<T> Iterator for RawValIter<T> { | |
type Item = T; | |
fn next(&mut self) -> Option<T> { | |
if self.start == self.end { | |
None | |
} else { | |
unsafe { | |
let result = ptr::read(self.start); | |
self.start = if mem::size_of::<T>() == 0 { | |
(self.start as usize + 1) as *const _ | |
} else { | |
self.start.offset(1) | |
}; | |
Some(result) | |
} | |
} | |
} | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
let elem_size = mem::size_of::<T>(); | |
let len = | |
(self.end as usize - self.start as usize) / if elem_size == 0 { 1 } else { elem_size }; | |
(len, Some(len)) | |
} | |
} | |
impl<T> DoubleEndedIterator for RawValIter<T> { | |
fn next_back(&mut self) -> Option<T> { | |
if self.start == self.end { | |
None | |
} else { | |
unsafe { | |
self.end = if mem::size_of::<T>() == 0 { | |
(self.end as usize - 1) as *const _ | |
} else { | |
self.end.offset(-1) | |
}; | |
Some(ptr::read(self.end)) | |
} | |
} | |
} | |
} | |
pub struct IntoIter<T> { | |
_buf: RawVec<T>, | |
iter: RawValIter<T>, | |
} | |
impl<T> Iterator for IntoIter<T> { | |
type Item = T; | |
fn next(&mut self) -> Option<T> { | |
self.iter.next() | |
} | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
self.iter.size_hint() | |
} | |
} | |
impl<T> DoubleEndedIterator for IntoIter<T> { | |
fn next_back(&mut self) -> Option<T> { | |
self.iter.next_back() | |
} | |
} | |
impl<T> Drop for IntoIter<T> { | |
fn drop(&mut self) { | |
for _ in &mut *self {} | |
} | |
} | |
pub struct Drain<'a, T: 'a> { | |
vec: PhantomData<&'a mut Vec<T>>, | |
iter: RawValIter<T>, | |
} | |
impl<'a, T> Iterator for Drain<'a, T> { | |
type Item = T; | |
fn next(&mut self) -> Option<T> { | |
self.iter.next() | |
} | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
self.iter.size_hint() | |
} | |
} | |
impl<'a, T> DoubleEndedIterator for Drain<'a, T> { | |
fn next_back(&mut self) -> Option<T> { | |
self.iter.next_back() | |
} | |
} | |
impl<'a, T> Drop for Drain<'a, T> { | |
fn drop(&mut self) { | |
for _ in &mut self.iter {} | |
} | |
} | |
fn main() { | |
let mut v = Vec::<i32>::new(); | |
v.push(3); | |
v.push(2); | |
v.push(1); | |
v.insert(1, 4); | |
v.insert(1, 8); | |
v.sort(); | |
v.remove(1); | |
println!("{:?}", v.pop()); | |
for i in v.into_iter().rev() { | |
print!("{} ", i); | |
} | |
println!(); | |
let mut v = Vec::<()>::new(); | |
v.push(()); | |
v.push(()); | |
v.push(()); | |
for i in v.into_iter() { | |
print!("{:?} ", i); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment