/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! Small vectors in various sizes. These store a certain number of elements inline and fall back //! to the heap for larger allocations. use i = std::unstable::intrinsics::init; use std::cast; use std::libc::c_char; use std::mem; use std::num; use std::ptr; use std::rt::global_heap; use std::rt::local_heap; use std::unstable::intrinsics; use std::unstable::raw::Slice; use std::util; // Generic code for all small vectors trait SmallVecPrivate { unsafe fn set_len(&mut self, new_len: uint); unsafe fn set_cap(&mut self, new_cap: uint); fn data(&self, index: uint) -> *T; fn mut_data(&mut self, index: uint) -> *mut T; unsafe fn ptr(&self) -> *T; unsafe fn mut_ptr(&mut self) -> *mut T; unsafe fn set_ptr(&mut self, new_ptr: *mut T); } pub trait SmallVec : SmallVecPrivate { fn inline_size(&self) -> uint; fn len(&self) -> uint; fn cap(&self) -> uint; fn spilled(&self) -> bool { self.cap() > self.inline_size() } fn begin(&self) -> *T { unsafe { if self.spilled() { self.ptr() } else { self.data(0) } } } fn end(&self) -> *T { unsafe { self.begin().offset(self.len() as int) } } fn iter<'a>(&'a self) -> SmallVecIterator<'a,T> { SmallVecIterator { ptr: self.begin(), end: self.end(), lifetime: None, } } /// NB: For efficiency reasons (avoiding making a second copy of the inline elements), this /// actually clears out the original array instead of moving it. fn move_iter<'a>(&'a mut self) -> SmallVecMoveIterator<'a,T> { unsafe { let iter = cast::transmute(self.iter()); let ptr_opt = if self.spilled() { Some(cast::transmute(self.ptr())) } else { None }; let inline_size = self.inline_size(); self.set_cap(inline_size); self.set_len(0); SmallVecMoveIterator { allocation: ptr_opt, iter: iter, lifetime: None, } } } fn push(&mut self, value: T) { let cap = self.cap(); if self.len() == cap { self.grow(num::max(cap * 2, 1)) } unsafe { let end: &mut T = cast::transmute(self.end()); intrinsics::move_val_init(end, value); let len = self.len(); self.set_len(len + 1) } } fn grow(&mut self, new_cap: uint) { unsafe { let new_alloc: *mut T = cast::transmute(global_heap::malloc_raw(mem::size_of::() * new_cap)); ptr::copy_nonoverlapping_memory(new_alloc, self.begin(), self.len()); if self.spilled() { if intrinsics::owns_managed::() { local_heap::local_free(self.ptr() as *u8 as *c_char) } else { global_heap::exchange_free(self.ptr() as *u8 as *c_char) } } else { let mut_begin: *mut T = cast::transmute(self.begin()); intrinsics::set_memory(mut_begin, 0, self.len()) } self.set_ptr(new_alloc); self.set_cap(new_cap) } } fn get<'a>(&'a self, index: uint) -> &'a T { if index >= self.len() { self.fail_bounds_check(index) } unsafe { cast::transmute(self.begin().offset(index as int)) } } fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut T { if index >= self.len() { self.fail_bounds_check(index) } unsafe { cast::transmute(self.begin().offset(index as int)) } } fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [T] { assert!(start <= end); assert!(end <= self.len()); unsafe { cast::transmute(Slice { data: self.begin().offset(start as int), len: (end - start) }) } } fn as_slice<'a>(&'a self) -> &'a [T] { self.slice(0, self.len()) } fn mut_slice<'a>(&'a mut self, start: uint, end: uint) -> &'a mut [T] { assert!(start <= end); assert!(end <= self.len()); unsafe { cast::transmute(Slice { data: self.begin().offset(start as int), len: (end - start) }) } } fn mut_slice_from<'a>(&'a mut self, start: uint) -> &'a mut [T] { let len = self.len(); self.mut_slice(start, len) } fn fail_bounds_check(&self, index: uint) { fail!("index {} beyond length ({})", index, self.len()) } } pub struct SmallVecIterator<'a,T> { priv ptr: *T, priv end: *T, priv lifetime: Option<&'a T> } impl<'a,T> Iterator<&'a T> for SmallVecIterator<'a,T> { #[inline] fn next(&mut self) -> Option<&'a T> { unsafe { if self.ptr == self.end { return None } let old = self.ptr; self.ptr = if mem::size_of::() == 0 { cast::transmute(self.ptr as uint + 1) } else { self.ptr.offset(1) }; Some(cast::transmute(old)) } } } pub struct SmallVecMoveIterator<'a,T> { priv allocation: Option<*mut u8>, priv iter: SmallVecIterator<'static,T>, priv lifetime: Option<&'a T>, } impl<'a,T> Iterator for SmallVecMoveIterator<'a,T> { #[inline] fn next(&mut self) -> Option { unsafe { match self.iter.next() { None => None, Some(reference) => { // Zero out the values as we go so they don't get double-freed. let reference: &mut T = cast::transmute(reference); Some(util::replace(reference, intrinsics::init())) } } } } } #[unsafe_destructor] impl<'a,T> Drop for SmallVecMoveIterator<'a,T> { fn drop(&mut self) { // Destroy the remaining elements. for _ in *self {} match self.allocation { None => {} Some(allocation) => { unsafe { if intrinsics::owns_managed::() { local_heap::local_free(allocation as *u8 as *c_char) } else { global_heap::exchange_free(allocation as *u8 as *c_char) } } } } } } // Concrete implementations macro_rules! def_small_vector( ($name:ident, $size:expr) => ( pub struct $name { len: uint, cap: uint, ptr: *T, data: [T, ..$size], } ) ) macro_rules! def_small_vector_private_trait_impl( ($name:ident, $size:expr) => ( impl SmallVecPrivate for $name { unsafe fn set_len(&mut self, new_len: uint) { self.len = new_len } unsafe fn set_cap(&mut self, new_cap: uint) { self.cap = new_cap } fn data(&self, index: uint) -> *T { let ptr: *T = &self.data[index]; ptr } fn mut_data(&mut self, index: uint) -> *mut T { let ptr: *mut T = &mut self.data[index]; ptr } unsafe fn ptr(&self) -> *T { self.ptr } unsafe fn mut_ptr(&mut self) -> *mut T { cast::transmute(self.ptr) } unsafe fn set_ptr(&mut self, new_ptr: *mut T) { self.ptr = cast::transmute(new_ptr) } } ) ) macro_rules! def_small_vector_trait_impl( ($name:ident, $size:expr) => ( impl SmallVec for $name { fn inline_size(&self) -> uint { $size } fn len(&self) -> uint { self.len } fn cap(&self) -> uint { self.cap } } ) ) macro_rules! def_small_vector_drop_impl( ($name:ident, $size:expr) => ( #[unsafe_destructor] impl Drop for $name { fn drop(&mut self) { if !self.spilled() { return } unsafe { let ptr = self.mut_ptr(); for i in range(0, self.len()) { *ptr.offset(i as int) = intrinsics::uninit(); } if intrinsics::owns_managed::() { local_heap::local_free(self.ptr() as *u8 as *c_char) } else { global_heap::exchange_free(self.ptr() as *u8 as *c_char) } } } } ) ) macro_rules! def_small_vector_clone_impl( ($name:ident) => ( impl Clone for $name { fn clone(&self) -> $name { let mut new_vector = $name::new(); for element in self.iter() { new_vector.push((*element).clone()) } new_vector } } ) ) macro_rules! def_small_vector_impl( ($name:ident, $size:expr) => ( impl $name { #[inline] pub fn new() -> $name { unsafe { $name { len: 0, cap: $size, ptr: ptr::null(), data: intrinsics::init(), } } } } ) ) /// TODO(pcwalton): Remove in favor of `vec_ng` after a Rust upgrade. pub struct SmallVec0 { len: uint, cap: uint, ptr: *mut T, } impl SmallVecPrivate for SmallVec0 { unsafe fn set_len(&mut self, new_len: uint) { self.len = new_len } unsafe fn set_cap(&mut self, new_cap: uint) { self.cap = new_cap } fn data(&self, _: uint) -> *T { ptr::null() } fn mut_data(&mut self, _: uint) -> *mut T { ptr::mut_null() } unsafe fn ptr(&self) -> *T { cast::transmute(self.ptr) } unsafe fn mut_ptr(&mut self) -> *mut T { self.ptr } unsafe fn set_ptr(&mut self, new_ptr: *mut T) { self.ptr = new_ptr } } impl SmallVec for SmallVec0 { fn inline_size(&self) -> uint { 0 } fn len(&self) -> uint { self.len } fn cap(&self) -> uint { self.cap } } impl SmallVec0 { pub fn new() -> SmallVec0 { SmallVec0 { len: 0, cap: 0, ptr: ptr::mut_null(), } } } def_small_vector_drop_impl!(SmallVec0, 0) def_small_vector_clone_impl!(SmallVec0) def_small_vector!(SmallVec1, 1) def_small_vector_private_trait_impl!(SmallVec1, 1) def_small_vector_trait_impl!(SmallVec1, 1) def_small_vector_drop_impl!(SmallVec1, 1) def_small_vector_clone_impl!(SmallVec1) def_small_vector_impl!(SmallVec1, 1) def_small_vector!(SmallVec2, 2) def_small_vector_private_trait_impl!(SmallVec2, 2) def_small_vector_trait_impl!(SmallVec2, 2) def_small_vector_drop_impl!(SmallVec2, 2) def_small_vector_clone_impl!(SmallVec2) def_small_vector_impl!(SmallVec2, 2) def_small_vector!(SmallVec4, 4) def_small_vector_private_trait_impl!(SmallVec4, 4) def_small_vector_trait_impl!(SmallVec4, 4) def_small_vector_drop_impl!(SmallVec4, 4) def_small_vector_clone_impl!(SmallVec4) def_small_vector_impl!(SmallVec4, 4) def_small_vector!(SmallVec8, 8) def_small_vector_private_trait_impl!(SmallVec8, 8) def_small_vector_trait_impl!(SmallVec8, 8) def_small_vector_drop_impl!(SmallVec8, 8) def_small_vector_clone_impl!(SmallVec8) def_small_vector_impl!(SmallVec8, 8) def_small_vector!(SmallVec16, 16) def_small_vector_private_trait_impl!(SmallVec16, 16) def_small_vector_trait_impl!(SmallVec16, 16) def_small_vector_drop_impl!(SmallVec16, 16) def_small_vector_clone_impl!(SmallVec16) def_small_vector_impl!(SmallVec16, 16) def_small_vector!(SmallVec24, 24) def_small_vector_private_trait_impl!(SmallVec24, 24) def_small_vector_trait_impl!(SmallVec24, 24) def_small_vector_drop_impl!(SmallVec24, 24) def_small_vector_clone_impl!(SmallVec24) def_small_vector_impl!(SmallVec24, 24) def_small_vector!(SmallVec32, 32) def_small_vector_private_trait_impl!(SmallVec32, 32) def_small_vector_trait_impl!(SmallVec32, 32) def_small_vector_drop_impl!(SmallVec32, 32) def_small_vector_clone_impl!(SmallVec32) def_small_vector_impl!(SmallVec32, 32) #[cfg(test)] pub mod tests { use smallvec::{SmallVec, SmallVec0, SmallVec2, SmallVec16}; // We heap allocate all these strings so that double frees will show up under valgrind. #[test] pub fn test_inline() { let mut v = SmallVec16::new(); v.push(~"hello"); v.push(~"there"); assert_eq!(v.as_slice(), &[~"hello", ~"there"]); } #[test] pub fn test_spill() { let mut v = SmallVec2::new(); v.push(~"hello"); v.push(~"there"); v.push(~"burma"); v.push(~"shave"); assert_eq!(v.as_slice(), &[~"hello", ~"there", ~"burma", ~"shave"]); } #[test] pub fn test_double_spill() { let mut v = SmallVec2::new(); v.push(~"hello"); v.push(~"there"); v.push(~"burma"); v.push(~"shave"); v.push(~"hello"); v.push(~"there"); v.push(~"burma"); v.push(~"shave"); assert_eq!(v.as_slice(), &[ ~"hello", ~"there", ~"burma", ~"shave", ~"hello", ~"there", ~"burma", ~"shave", ]); } #[test] pub fn test_smallvec0() { let mut v = SmallVec0::new(); v.push(~"hello"); v.push(~"there"); v.push(~"burma"); v.push(~"shave"); v.push(~"hello"); v.push(~"there"); v.push(~"burma"); v.push(~"shave"); assert_eq!(v.as_slice(), &[ ~"hello", ~"there", ~"burma", ~"shave", ~"hello", ~"there", ~"burma", ~"shave", ]); } }