2012-12-10 19:32:48 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-07-06 20:20:36 -05:00
|
|
|
// chameneos
|
|
|
|
|
2014-02-14 12:10:06 -06:00
|
|
|
extern crate extra;
|
2013-05-24 21:35:29 -05:00
|
|
|
|
|
|
|
use std::option;
|
|
|
|
use std::os;
|
|
|
|
use std::task;
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
fn print_complements() {
|
2013-06-17 15:37:11 -05:00
|
|
|
let all = [Blue, Red, Yellow];
|
2013-08-03 11:45:23 -05:00
|
|
|
for aa in all.iter() {
|
|
|
|
for bb in all.iter() {
|
2014-01-09 04:06:55 -06:00
|
|
|
println!("{} + {} -> {}", show_color(*aa), show_color(*bb),
|
|
|
|
show_color(transform(*aa, *bb)));
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-07 23:43:12 -05:00
|
|
|
enum color { Red, Yellow, Blue }
|
2012-07-06 20:20:36 -05:00
|
|
|
|
2013-01-28 20:55:44 -06:00
|
|
|
struct CreatureInfo {
|
|
|
|
name: uint,
|
|
|
|
color: color
|
|
|
|
}
|
2012-07-06 20:20:36 -05:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn show_color(cc: color) -> ~str {
|
2014-01-19 02:21:14 -06:00
|
|
|
match cc {
|
2012-08-03 21:59:04 -05:00
|
|
|
Red => {~"red"}
|
|
|
|
Yellow => {~"yellow"}
|
|
|
|
Blue => {~"blue"}
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn show_color_list(set: ~[color]) -> ~str {
|
|
|
|
let mut out = ~"";
|
2013-08-03 11:45:23 -05:00
|
|
|
for col in set.iter() {
|
2013-06-11 21:13:42 -05:00
|
|
|
out.push_char(' ');
|
|
|
|
out.push_str(show_color(*col));
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return out;
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn show_digit(nn: uint) -> ~str {
|
2014-01-19 02:21:14 -06:00
|
|
|
match nn {
|
2012-08-03 21:59:04 -05:00
|
|
|
0 => {~"zero"}
|
|
|
|
1 => {~"one"}
|
|
|
|
2 => {~"two"}
|
|
|
|
3 => {~"three"}
|
|
|
|
4 => {~"four"}
|
|
|
|
5 => {~"five"}
|
|
|
|
6 => {~"six"}
|
|
|
|
7 => {~"seven"}
|
|
|
|
8 => {~"eight"}
|
|
|
|
9 => {~"nine"}
|
2013-10-21 15:08:31 -05:00
|
|
|
_ => {fail!("expected digits from 0 to 9...")}
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn show_number(nn: uint) -> ~str {
|
|
|
|
let mut out = ~"";
|
2012-07-06 20:20:36 -05:00
|
|
|
let mut num = nn;
|
|
|
|
let mut dig;
|
|
|
|
|
|
|
|
if num == 0 { out = show_digit(0) };
|
|
|
|
|
|
|
|
while num != 0 {
|
|
|
|
dig = num % 10;
|
|
|
|
num = num / 10;
|
2013-05-29 13:10:16 -05:00
|
|
|
out = show_digit(dig) + " " + out;
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
2013-06-16 15:23:45 -05:00
|
|
|
return ~" " + out;
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn transform(aa: color, bb: color) -> color {
|
2012-08-06 14:34:08 -05:00
|
|
|
match (aa, bb) {
|
2012-08-03 21:59:04 -05:00
|
|
|
(Red, Red ) => { Red }
|
|
|
|
(Red, Yellow) => { Blue }
|
|
|
|
(Red, Blue ) => { Yellow }
|
|
|
|
(Yellow, Red ) => { Blue }
|
|
|
|
(Yellow, Yellow) => { Yellow }
|
|
|
|
(Yellow, Blue ) => { Red }
|
|
|
|
(Blue, Red ) => { Yellow }
|
|
|
|
(Blue, Yellow) => { Red }
|
|
|
|
(Blue, Blue ) => { Blue }
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn creature(
|
|
|
|
name: uint,
|
|
|
|
color: color,
|
2013-01-29 01:54:39 -06:00
|
|
|
from_rendezvous: Port<Option<CreatureInfo>>,
|
Rewrite channels yet again for upgradeability
This, the Nth rewrite of channels, is not a rewrite of the core logic behind
channels, but rather their API usage. In the past, we had the distinction
between oneshot, stream, and shared channels, but the most recent rewrite
dropped oneshots in favor of streams and shared channels.
This distinction of stream vs shared has shown that it's not quite what we'd
like either, and this moves the `std::comm` module in the direction of "one
channel to rule them all". There now remains only one Chan and one Port.
This new channel is actually a hybrid oneshot/stream/shared channel under the
hood in order to optimize for the use cases in question. Additionally, this also
reduces the cognitive burden of having to choose between a Chan or a SharedChan
in an API.
My simple benchmarks show no reduction in efficiency over the existing channels
today, and a 3x improvement in the oneshot case. I sadly don't have a
pre-last-rewrite compiler to test out the old old oneshots, but I would imagine
that the performance is comparable, but slightly slower (due to atomic reference
counting).
This commit also brings the bonus bugfix to channels that the pending queue of
messages are all dropped when a Port disappears rather then when both the Port
and the Chan disappear.
2014-01-08 20:31:48 -06:00
|
|
|
to_rendezvous: Chan<CreatureInfo>,
|
|
|
|
to_rendezvous_log: Chan<~str>
|
2012-07-06 20:20:36 -05:00
|
|
|
) {
|
|
|
|
let mut color = color;
|
|
|
|
let mut creatures_met = 0;
|
|
|
|
let mut evil_clones_met = 0;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
// ask for a pairing
|
2013-01-29 01:54:39 -06:00
|
|
|
to_rendezvous.send(CreatureInfo {name: name, color: color});
|
|
|
|
let resp = from_rendezvous.recv();
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
// log and change, or print and quit
|
2012-08-06 14:34:08 -05:00
|
|
|
match resp {
|
2012-08-20 14:23:37 -05:00
|
|
|
option::Some(other_creature) => {
|
2012-07-06 20:20:36 -05:00
|
|
|
color = transform(color, other_creature.color);
|
|
|
|
|
|
|
|
// track some statistics
|
|
|
|
creatures_met += 1;
|
|
|
|
if other_creature.name == name {
|
|
|
|
evil_clones_met += 1;
|
|
|
|
}
|
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
option::None => {
|
2012-07-06 20:20:36 -05:00
|
|
|
// log creatures met and evil clones of self
|
2013-09-30 01:13:47 -05:00
|
|
|
let report = format!("{} {}",
|
|
|
|
creatures_met, show_number(evil_clones_met));
|
2013-01-29 01:54:39 -06:00
|
|
|
to_rendezvous_log.send(report);
|
2012-07-06 20:20:36 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rendezvous(nn: uint, set: ~[color]) {
|
2012-12-12 21:17:31 -06:00
|
|
|
|
2012-07-07 23:43:12 -05:00
|
|
|
// these ports will allow us to hear from the creatures
|
Rewrite channels yet again for upgradeability
This, the Nth rewrite of channels, is not a rewrite of the core logic behind
channels, but rather their API usage. In the past, we had the distinction
between oneshot, stream, and shared channels, but the most recent rewrite
dropped oneshots in favor of streams and shared channels.
This distinction of stream vs shared has shown that it's not quite what we'd
like either, and this moves the `std::comm` module in the direction of "one
channel to rule them all". There now remains only one Chan and one Port.
This new channel is actually a hybrid oneshot/stream/shared channel under the
hood in order to optimize for the use cases in question. Additionally, this also
reduces the cognitive burden of having to choose between a Chan or a SharedChan
in an API.
My simple benchmarks show no reduction in efficiency over the existing channels
today, and a 3x improvement in the oneshot case. I sadly don't have a
pre-last-rewrite compiler to test out the old old oneshots, but I would imagine
that the performance is comparable, but slightly slower (due to atomic reference
counting).
This commit also brings the bonus bugfix to channels that the pending queue of
messages are all dropped when a Port disappears rather then when both the Port
and the Chan disappear.
2014-01-08 20:31:48 -06:00
|
|
|
let (from_creatures, to_rendezvous) = Chan::<CreatureInfo>::new();
|
|
|
|
let (from_creatures_log, to_rendezvous_log) = Chan::<~str>::new();
|
2012-07-07 23:43:12 -05:00
|
|
|
|
|
|
|
// these channels will be passed to the creatures so they can talk to us
|
|
|
|
|
|
|
|
// these channels will allow us to talk to each creature by 'name'/index
|
2013-01-29 01:54:39 -06:00
|
|
|
let to_creature: ~[Chan<Option<CreatureInfo>>] =
|
2013-08-09 22:09:47 -05:00
|
|
|
set.iter().enumerate().map(|(ii, col)| {
|
2012-09-21 20:43:30 -05:00
|
|
|
// create each creature as a listener with a port, and
|
|
|
|
// give us a channel to talk to each
|
|
|
|
let ii = ii;
|
|
|
|
let col = *col;
|
2013-01-29 01:54:39 -06:00
|
|
|
let to_rendezvous = to_rendezvous.clone();
|
|
|
|
let to_rendezvous_log = to_rendezvous_log.clone();
|
2013-12-15 20:17:43 -06:00
|
|
|
let (from_rendezvous, to_creature) = Chan::new();
|
2014-01-27 17:29:50 -06:00
|
|
|
task::spawn(proc() {
|
2013-12-03 18:44:16 -06:00
|
|
|
creature(ii,
|
|
|
|
col,
|
|
|
|
from_rendezvous,
|
|
|
|
to_rendezvous.clone(),
|
2013-01-29 01:54:39 -06:00
|
|
|
to_rendezvous_log.clone());
|
2014-01-27 17:29:50 -06:00
|
|
|
});
|
2013-01-29 01:54:39 -06:00
|
|
|
to_creature
|
2013-06-29 00:05:50 -05:00
|
|
|
}).collect();
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
let mut creatures_met = 0;
|
|
|
|
|
|
|
|
// set up meetings...
|
2013-08-05 22:43:06 -05:00
|
|
|
for _ in range(0, nn) {
|
2013-01-29 01:54:39 -06:00
|
|
|
let fst_creature: CreatureInfo = from_creatures.recv();
|
|
|
|
let snd_creature: CreatureInfo = from_creatures.recv();
|
2012-07-07 23:43:12 -05:00
|
|
|
|
|
|
|
creatures_met += 2;
|
|
|
|
|
2013-01-29 01:54:39 -06:00
|
|
|
to_creature[fst_creature.name].send(Some(snd_creature));
|
|
|
|
to_creature[snd_creature.name].send(Some(fst_creature));
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// tell each creature to stop
|
2013-08-03 11:45:23 -05:00
|
|
|
for to_one in to_creature.iter() {
|
2013-01-29 01:54:39 -06:00
|
|
|
to_one.send(None);
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// save each creature's meeting stats
|
|
|
|
let mut report = ~[];
|
2013-08-03 11:45:23 -05:00
|
|
|
for _to_one in to_creature.iter() {
|
2013-01-29 01:54:39 -06:00
|
|
|
report.push(from_creatures_log.recv());
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// print each color in the set
|
2014-01-09 04:06:55 -06:00
|
|
|
println!("{}", show_color_list(set));
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
// print each creature's stats
|
2013-08-03 11:45:23 -05:00
|
|
|
for rep in report.iter() {
|
2014-01-09 04:06:55 -06:00
|
|
|
println!("{}", *rep);
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// print the total number of creatures met
|
2014-01-09 04:06:55 -06:00
|
|
|
println!("{}", show_number(creatures_met));
|
2012-07-06 20:20:36 -05:00
|
|
|
}
|
|
|
|
|
2012-10-03 21:16:27 -05:00
|
|
|
fn main() {
|
|
|
|
let args = os::args();
|
2013-07-17 14:31:20 -05:00
|
|
|
let args = if os::getenv("RUST_BENCH").is_some() {
|
2012-07-14 00:57:48 -05:00
|
|
|
~[~"", ~"200000"]
|
2012-07-08 00:39:23 -05:00
|
|
|
} else if args.len() <= 1u {
|
2012-07-14 00:57:48 -05:00
|
|
|
~[~"", ~"600"]
|
2012-07-06 20:20:36 -05:00
|
|
|
} else {
|
|
|
|
args
|
|
|
|
};
|
|
|
|
|
2013-09-15 00:27:32 -05:00
|
|
|
let nn = from_str::<uint>(args[1]).unwrap();
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
print_complements();
|
2014-01-09 04:06:55 -06:00
|
|
|
println!("");
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
rendezvous(nn, ~[Blue, Red, Yellow]);
|
2014-01-09 04:06:55 -06:00
|
|
|
println!("");
|
2012-07-06 20:20:36 -05:00
|
|
|
|
|
|
|
rendezvous(nn,
|
|
|
|
~[Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue]);
|
|
|
|
}
|