Skip to content

Commit b108ac2

Browse files
committed
add swappable/dvec modules
1 parent 11e9947 commit b108ac2

File tree

7 files changed

+452
-1
lines changed

7 files changed

+452
-1
lines changed

src/libcore/core.rc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export comm, task, future;
4141
export extfmt;
4242
export tuple;
4343
export to_str;
44+
export swappable;
45+
export dvec, dvec_iter;
4446

4547
// NDM seems to be necessary for resolve to work
4648
export vec_iter, option_iter;
@@ -168,7 +170,13 @@ mod option_iter {
168170
}
169171
mod result;
170172
mod to_str;
171-
173+
mod swappable;
174+
mod dvec;
175+
#[path="iter-trait"]
176+
mod dvec_iter {
177+
#[path = "dvec.rs"]
178+
mod inst;
179+
}
172180

173181
// Concurrency
174182
mod comm;

src/libcore/dvec.rs

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
// Dynamic Vector
2+
//
3+
// A growable vector that makes use of unique pointers so that the
4+
// result can be sent between tasks and so forth.
5+
//
6+
// Note that recursive use is not permitted.
7+
8+
import dvec_iter::extensions;
9+
import unsafe::reinterpret_cast;
10+
import ptr::{null, extensions};
11+
12+
export dvec;
13+
export from_vec;
14+
export extensions;
15+
export unwrap;
16+
17+
#[doc = "
18+
19+
A growable, modifiable vector type that accumulates elements into a
20+
unique vector.
21+
22+
# Limitations on recursive use
23+
24+
This class works by swapping the unique vector out of the data
25+
structure whenever it is to be used. Therefore, recursive use is not
26+
permitted. That is, while iterating through a vector, you cannot
27+
access the vector in any other way or else the program will fail. If
28+
you wish, you can use the `swap()` method to gain access to the raw
29+
vector and transform it or use it any way you like. Eventually, we
30+
may permit read-only access during iteration or other use.
31+
32+
# WARNING
33+
34+
For maximum performance, this type is implemented using some rather
35+
unsafe code. In particular, this innocent looking `[mut A]` pointer
36+
*may be null!* Therefore, it is important you not reach into the
37+
data structure manually but instead use the provided extensions.
38+
39+
The reason that I did not use an unsafe pointer in the structure
40+
itself is that I wanted to ensure that the vector would be freed when
41+
the dvec is dropped. The reason that I did not use an `option<T>`
42+
instead of a nullable pointer is that I found experimentally that it
43+
becomes approximately 50% slower. This can probably be improved
44+
through optimization. You can run your own experiments using
45+
`src/test/bench/vec-append.rs`. My own tests found that using null
46+
pointers achieved about 103 million pushes/second. Using an option
47+
type could only produce 47 million pushes/second.
48+
49+
"]
50+
type dvec<A> = {
51+
52+
mut data: [mut A]
53+
};
54+
55+
#[doc = "Creates a new, empty dvec"]
56+
fn dvec<A>() -> dvec<A> {
57+
{mut data: [mut]}
58+
}
59+
60+
#[doc = "Creates a new dvec with the contents of a vector"]
61+
fn from_vec<A>(+v: [mut A]) -> dvec<A> {
62+
{mut data: v}
63+
}
64+
65+
#[doc = "Consumes the vector and returns its contents"]
66+
fn unwrap<A>(-d: dvec<A>) -> [mut A] {
67+
let {data: v} <- d;
68+
ret v;
69+
}
70+
71+
impl private_methods<A> for dvec<A> {
72+
fn check_not_borrowed() {
73+
unsafe {
74+
let data: *() = unsafe::reinterpret_cast(self.data);
75+
if data.is_null() {
76+
fail "Recursive use of dvec";
77+
}
78+
}
79+
}
80+
81+
#[inline(always)]
82+
fn borrow<B>(f: fn(-[mut A]) -> B) -> B {
83+
unsafe {
84+
let mut data = unsafe::reinterpret_cast(null::<()>());
85+
data <-> self.data;
86+
let data_ptr: *() = unsafe::reinterpret_cast(data);
87+
if data_ptr.is_null() { fail "Recursive use of dvec"; }
88+
ret f(data);
89+
}
90+
}
91+
92+
#[inline(always)]
93+
fn return(-data: [mut A]) {
94+
unsafe {
95+
self.data <- data;
96+
}
97+
}
98+
}
99+
100+
// In theory, most everything should work with any A, but in practice
101+
// almost nothing works without the copy bound due to limitations
102+
// around closures.
103+
impl extensions<A> for dvec<A> {
104+
#[doc = "
105+
106+
Swaps out the current vector and hands it off to a user-provided
107+
function `f`. The function should transform it however is desired
108+
and return a new vector to replace it with.
109+
110+
"]
111+
fn swap(f: fn(-[mut A]) -> [mut A]) {
112+
self.borrow { |v| self.return(f(v)) }
113+
}
114+
115+
#[doc = "Returns the number of elements currently in the dvec"]
116+
fn len() -> uint {
117+
self.borrow { |v|
118+
let l = v.len();
119+
self.return(v);
120+
l
121+
}
122+
}
123+
124+
#[doc = "Overwrite the current contents"]
125+
fn set(+w: [mut A]) {
126+
self.check_not_borrowed();
127+
self.data <- w; //FIXME check for recursive use
128+
}
129+
}
130+
131+
impl extensions<A:copy> for dvec<A> {
132+
#[doc = "Append a single item to the end of the list"]
133+
fn push(t: A) {
134+
self.swap { |v| v += [t]; v } // more efficient than v + [t]
135+
}
136+
137+
#[doc = "Remove and return the last element"]
138+
fn pop() -> A {
139+
self.borrow { |v|
140+
let result = vec::pop(v);
141+
self.return(v);
142+
result
143+
}
144+
}
145+
146+
#[doc = "
147+
Append all elements of a vector to the end of the list
148+
149+
Equivalent to `append_iter()` but potentially more efficient.
150+
"]
151+
fn push_all(ts: [const A]/&) {
152+
self.push_slice(ts, 0u, vec::len(ts));
153+
}
154+
155+
#[doc = "
156+
Appends elements from `from_idx` to `to_idx` (exclusive)
157+
"]
158+
fn push_slice(ts: [const A]/&, from_idx: uint, to_idx: uint) {
159+
self.swap { |v|
160+
let new_len = vec::len(v) + to_idx - from_idx;
161+
vec::reserve(v, new_len);
162+
let mut i = from_idx;
163+
while i < to_idx {
164+
v += [ts[i]];
165+
i += 1u;
166+
}
167+
v
168+
}
169+
}
170+
171+
//FIXME--
172+
//#[doc = "
173+
// Append all elements of an iterable.
174+
//
175+
// Failure will occur if the iterable's `each()` method
176+
// attempts to access this vector.
177+
//"]
178+
//fn append_iter<I:iter::base<A>>(ts: I) {
179+
// self.dvec.swap { |v|
180+
// alt ts.size_hint() {
181+
// none {}
182+
// some(h) { vec::reserve(v, len(v) + h) }
183+
// }
184+
//
185+
// for ts.each { |t| v = v + [t] };
186+
//
187+
// v
188+
// }
189+
//}
190+
191+
#[doc = "
192+
Gets a copy of the current contents.
193+
194+
See `unwrap()` if you do not wish to copy the contents.
195+
"]
196+
fn get() -> [A] {
197+
self.borrow { |v|
198+
let w = vec::from_mut(copy v);
199+
self.return(v);
200+
w
201+
}
202+
}
203+
204+
#[doc = "Remove and return the first element"]
205+
fn shift() -> A {
206+
self.borrow { |v|
207+
let mut v = vec::from_mut(v);
208+
let result = vec::shift(v);
209+
self.return(vec::to_mut(v));
210+
result
211+
}
212+
}
213+
214+
#[doc = "Copy out an individual element"]
215+
#[inline]
216+
fn [](idx: uint) -> A {
217+
self.get_elt(idx)
218+
}
219+
220+
#[doc = "Copy out an individual element"]
221+
#[inline]
222+
fn get_elt(idx: uint) -> A {
223+
self.check_not_borrowed();
224+
ret self.data[idx];
225+
}
226+
227+
#[doc = "Overwrites the contents of the element at `idx` with `a`"]
228+
fn set_elt(idx: uint, a: A) {
229+
self.check_not_borrowed();
230+
self.data[idx] = a;
231+
}
232+
233+
#[doc = "Overwrites the contents of the element at `idx` with `a`"]
234+
fn grow_set_elt(idx: uint, initval: A, val: A) {
235+
self.swap { |v| vec::grow_set(v, idx, initval, val); v }
236+
}
237+
}

