Skip to content

Commit

Permalink
auto merge of #6260 : alexcrichton/rust/issue-3466-no-swap, r=pcwalton
Browse files Browse the repository at this point in the history
There may be a more efficient implementation of `core::util::swap_ptr`. The issue mentioned using `move_val_init`, but I couldn't figure out what that did, so I just used `copy_memory` a few times instead.

I'm not exactly the best at reading LLVM generated by rust, but this does appear to be optimized away just as expected (when possible).
  • Loading branch information
bors committed May 11, 2013
2 parents c49cf8b + 60803e5 commit 9f106a6
Show file tree
Hide file tree
Showing 48 changed files with 296 additions and 430 deletions.
31 changes: 1 addition & 30 deletions doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -1946,35 +1946,6 @@ fn avg(v: &[float]) -> float {
}
~~~~

#### Swap expressions

A _swap expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) followed by a bi-directional arrow (`<->`) and another [lvalue](#lvalues-rvalues-and-temporaries).

Evaluating a swap expression causes, as a side effect, the values held in the left-hand-side and right-hand-side [lvalues](#lvalues-rvalues-and-temporaries) to be exchanged indivisibly.

Evaluating a swap expression neither changes reference counts,
nor deeply copies any owned structure pointed to by the moved [rvalue](#lvalues-rvalues-and-temporaries).
Instead, the swap expression represents an indivisible *exchange of ownership*,
between the right-hand-side and the left-hand-side of the expression.
No allocation or destruction is entailed.

An example of three different swap expressions:

~~~~~~~~
# let mut x = &mut [0];
# let mut a = &mut [0];
# let i = 0;
# struct S1 { z: int };
# struct S2 { c: int };
# let mut y = S1{z: 0};
# let mut b = S2{c: 0};
x <-> a;
x[i] <-> a[i];
y.z <-> b.c;
~~~~~~~~


#### Assignment expressions

An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
Expand Down Expand Up @@ -2015,7 +1986,7 @@ as
== !=
&&
||
= <->
=
~~~~

Operators at the same precedence level are evaluated left-to-right.
Expand Down
4 changes: 3 additions & 1 deletion doc/tutorial-ffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ wrapping `malloc` and `free`:
~~~~
use core::libc::{c_void, size_t, malloc, free};
use core::unstable::intrinsics;
use core::util;
// a wrapper around the handle returned by the foreign code
pub struct Unique<T> {
Expand Down Expand Up @@ -184,7 +185,8 @@ impl<T: Owned> Drop for Unique<T> {
fn finalize(&self) {
unsafe {
let mut x = intrinsics::init(); // dummy value to swap in
x <-> *self.ptr; // moving the object out is needed to call the destructor
// moving the object out is needed to call the destructor
util::replace_ptr(self.ptr, x);
free(self.ptr as *c_void)
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use cast::transmute_mut;
use prelude::*;
use util::replace;

/*
A dynamic, mutable location.
Expand Down Expand Up @@ -48,9 +49,7 @@ pub impl<T> Cell<T> {
fail!(~"attempt to take an empty cell");
}
let mut value = None;
value <-> self.value;
value.unwrap()
replace(&mut self.value, None).unwrap()
}
/// Returns the value, failing if the cell is full.
Expand Down
29 changes: 11 additions & 18 deletions src/libcore/comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use uint;
use unstable;
use vec;
use unstable::Exclusive;
use util::replace;

use pipes::{recv, try_recv, wait_many, peek, PacketHeader};

Expand Down Expand Up @@ -149,9 +150,8 @@ impl<T: Owned> GenericChan<T> for Chan<T> {
#[inline(always)]
fn send(&self, x: T) {
unsafe {
let mut endp = None;
let mut self_endp = transmute_mut(&self.endp);
endp <-> *self_endp;
let endp = replace(self_endp, None);
*self_endp = Some(streamp::client::data(endp.unwrap(), x))
}
}
Expand All @@ -161,9 +161,8 @@ impl<T: Owned> GenericSmartChan<T> for Chan<T> {
#[inline(always)]
fn try_send(&self, x: T) -> bool {
unsafe {
let mut endp = None;
let mut self_endp = transmute_mut(&self.endp);
endp <-> *self_endp;
let endp = replace(self_endp, None);
match streamp::client::try_data(endp.unwrap(), x) {
Some(next) => {
*self_endp = Some(next);
Expand All @@ -179,9 +178,8 @@ impl<T: Owned> GenericPort<T> for Port<T> {
#[inline(always)]
fn recv(&self) -> T {
unsafe {
let mut endp = None;
let mut self_endp = transmute_mut(&self.endp);
endp <-> *self_endp;
let endp = replace(self_endp, None);
let streamp::data(x, endp) = recv(endp.unwrap());
*self_endp = Some(endp);
x
Expand All @@ -191,9 +189,8 @@ impl<T: Owned> GenericPort<T> for Port<T> {
#[inline(always)]
fn try_recv(&self) -> Option<T> {
unsafe {
let mut endp = None;
let mut self_endp = transmute_mut(&self.endp);
endp <-> *self_endp;
let endp = replace(self_endp, None);
match try_recv(endp.unwrap()) {
Some(streamp::data(x, endp)) => {
*self_endp = Some(endp);
Expand All @@ -209,14 +206,13 @@ impl<T: Owned> Peekable<T> for Port<T> {
#[inline(always)]
fn peek(&self) -> bool {
unsafe {
let mut endp = None;
let mut self_endp = transmute_mut(&self.endp);
endp <-> *self_endp;
let mut endp = replace(self_endp, None);
let peek = match endp {
Some(ref mut endp) => peek(endp),
None => fail!(~"peeking empty stream")
};
*self_endp <-> endp;
*self_endp = endp;
peek
}
}
Expand Down Expand Up @@ -267,8 +263,7 @@ impl<T:Owned> GenericPort<T> for PortSet<T> {
let mut result = None;
// we have to swap the ports array so we aren't borrowing
// aliasable mutable memory.
let mut ports = ~[];
ports <-> *self_ports;
let mut ports = replace(self_ports, ~[]);
while result.is_none() && ports.len() > 0 {
let i = wait_many(ports);
match ports[i].try_recv() {
Expand All @@ -281,7 +276,7 @@ impl<T:Owned> GenericPort<T> for PortSet<T> {
}
}
}
ports <-> *self_ports;
*self_ports = ports;
result
}
}
Expand Down Expand Up @@ -320,8 +315,7 @@ impl<T: Owned> GenericChan<T> for SharedChan<T> {
fn send(&self, x: T) {
let mut xx = Some(x);
do self.ch.with_imm |chan| {
let mut x = None;
x <-> xx;
let x = replace(&mut xx, None);
chan.send(x.unwrap())
}
}
Expand All @@ -331,8 +325,7 @@ impl<T: Owned> GenericSmartChan<T> for SharedChan<T> {
fn try_send(&self, x: T) -> bool {
let mut xx = Some(x);
do self.ch.with_imm |chan| {
let mut x = None;
x <-> xx;
let x = replace(&mut xx, None);
chan.try_send(x.unwrap())
}
}
Expand Down
24 changes: 8 additions & 16 deletions src/libcore/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,13 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
/// Expands the capacity of the array and re-insert each of the
/// existing buckets.
fn resize(&mut self, new_capacity: uint) {
let old_capacity = self.buckets.len();
self.resize_at = resize_at(new_capacity);

let mut old_buckets = vec::from_fn(new_capacity, |_| None);
self.buckets <-> old_buckets;
let old_buckets = replace(&mut self.buckets,
vec::from_fn(new_capacity, |_| None));

self.size = 0;
for uint::range(0, old_capacity) |i| {
let mut bucket = None;
bucket <-> old_buckets[i];
do vec::consume(old_buckets) |_, bucket| {
self.insert_opt_bucket(bucket);
}
}
Expand Down Expand Up @@ -265,13 +262,11 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
};
let len_buckets = self.buckets.len();
let mut bucket = None;
self.buckets[idx] <-> bucket;
let bucket = replace(&mut self.buckets[idx], None);
let value = match bucket {
None => None,
Some(bucket) => {
let Bucket{value: value, _} = bucket;
Some(Bucket{value, _}) => {
Some(value)
},
};
Expand All @@ -281,8 +276,7 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
let size = self.size - 1;
idx = self.next_bucket(idx, len_buckets);
while self.buckets[idx].is_some() {
let mut bucket = None;
bucket <-> self.buckets[idx];
let bucket = replace(&mut self.buckets[idx], None);
self.insert_opt_bucket(bucket);
idx = self.next_bucket(idx, len_buckets);
}
Expand Down Expand Up @@ -613,15 +607,13 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> {
}
fn consume(&mut self, f: &fn(K, V)) {
let mut buckets = ~[];
self.buckets <-> buckets;
let buckets = replace(&mut self.buckets, ~[]);
self.size = 0;
do vec::consume(buckets) |_, bucket| {
match bucket {
None => {},
Some(bucket) => {
let Bucket{key: key, value: value, _} = bucket;
Some(Bucket{key, value, _}) => {
f(key, value)
}
}
Expand Down
29 changes: 9 additions & 20 deletions src/libcore/pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ use unstable::intrinsics;
use ptr;
use task;
use vec;
use util::replace;

static SPIN_COUNT: uint = 0;

Expand Down Expand Up @@ -428,8 +429,7 @@ fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> {
// optimistic path
match p.header.state {
Full => {
let mut payload = None;
payload <-> p.payload;
let payload = replace(&mut p.payload, None);
p.header.state = Empty;
return Some(payload.unwrap())
},
Expand Down Expand Up @@ -480,8 +480,7 @@ fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> {
fail!(~"blocking on already blocked packet")
},
Full => {
let mut payload = None;
payload <-> p.payload;
let payload = replace(&mut p.payload, None);
let old_task = swap_task(&mut p.header.blocked_task, ptr::null());
if !old_task.is_null() {
unsafe {
Expand Down Expand Up @@ -675,8 +674,7 @@ impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> {
unsafe {
let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self);
if this.p != None {
let mut p = None;
p <-> this.p;
let p = replace(&mut this.p, None);
sender_terminate(p.unwrap())
}
}
Expand All @@ -695,9 +693,7 @@ pub fn SendPacketBuffered<T,Tbuffer>(p: *mut Packet<T>)
pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> {
fn unwrap(&mut self) -> *mut Packet<T> {
let mut p = None;
p <-> self.p;
p.unwrap()
replace(&mut self.p, None).unwrap()
}
fn header(&mut self) -> *mut PacketHeader {
Expand All @@ -713,9 +709,7 @@ pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> {
fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> {
//error!("send reuse_buffer");
let mut tmp = None;
tmp <-> self.buffer;
tmp.unwrap()
replace(&mut self.buffer, None).unwrap()
}
}
Expand All @@ -738,8 +732,7 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> {
unsafe {
let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self);
if this.p != None {
let mut p = None;
p <-> this.p;
let p = replace(&mut this.p, None);
receiver_terminate(p.unwrap())
}
}
Expand All @@ -748,15 +741,11 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> {
pub impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> {
fn unwrap(&mut self) -> *mut Packet<T> {
let mut p = None;
p <-> self.p;
p.unwrap()
replace(&mut self.p, None).unwrap()
}
fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> {
let mut tmp = None;
tmp <-> self.buffer;
tmp.unwrap()
replace(&mut self.buffer, None).unwrap()
}
}
Expand Down
Loading

0 comments on commit 9f106a6

Please sign in to comment.