Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions src/intoiter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
use std::{
mem,
ptr::{self, NonNull},
};

use crate::{RawVector, Vector};

use crate::alloc::{Allocator, Global};

pub struct IntoIter<T, A: Allocator = Global> {
_buf: RawVector<T>, // we don't actually care about this. Just need it to live.
iter: RawValIter<T>,
pub(crate) allocator: A,
}

impl<T, A: Allocator> Iterator for IntoIter<T, A> {
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> ExactSizeIterator for IntoIter<T> {}

impl<T, A: Allocator> Drop for IntoIter<T, A> {
fn drop(&mut self) {
// drop any remaining elements
for _ in &mut *self {}

unsafe {
self._buf.deallocate_no_drop(&self.allocator);
}
}
}

impl<T, A: Allocator> IntoIterator for Vector<T, A> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
let (iter, buf) = unsafe { (RawValIter::new(&self), ptr::read(&self.raw)) };

mem::forget(self);

IntoIter {
iter,
_buf: buf,
allocator: Global,
}
}
}

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.len() == 0 {
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 {
if mem::size_of::<T>() == 0 {
self.start = (self.start as usize + 1) as *const _;
Some(ptr::read(NonNull::<T>::dangling().as_ptr()))
} else {
let old_ptr = self.start;
self.start = self.start.offset(1);
Some(ptr::read(old_ptr))
}
}
}
}

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 {
if mem::size_of::<T>() == 0 {
self.end = (self.end as usize - 1) as *const _;
Some(ptr::read(NonNull::<T>::dangling().as_ptr()))
} else {
self.end = self.end.offset(-1);
Some(ptr::read(self.end))
}
}
}
}
}

impl<T> ExactSizeIterator for RawValIter<T> {}

#[cfg(test)]
mod tests {
use std::sync::atomic::AtomicUsize;

#[test]
fn into_iter_test() {
struct Foo {
value: Box<i32>,
}

impl Foo {
pub fn new(value: i32) -> Self {
Self {
value: Box::new(value),
}
}
}

impl Drop for Foo {
fn drop(&mut self) {}
}

let mut vector = crate::Vector::new();

for i in 0..=100 {
vector.push(Foo::new(i));
}

let resulting = vector.into_iter().collect::<Vec<_>>();

let sum = resulting.into_iter().map(|x| *x.value).sum::<i32>();

assert_eq!(sum, 5050)
}

#[test]
fn into_iter_drops_everything() {
static COUNTER: AtomicUsize = AtomicUsize::new(0);

struct Foo {
value: Box<i32>,
}

impl Foo {
pub fn new(value: i32) -> Self {
Self {
value: Box::new(value),
}
}
}

impl Drop for Foo {
fn drop(&mut self) {
COUNTER.fetch_add(1, std::sync::atomic::Ordering::Acquire);
}
}

let mut vector = crate::Vector::new();

for i in 0..=100 {
vector.push(Foo::new(i));
}

let resulting = vector.into_iter().collect::<Vec<_>>();
let sum = resulting.into_iter().map(|x| *x.value).sum::<i32>();
assert_eq!(sum, 5050);
assert_eq!(COUNTER.load(std::sync::atomic::Ordering::Relaxed), 101);
}

#[test]
fn into_iter_drops_everything_partial_usage() {
static COUNTER: AtomicUsize = AtomicUsize::new(0);

struct Foo {}

impl Foo {
pub fn new() -> Self {
Self {}
}
}

impl Drop for Foo {
fn drop(&mut self) {
COUNTER.fetch_add(1, std::sync::atomic::Ordering::Acquire);
}
}

let mut vector = crate::Vector::new();

for _ in 0..=100 {
vector.push(Foo::new());
}

let mut iter = vector.into_iter();

iter.next();
iter.next();

drop(iter);

assert_eq!(COUNTER.load(std::sync::atomic::Ordering::Relaxed), 101);
}
}
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#![cfg_attr(feature = "nightly", feature(allocator_api))]
#![doc = include_str!("../README.md")]

mod drain;
mod intoiter;
mod raw;
mod shared;
mod vector;
mod drain;
mod splice;
mod vector;

pub use raw::{AtomicRefCount, BufferSize, DefaultRefCount, RefCount};
pub use shared::{AtomicSharedVector, RefCountedVector, SharedVector};
pub use vector::{Vector, RawVector};
pub use vector::{RawVector, Vector};

pub use intoiter::IntoIter;

pub mod alloc {
pub use allocator_api2::alloc::{AllocError, Allocator, Global};
Expand Down
26 changes: 20 additions & 6 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ pub struct VecHeader {
}

impl VecHeader {
fn remaining_capacity(&self) -> u32 { self.cap - self.len }
fn remaining_capacity(&self) -> u32 {
self.cap - self.len
}
}

#[repr(C)]
Expand Down Expand Up @@ -173,8 +175,13 @@ impl<T, R: RefCount, A: Allocator> HeaderBuffer<T, R, A> {
}
}

pub unsafe fn move_data<T>(src_data: *mut T, src_vec: &mut VecHeader, dst_data: *mut T, dst_vec: &mut VecHeader) {
debug_assert!(dst_vec.cap - dst_vec.len >= src_vec.len);
pub unsafe fn move_data<T>(
src_data: *mut T,
src_vec: &mut VecHeader,
dst_data: *mut T,
dst_vec: &mut VecHeader,
) {
debug_assert!(dst_vec.cap - dst_vec.len >= src_vec.len);
let len = src_vec.len;
if len > 0 {
unsafe {
Expand All @@ -189,8 +196,11 @@ pub unsafe fn move_data<T>(src_data: *mut T, src_vec: &mut VecHeader, dst_data:
}
}

pub unsafe fn extend_from_slice_assuming_capacity<T: Clone>(data: *mut T, vec: &mut VecHeader, slice: &[T])
where
pub unsafe fn extend_from_slice_assuming_capacity<T: Clone>(
data: *mut T,
vec: &mut VecHeader,
slice: &[T],
) where
T: Clone,
{
let len = slice.len() as u32;
Expand All @@ -209,7 +219,11 @@ where
}

// Returns true if the iterator was emptied.
pub unsafe fn extend_within_capacity<T, I: Iterator<Item = T>>(data: *mut T, vec: &mut VecHeader, iter: &mut I) -> bool {
pub unsafe fn extend_within_capacity<T, I: Iterator<Item = T>>(
data: *mut T,
vec: &mut VecHeader,
iter: &mut I,
) -> bool {
let inital_len = vec.len;

let mut ptr = data.add(inital_len as usize);
Expand Down
Loading