2012-09-20 17:33:52 -05:00
|
|
|
//! Managed vectors
|
2012-07-17 18:31:19 -05:00
|
|
|
|
2012-09-04 13:12:17 -05:00
|
|
|
use ptr::addr_of;
|
2012-07-17 18:31:19 -05:00
|
|
|
|
|
|
|
export init_op;
|
|
|
|
export capacity;
|
2012-08-23 12:22:14 -05:00
|
|
|
export build_sized, build, build_sized_opt;
|
2012-07-17 18:31:19 -05:00
|
|
|
export map;
|
|
|
|
export from_fn, from_elem;
|
2012-09-19 13:43:54 -05:00
|
|
|
export raw;
|
2012-09-19 20:00:26 -05:00
|
|
|
export traits;
|
2012-07-17 18:31:19 -05:00
|
|
|
|
|
|
|
/// Code for dealing with @-vectors. This is pretty incomplete, and
|
|
|
|
/// contains a bunch of duplication from the code for ~-vectors.
|
|
|
|
|
|
|
|
#[abi = "cdecl"]
|
|
|
|
extern mod rustrt {
|
2012-09-21 20:10:45 -05:00
|
|
|
#[legacy_exports];
|
2012-08-13 18:20:27 -05:00
|
|
|
fn vec_reserve_shared_actual(++t: *sys::TypeDesc,
|
2012-09-12 19:45:23 -05:00
|
|
|
++v: **vec::raw::VecRepr,
|
2012-07-17 18:31:19 -05:00
|
|
|
++n: libc::size_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[abi = "rust-intrinsic"]
|
|
|
|
extern mod rusti {
|
2012-09-21 20:10:45 -05:00
|
|
|
#[legacy_exports];
|
2012-07-17 18:31:19 -05:00
|
|
|
fn move_val_init<T>(&dst: T, -src: T);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of elements the vector can hold without reallocating
|
|
|
|
#[inline(always)]
|
|
|
|
pure fn capacity<T>(&&v: @[const T]) -> uint {
|
|
|
|
unsafe {
|
2012-09-18 13:18:56 -05:00
|
|
|
let repr: **raw::VecRepr =
|
2012-09-18 19:34:08 -05:00
|
|
|
::cast::reinterpret_cast(&addr_of(v));
|
2012-09-14 21:09:38 -05:00
|
|
|
(**repr).unboxed.alloc / sys::size_of::<T>()
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a vector by calling a provided function with an argument
|
|
|
|
* function that pushes an element to the back of a vector.
|
|
|
|
* This version takes an initial size for the vector.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * size - An initial size of the vector to reserve
|
|
|
|
* * builder - A function that will construct the vector. It recieves
|
|
|
|
* as an argument a function that will push an element
|
|
|
|
* onto the vector being constructed.
|
|
|
|
*/
|
|
|
|
#[inline(always)]
|
|
|
|
pure fn build_sized<A>(size: uint, builder: fn(push: pure fn(+A))) -> @[A] {
|
|
|
|
let mut vec = @[];
|
2012-09-18 13:18:56 -05:00
|
|
|
unsafe { raw::reserve(vec, size); }
|
|
|
|
builder(|+x| unsafe { raw::push(vec, move x) });
|
2012-08-01 19:30:05 -05:00
|
|
|
return vec;
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a vector by calling a provided function with an argument
|
|
|
|
* function that pushes an element to the back of a vector.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * builder - A function that will construct the vector. It recieves
|
|
|
|
* as an argument a function that will push an element
|
|
|
|
* onto the vector being constructed.
|
|
|
|
*/
|
|
|
|
#[inline(always)]
|
|
|
|
pure fn build<A>(builder: fn(push: pure fn(+A))) -> @[A] {
|
|
|
|
build_sized(4, builder)
|
|
|
|
}
|
|
|
|
|
2012-08-23 12:22:14 -05:00
|
|
|
/**
|
|
|
|
* Builds a vector by calling a provided function with an argument
|
|
|
|
* function that pushes an element to the back of a vector.
|
|
|
|
* This version takes an initial size for the vector.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * size - An option, maybe containing initial size of the vector to reserve
|
|
|
|
* * builder - A function that will construct the vector. It recieves
|
|
|
|
* as an argument a function that will push an element
|
|
|
|
* onto the vector being constructed.
|
|
|
|
*/
|
|
|
|
#[inline(always)]
|
2012-08-20 14:23:37 -05:00
|
|
|
pure fn build_sized_opt<A>(size: Option<uint>,
|
2012-08-23 12:22:14 -05:00
|
|
|
builder: fn(push: pure fn(+A))) -> @[A] {
|
|
|
|
build_sized(size.get_default(4), builder)
|
|
|
|
}
|
|
|
|
|
2012-08-08 16:30:30 -05:00
|
|
|
// Appending
|
|
|
|
#[inline(always)]
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn append<T: Copy>(lhs: @[T], rhs: &[const T]) -> @[T] {
|
2012-08-08 16:30:30 -05:00
|
|
|
do build_sized(lhs.len() + rhs.len()) |push| {
|
2012-09-18 23:41:37 -05:00
|
|
|
for vec::each(lhs) |x| { push(*x); }
|
2012-08-08 16:30:30 -05:00
|
|
|
for uint::range(0, rhs.len()) |i| { push(rhs[i]); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-17 18:31:19 -05:00
|
|
|
/// Apply a function to each element of a vector and return the results
|
|
|
|
pure fn map<T, U>(v: &[T], f: fn(T) -> U) -> @[U] {
|
|
|
|
do build_sized(v.len()) |push| {
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(v) |elem| {
|
2012-09-18 23:41:37 -05:00
|
|
|
push(f(*elem));
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates and initializes an immutable vector.
|
|
|
|
*
|
|
|
|
* Creates an immutable vector of size `n_elts` and initializes the elements
|
|
|
|
* to the value returned by the function `op`.
|
|
|
|
*/
|
2012-08-24 16:45:02 -05:00
|
|
|
pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> @[T] {
|
2012-07-17 18:31:19 -05:00
|
|
|
do build_sized(n_elts) |push| {
|
|
|
|
let mut i: uint = 0u;
|
|
|
|
while i < n_elts { push(op(i)); i += 1u; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates and initializes an immutable vector.
|
|
|
|
*
|
|
|
|
* Creates an immutable vector of size `n_elts` and initializes the elements
|
|
|
|
* to the value `t`.
|
|
|
|
*/
|
2012-09-07 16:52:28 -05:00
|
|
|
pure fn from_elem<T: Copy>(n_elts: uint, t: T) -> @[T] {
|
2012-07-17 18:31:19 -05:00
|
|
|
do build_sized(n_elts) |push| {
|
|
|
|
let mut i: uint = 0u;
|
|
|
|
while i < n_elts { push(t); i += 1u; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-08 16:30:30 -05:00
|
|
|
#[cfg(notest)]
|
2012-09-19 20:00:26 -05:00
|
|
|
mod traits {
|
2012-09-21 20:10:45 -05:00
|
|
|
#[legacy_exports];
|
2012-09-19 20:00:26 -05:00
|
|
|
#[cfg(stage0)]
|
|
|
|
impl<T: Copy> @[T]: Add<&[const T],@[T]> {
|
|
|
|
#[inline(always)]
|
|
|
|
pure fn add(rhs: &[const T]) -> @[T] {
|
|
|
|
append(self, rhs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(stage1)]
|
|
|
|
#[cfg(stage2)]
|
|
|
|
impl<T: Copy> @[T] : Add<&[const T],@[T]> {
|
|
|
|
#[inline(always)]
|
|
|
|
pure fn add(rhs: & &[const T]) -> @[T] {
|
|
|
|
append(self, (*rhs))
|
|
|
|
}
|
2012-08-08 16:30:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-19 20:00:26 -05:00
|
|
|
#[cfg(test)]
|
2012-09-21 20:10:45 -05:00
|
|
|
mod traits {
|
|
|
|
#[legacy_exports];}
|
2012-07-17 18:31:19 -05:00
|
|
|
|
2012-09-18 13:18:56 -05:00
|
|
|
mod raw {
|
2012-09-21 20:10:45 -05:00
|
|
|
#[legacy_exports];
|
2012-09-12 19:45:23 -05:00
|
|
|
type VecRepr = vec::raw::VecRepr;
|
|
|
|
type SliceRepr = vec::raw::SliceRepr;
|
2012-07-17 18:31:19 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the length of a vector
|
|
|
|
*
|
|
|
|
* This will explicitly set the size of the vector, without actually
|
|
|
|
* modifing its buffers, so it is up to the caller to ensure that
|
|
|
|
* the vector is actually the specified size.
|
|
|
|
*/
|
|
|
|
#[inline(always)]
|
|
|
|
unsafe fn set_len<T>(&&v: @[const T], new_len: uint) {
|
2012-09-18 19:34:08 -05:00
|
|
|
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(v));
|
2012-09-14 21:09:38 -05:00
|
|
|
(**repr).unboxed.fill = new_len * sys::size_of::<T>();
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
unsafe fn push<T>(&v: @[const T], +initval: T) {
|
2012-09-18 19:34:08 -05:00
|
|
|
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(v));
|
2012-09-14 21:09:38 -05:00
|
|
|
let fill = (**repr).unboxed.fill;
|
|
|
|
if (**repr).unboxed.alloc > fill {
|
2012-09-10 14:14:14 -05:00
|
|
|
push_fast(v, move initval);
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
|
|
|
else {
|
2012-09-10 14:14:14 -05:00
|
|
|
push_slow(v, move initval);
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
|
|
|
}
|
2012-07-30 13:21:40 -05:00
|
|
|
// This doesn't bother to make sure we have space.
|
|
|
|
#[inline(always)] // really pretty please
|
|
|
|
unsafe fn push_fast<T>(&v: @[const T], +initval: T) {
|
2012-09-18 19:34:08 -05:00
|
|
|
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(v));
|
2012-09-14 21:09:38 -05:00
|
|
|
let fill = (**repr).unboxed.fill;
|
|
|
|
(**repr).unboxed.fill += sys::size_of::<T>();
|
|
|
|
let p = ptr::addr_of((**repr).unboxed.data);
|
2012-07-30 13:21:40 -05:00
|
|
|
let p = ptr::offset(p, fill) as *mut T;
|
2012-09-11 19:17:54 -05:00
|
|
|
rusti::move_val_init(*p, move initval);
|
2012-07-30 13:21:40 -05:00
|
|
|
}
|
|
|
|
|
2012-07-17 18:31:19 -05:00
|
|
|
unsafe fn push_slow<T>(&v: @[const T], +initval: T) {
|
|
|
|
reserve_at_least(v, v.len() + 1u);
|
2012-09-10 14:14:14 -05:00
|
|
|
push_fast(v, move initval);
|
2012-07-17 18:31:19 -05:00
|
|
|
}
|
2012-07-30 13:21:40 -05:00
|
|
|
|
2012-07-17 18:31:19 -05:00
|
|
|
/**
|
|
|
|
* Reserves capacity for exactly `n` elements in the given vector.
|
|
|
|
*
|
|
|
|
* If the capacity for `v` is already equal to or greater than the
|
|
|
|
* requested capacity, then no action is taken.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * v - A vector
|
|
|
|
* * n - The number of elements to reserve space for
|
|
|
|
*/
|
|
|
|
unsafe fn reserve<T>(&v: @[const T], n: uint) {
|
|
|
|
// Only make the (slow) call into the runtime if we have to
|
|
|
|
if capacity(v) < n {
|
2012-08-14 18:54:13 -05:00
|
|
|
let ptr = addr_of(v) as **VecRepr;
|
2012-07-17 18:31:19 -05:00
|
|
|
rustrt::vec_reserve_shared_actual(sys::get_type_desc::<T>(),
|
|
|
|
ptr, n as libc::size_t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reserves capacity for at least `n` elements in the given vector.
|
|
|
|
*
|
|
|
|
* This function will over-allocate in order to amortize the
|
|
|
|
* allocation costs in scenarios where the caller may need to
|
|
|
|
* repeatedly reserve additional space.
|
|
|
|
*
|
|
|
|
* If the capacity for `v` is already equal to or greater than the
|
|
|
|
* requested capacity, then no action is taken.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * v - A vector
|
|
|
|
* * n - The number of elements to reserve space for
|
|
|
|
*/
|
|
|
|
unsafe fn reserve_at_least<T>(&v: @[const T], n: uint) {
|
|
|
|
reserve(v, uint::next_power_of_two(n));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2012-07-31 19:30:38 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test() {
|
|
|
|
// Some code that could use that, then:
|
|
|
|
fn seq_range(lo: uint, hi: uint) -> @[uint] {
|
|
|
|
do build |push| {
|
|
|
|
for uint::range(lo, hi) |i| {
|
|
|
|
push(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert seq_range(10, 15) == @[10, 11, 12, 13, 14];
|
|
|
|
assert from_fn(5, |x| x+1) == @[1, 2, 3, 4, 5];
|
|
|
|
assert from_elem(5, 3.14) == @[3.14, 3.14, 3.14, 3.14, 3.14];
|
2012-08-08 16:30:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn append_test() {
|
|
|
|
assert @[1,2,3] + @[4,5,6] == @[1,2,3,4,5,6];
|
|
|
|
}
|
|
|
|
|