src/libcore/iter-trait/dvec.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
type IMPL_T<A> = dvec::dvec<A>;
2+
3+
#[doc = "
4+
Iterates through the current contents.
5+
6+
Attempts to access this dvec during iteration will fail.
7+
"]
8+
fn EACH<A>(self: IMPL_T<A>, f: fn(A) -> bool) {
9+
import dvec::extensions;
10+
self.swap { |v| vec::each(v, f); v }
11+
}
12+
13+
fn SIZE_HINT<A>(self: IMPL_T<A>) -> option<uint> {
14+
import dvec::extensions;
15+
some(self.len())
16+
}

src/libcore/swappable.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
export swappable;
2+
export unwrap;
3+
export methods;
4+
5+
#[doc = "
6+
A value that may be swapped out temporarily while it is being processed
7+
and then replaced. Swappables are most useful when working with unique
8+
values, which often cannot be mutated unless they are stored in the local
9+
stack frame to ensure memory safety.
10+
11+
The type guarantees the invariant that the value is always \"swapped in\"
12+
except during the execution of the `swap()` and `with()` methods.
13+
"]
14+
type swappable<A> = {
15+
mut o_t: option<A>
16+
};
17+
18+
#[doc = "Create a swappable swapped in with a given initial value"]
19+
fn swappable<A>(+t: A) -> swappable<A> {
20+
{mut o_t: some(t)}
21+
}
22+
23+
#[doc = "Consumes a swappable and returns its contents without copying"]
24+
fn unwrap<A>(-s: swappable<A>) -> A {
25+
let {o_t: o_t} <- s;
26+
option::unwrap(o_t)
27+
}
28+
29+
impl methods<A> for swappable<A> {
30+
#[doc = "
31+
Overwrites the contents of the swappable
32+
"]
33+
fn set(+a: A) {
34+
self.o_t <- some(a);
35+
}
36+
37+
#[doc = "
38+
Invokes `f()` with the current value but replaces the
39+
current value when complete. Returns the result of `f()`.
40+
41+
Attempts to read or access the receiver while `f()` is executing
42+
will fail dynamically.
43+
"]
44+
fn with<B>(f: fn(A) -> B) -> B {
45+
let mut o_u = none;
46+
self.swap { |t| o_u <- some(f(t)); t }
47+
option::unwrap(o_u)
48+
}
49+
50+
#[doc = "
51+
Invokes `f()` with the current value and then replaces the
52+
current value with the result of `f()`.
53+
54+
Attempts to read or access the receiver while `f()` is executing
55+
will fail dynamically.
56+
"]
57+
fn swap(f: fn(-A) -> A) {
58+
alt self.o_t {
59+
none { fail "no value present---already swapped?"; }
60+
some(_) {}
61+
}
62+
63+
let mut o_t = none;
64+
o_t <-> self.o_t;
65+
self.o_t <- some(f(option::unwrap(o_t)));
66+
}
67+
68+
#[doc = "True if there is a value present in this swappable"]
69+
fn is_present() -> bool {
70+
alt self.o_t {
71+
none {false}
72+
some(_) {true}
73+
}
74+
}
75+
76+
#[doc = "
77+
Removes the value from the swappable. Any further attempts
78+
to use the swapabble without first invoking `set()` will fail.
79+
"]
80+
fn take() -> A {
81+
alt self.o_t {
82+
none { fail "swapped out"; }
83+
some(_) {}
84+
}
85+
86+
let mut o_t = none;
87+
option::unwrap(o_t)
88+
}
89+
}
90+
91+
impl methods<A:copy> for swappable<A> {
92+
#[doc = "
93+
Copies out the contents of the swappable
94+
"]
95+
fn get() -> A {
96+
self.o_t.get()
97+
}
98+
}

0 commit comments

Comments
 (0)