rust/src/libcore/dvec.rs

262 lines
6.9 KiB
Rust
Raw Normal View History

2012-05-10 02:30:31 +02:00
// Dynamic Vector
//
// A growable vector that makes use of unique pointers so that the
// result can be sent between tasks and so forth.
//
// Note that recursive use is not permitted.
import dvec_iter::extensions;
import unsafe::reinterpret_cast;
import ptr::{null, extensions};
export dvec;
export from_vec;
export extensions;
export unwrap;
#[doc = "
A growable, modifiable vector type that accumulates elements into a
unique vector.
# Limitations on recursive use
This class works by swapping the unique vector out of the data
structure whenever it is to be used. Therefore, recursive use is not
permitted. That is, while iterating through a vector, you cannot
access the vector in any other way or else the program will fail. If
you wish, you can use the `swap()` method to gain access to the raw
vector and transform it or use it any way you like. Eventually, we
may permit read-only access during iteration or other use.
# WARNING
For maximum performance, this type is implemented using some rather
unsafe code. In particular, this innocent looking `[mut A]` pointer
*may be null!* Therefore, it is important you not reach into the
data structure manually but instead use the provided extensions.
The reason that I did not use an unsafe pointer in the structure
itself is that I wanted to ensure that the vector would be freed when
the dvec is dropped. The reason that I did not use an `option<T>`
instead of a nullable pointer is that I found experimentally that it
becomes approximately 50% slower. This can probably be improved
through optimization. You can run your own experiments using
`src/test/bench/vec-append.rs`. My own tests found that using null
pointers achieved about 103 million pushes/second. Using an option
type could only produce 47 million pushes/second.
"]
type dvec<A> = {
mut data: [mut A]
};
#[doc = "Creates a new, empty dvec"]
fn dvec<A>() -> dvec<A> {
{mut data: [mut]}
}
#[doc = "Creates a new dvec with a single element"]
fn from_elt<A>(+e: A) -> dvec<A> {
{mut data: [mut e]}
}
2012-05-10 02:30:31 +02:00
#[doc = "Creates a new dvec with the contents of a vector"]
fn from_vec<A>(+v: [mut A]) -> dvec<A> {
{mut data: v}
}
#[doc = "Consumes the vector and returns its contents"]
fn unwrap<A>(-d: dvec<A>) -> [mut A] {
let {data: v} <- d;
ret v;
}
impl private_methods<A> for dvec<A> {
fn check_not_borrowed() {
unsafe {
let data: *() = unsafe::reinterpret_cast(self.data);
if data.is_null() {
fail "Recursive use of dvec";
}
}
}
#[inline(always)]
fn borrow<B>(f: fn(-[mut A]) -> B) -> B {
unsafe {
let mut data = unsafe::reinterpret_cast(null::<()>());
data <-> self.data;
let data_ptr: *() = unsafe::reinterpret_cast(data);
if data_ptr.is_null() { fail "Recursive use of dvec"; }
ret f(data);
}
}
#[inline(always)]
fn return(-data: [mut A]) {
unsafe {
self.data <- data;
}
}
}
// In theory, most everything should work with any A, but in practice
// almost nothing works without the copy bound due to limitations
// around closures.
impl extensions<A> for dvec<A> {
#[doc = "
Swaps out the current vector and hands it off to a user-provided
function `f`. The function should transform it however is desired
and return a new vector to replace it with.
"]
fn swap(f: fn(-[mut A]) -> [mut A]) {
self.borrow { |v| self.return(f(v)) }
}
#[doc = "Returns the number of elements currently in the dvec"]
fn len() -> uint {
self.borrow { |v|
let l = v.len();
self.return(v);
l
}
}
#[doc = "Overwrite the current contents"]
fn set(+w: [mut A]) {
self.check_not_borrowed();
2012-06-15 15:23:58 +02:00
self.data <- w;
2012-05-10 02:30:31 +02:00
}
}
impl extensions<A:copy> for dvec<A> {
#[doc = "Append a single item to the end of the list"]
fn push(t: A) {
self.swap { |v|
let mut v <- v;
vec::push(v, t);
v
}
2012-05-10 02:30:31 +02:00
}
#[doc = "Remove and return the last element"]
fn pop() -> A {
self.borrow { |v|
let mut v <- v;
2012-05-10 02:30:31 +02:00
let result = vec::pop(v);
self.return(v);
result
}
}
#[doc = "
Append all elements of a vector to the end of the list
Equivalent to `append_iter()` but potentially more efficient.
"]
fn push_all(ts: [const A]/&) {
self.push_slice(ts, 0u, vec::len(ts));
}
#[doc = "
Appends elements from `from_idx` to `to_idx` (exclusive)
"]
fn push_slice(ts: [const A]/&, from_idx: uint, to_idx: uint) {
self.swap { |v|
let mut v <- v;
2012-05-10 02:30:31 +02:00
let new_len = vec::len(v) + to_idx - from_idx;
vec::reserve(v, new_len);
let mut i = from_idx;
while i < to_idx {
vec::push(v, ts[i]);
2012-05-10 02:30:31 +02:00
i += 1u;
}
v
}
}
#[doc = "
Append all elements of an iterable.
Failure will occur if the iterable's `each()` method
attempts to access this vector.
"]
fn append_iter<A, I:iter::base_iter<A>>(ts: I) {
self.swap { |v|
let mut v = alt ts.size_hint() {
none { v }
some(h) {
let len = v.len() + h;
let mut v <- v;
vec::reserve(v, len);
v
}
};
for ts.each { |t| v += [t] };
v
}
}
2012-05-10 02:30:31 +02:00
#[doc = "
Gets a copy of the current contents.
See `unwrap()` if you do not wish to copy the contents.
"]
fn get() -> [A] {
self.borrow { |v|
let w = vec::from_mut(copy v);
self.return(v);
w
}
}
#[doc = "Remove and return the first element"]
fn shift() -> A {
self.borrow { |v|
let mut v = vec::from_mut(v);
let result = vec::shift(v);
self.return(vec::to_mut(v));
result
}
}
#[doc = "Copy out an individual element"]
2012-05-15 22:41:15 +02:00
#[inline(always)]
2012-05-10 02:30:31 +02:00
fn [](idx: uint) -> A {
self.get_elt(idx)
}
#[doc = "Copy out an individual element"]
2012-05-15 22:41:15 +02:00
#[inline(always)]
2012-05-10 02:30:31 +02:00
fn get_elt(idx: uint) -> A {
self.check_not_borrowed();
ret self.data[idx];
}
#[doc = "Overwrites the contents of the element at `idx` with `a`"]
fn set_elt(idx: uint, a: A) {
self.check_not_borrowed();
self.data[idx] = a;
}
#[doc = "Overwrites the contents of the element at `idx` with `a`,
growing the vector if necessary. New elements will be initialized
with `initval`"]
2012-05-10 02:30:31 +02:00
fn grow_set_elt(idx: uint, initval: A, val: A) {
self.swap { |v|
let mut v <- v;
vec::grow_set(v, idx, initval, val);
v
}
2012-05-10 02:30:31 +02:00
}
#[doc = "Returns the last element, failing if the vector is empty"]
fn last() -> A {
self.get_elt(self.len() - 1u)
}
2012-05-10 02:30:31 +02:00
}