<commit_before>extern crate futures;
extern crate text_ui;
extern crate tokio;
extern crate tokio_serde_msgpack;
extern crate tokio_uds;
extern crate weaver;

use text_ui::app::App;
use text_ui::backend::Backend;
use text_ui::widget::{shared, DbgDump, Linear, Shared, Text, TextInput};
use text_ui::{Event, Input, Key};

use std::collections::BTreeMap;
use std::fmt;
use std::sync::mpsc::Sender;
use std::sync::{Arc, RwLock};
use std::thread;

use futures::sync::mpsc::SendError as FutureSendError;
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use futures::AsyncSink;

use tokio::prelude::{task, Async, Future, Sink, Stream};
use tokio_serde_msgpack::{from_io, MsgPackReader, MsgPackWriter};
use tokio_uds::UnixStream;

use weaver::{weaver_socket_path, ClientMessage, ClientRequest, ServerMessage, WeaverCommand};

#[derive(Debug, PartialEq)]
pub enum WeaverNotification {
    Updated,
    Server(ServerMessage),
}

pub struct WeaverState {
    pub command_history: BTreeMap<usize, WeaverCommand>,
    pub commands_tx: UnboundedSender<ClientMessage>,
    msgcounter: u32,
}

impl fmt::Debug for WeaverState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("WeaverState")
            .field("command_history", &self.command_history)
            .finish()
    }
}

impl WeaverState {
    pub fn new(commands_tx: UnboundedSender<ClientMessage>) -> Self {
        let command_history = BTreeMap::new();
        let msgcounter = 0;
        WeaverState {
            commands_tx,
            command_history,
            msgcounter,
        }
    }
    pub fn run_command(
        &mut self,
        cmd: String,
    ) -> Result<(), FutureSendError<weaver::ClientMessage>> {
        let request = ClientRequest::RunCommand(cmd);
        self.send_request(request)
    }

    pub fn send_request(
        &mut self,
        request: ClientRequest,
    ) -> Result<(), FutureSendError<weaver::ClientMessage>> {
        self.msgcounter += 1;
        let id = self.msgcounter;
        let msg = ClientMessage { id, request };
        self.commands_tx.unbounded_send(msg)
    }
}

pub struct WeaverClient<'a> {
    commands_rx: UnboundedReceiver<ClientMessage>,
    socket_rx: MsgPackReader<'a, UnixStream, ServerMessage>,
    socket_tx: MsgPackWriter<UnixStream, ClientMessage>,
    pub state: Arc<RwLock<WeaverState>>,
    pub notifications: Sender<WeaverNotification>,
    overflow: Option<ClientMessage>,
}

impl<'a> WeaverClient<'a> {
    pub fn new(notifications: Sender<WeaverNotification>) -> Self {
        let (commands_tx, commands_rx): (
            UnboundedSender<ClientMessage>,
            UnboundedReceiver<ClientMessage>,
        ) = unbounded();

        let state = Arc::new(RwLock::new(WeaverState::new(commands_tx)));
        let overflow = None;

        let socketpath = weaver_socket_path();
        let socket = UnixStream::connect(socketpath);
        let (socket_rx, socket_tx): (
            MsgPackReader<UnixStream, ServerMessage>,
            MsgPackWriter<UnixStream, ClientMessage>,
        ) = from_io(socket.expect("Could not connect to weaver daemon"));
        //let socket_tx = socket_tx.sink_map_err(|e| println!("Send Err: {:#?}", e));
        //let socket_rx = socket_rx.map_err(|e| panic!("Decode Error: {:#?}", e));

        WeaverClient {
            commands_rx,
            socket_rx,
            socket_tx,
            notifications,
            state,
            overflow,
        }
    }

    fn do_update(&mut self, msg: ServerMessage) -> Option<WeaverNotification> {
        use weaver::ServerNotice::*;
        let command_history = &mut self.state.write().unwrap().command_history;
        match msg.notice {
            CommandStarted(i, cmd) => {
                let _ = command_history.insert(i, WeaverCommand::new(cmd));
            }
            CommandOutput(i, text) => command_history.get_mut(&i).unwrap().stdout.push_str(&text),
            CommandErr(i, text) => command_history.get_mut(&i).unwrap().stderr.push_str(&text),
            CommandCompleted(i, rv) => command_history.get_mut(&i).unwrap().status = Some(rv),
        };
        Some(WeaverNotification::Updated)
    }
}

impl<'a> Future for WeaverClient<'a> {
    type Item = ();
    type Error = tokio_serde_msgpack::DecodeError;
    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        if let Some(msg) = self.overflow.take() {
            if let Ok(AsyncSink::NotReady(msg)) = self.socket_tx.start_send(msg) {
                self.overflow = Some(msg);
            }
        }

        if self.overflow == None {
            const LINES_PER_TICK: usize = 10;
            for i in 0..LINES_PER_TICK {
                match self.commands_rx.poll().unwrap() {
                    Async::Ready(Some(msg)) => {
                        if let Ok(AsyncSink::NotReady(msg)) = self.socket_tx.start_send(msg) {
                            self.overflow = Some(msg);
                        }
                        if i + 1 == LINES_PER_TICK {
                            task::current().notify();
                        }
                    }
                    _ => break,
                }
            }
        }

        let _ = self.socket_tx.poll_complete();

        while let Async::Ready(msg) = self.socket_rx.poll()? {
            if let Some(msg) = msg {
                self.notifications
                    .send(WeaverNotification::Server(msg.clone())).unwrap();
                match self.do_update(msg) {
                    Some(notification) => self.notifications.send(notification).unwrap(),
                    None => {},
                };
            } else {
                return Ok(Async::Ready(()));
            }
        }
        Ok(Async::NotReady)
    }
}

struct WeaverTui {
    log: Shared<Text>,
    input: Shared<TextInput>,
    vbox: Shared<Linear>,
    state: Shared<WeaverState>,
}

impl WeaverTui {
    fn new(state: Arc<RwLock<WeaverState>>) -> WeaverTui {
        let log = shared(Text::new(vec![]));
        let input = shared(TextInput::new(""));
        let state = state.into();
        let dbgdump = shared(DbgDump::new(&state));
        // XXX Ugly hack D:
        let mut contentbox = Linear::hbox();
        contentbox.push(&log);
        contentbox.push(&dbgdump);
        let content = shared(contentbox);
        let mut mainbox = Linear::vbox();
        mainbox.push(&content);
        mainbox.push(&input);
        let vbox = shared(mainbox);
        WeaverTui {
            log,
            input,
            vbox,
            state,
        }
    }

    fn submit_input(&mut self) {
        let text = self.input.write().unwrap().submit();
        self.state
            .write()
            .unwrap()
            .run_command(text.clone())
            .unwrap();
        let lines = text.lines();
        let mut log = self.log.write().unwrap();
        for line in lines {
            log.push(line.to_owned());
        }
    }

    fn log_msg(&mut self, msg: &str) {
        let lines: Vec<String> = msg.lines().map(|l| l.to_owned()).collect();
        self.log.write().unwrap().lines.extend(lines);
    }

    fn input(&mut self, key: Key) {
        match key {
            Key::Char('\n') => self.submit_input(),
            k => self.input.write().unwrap().keypress(k),
        }
    }
}

impl App for WeaverTui {
    type UI = Shared<Linear>;
    type MyEvent = WeaverNotification;
    fn widget(&self) -> Self::UI {
        self.vbox.clone()
    }
    fn handle_event(&mut self, event: Event<Self::MyEvent>) -> Result<(), Option<String>> {
        match event {
            Event::InputEvent(i) => match i {
                Input::Key(Key::Esc) => Err(None),
                Input::Key(k) => {
                    self.input(k);
                    Ok(())
                }
                _ => Ok(()),
            },
            Event::AppEvent(_) => {
                self.log_msg(&format!("{:?}", event));
                Ok(())
            }
        }
    }
}

fn main() {
    let be = Backend::new();
    let sender = be.sender.clone();
    let weaver = WeaverClient::new(sender);
    let mut app = WeaverTui::new(weaver.state.clone());
    thread::spawn(move || {
        tokio::run(weaver.map_err(|e| panic!("Client Error: {:#?}", e)));
    });
    app.log_msg("Esc to exit");
    be.run_app(&mut app);
}
<commit_msg>impl Widget for WeaverStateWidget<commit_after>extern crate futures;
extern crate text_ui;
extern crate tokio;
extern crate tokio_serde_msgpack;
extern crate tokio_uds;
extern crate weaver;

use text_ui::app::App;
use text_ui::backend::Backend;
use text_ui::widget::Widget;
use text_ui::pane::Pane;
use text_ui::widget::{shared, DbgDump, Line, Linear, Shared, Text, TextInput};
use text_ui::{text_to_lines, Event, Input, Key, Position, Size};

use std::collections::BTreeMap;
use std::fmt;
use std::sync::mpsc::Sender;
use std::sync::{Arc, RwLock};
use std::thread;

use futures::sync::mpsc::SendError as FutureSendError;
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use futures::AsyncSink;

use tokio::prelude::{task, Async, Future, Sink, Stream};
use tokio_serde_msgpack::{from_io, MsgPackReader, MsgPackWriter};
use tokio_uds::UnixStream;

use weaver::{weaver_socket_path, ClientMessage, ClientRequest, ServerMessage, WeaverCommand};

#[derive(Debug, PartialEq)]
pub enum WeaverNotification {
    Updated,
    Server(ServerMessage),
}

pub struct WeaverState {
    pub command_history: BTreeMap<usize, WeaverCommand>,
    pub commands_tx: UnboundedSender<ClientMessage>,
    msgcounter: u32,
}

impl fmt::Debug for WeaverState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("WeaverState")
            .field("command_history", &self.command_history)
            .finish()
    }
}

impl WeaverState {
    pub fn new(commands_tx: UnboundedSender<ClientMessage>) -> Self {
        let command_history = BTreeMap::new();
        let msgcounter = 0;
        WeaverState {
            commands_tx,
            command_history,
            msgcounter,
        }
    }
    pub fn run_command(
        &mut self,
        cmd: String,
    ) -> Result<(), FutureSendError<weaver::ClientMessage>> {
        let request = ClientRequest::RunCommand(cmd);
        self.send_request(request)
    }

    pub fn send_request(
        &mut self,
        request: ClientRequest,
    ) -> Result<(), FutureSendError<weaver::ClientMessage>> {
        self.msgcounter += 1;
        let id = self.msgcounter;
        let msg = ClientMessage { id, request };
        self.commands_tx.unbounded_send(msg)
    }
}

pub struct WeaverClient<'a> {
    commands_rx: UnboundedReceiver<ClientMessage>,
    socket_rx: MsgPackReader<'a, UnixStream, ServerMessage>,
    socket_tx: MsgPackWriter<UnixStream, ClientMessage>,
    pub state: Arc<RwLock<WeaverState>>,
    pub notifications: Sender<WeaverNotification>,
    overflow: Option<ClientMessage>,
}

impl<'a> WeaverClient<'a> {
    pub fn new(notifications: Sender<WeaverNotification>) -> Self {
        let (commands_tx, commands_rx): (
            UnboundedSender<ClientMessage>,
            UnboundedReceiver<ClientMessage>,
        ) = unbounded();

        let state = Arc::new(RwLock::new(WeaverState::new(commands_tx)));
        let overflow = None;

        let socketpath = weaver_socket_path();
        let socket = UnixStream::connect(socketpath);
        let (socket_rx, socket_tx): (
            MsgPackReader<UnixStream, ServerMessage>,
            MsgPackWriter<UnixStream, ClientMessage>,
        ) = from_io(socket.expect("Could not connect to weaver daemon"));
        //let socket_tx = socket_tx.sink_map_err(|e| println!("Send Err: {:#?}", e));
        //let socket_rx = socket_rx.map_err(|e| panic!("Decode Error: {:#?}", e));

        WeaverClient {
            commands_rx,
            socket_rx,
            socket_tx,
            notifications,
            state,
            overflow,
        }
    }

    fn do_update(&mut self, msg: ServerMessage) -> Option<WeaverNotification> {
        use weaver::ServerNotice::*;
        let command_history = &mut self.state.write().unwrap().command_history;
        match msg.notice {
            CommandStarted(i, cmd) => {
                let _ = command_history.insert(i, WeaverCommand::new(cmd));
            }
            CommandOutput(i, text) => command_history.get_mut(&i).unwrap().stdout.push_str(&text),
            CommandErr(i, text) => command_history.get_mut(&i).unwrap().stderr.push_str(&text),
            CommandCompleted(i, rv) => command_history.get_mut(&i).unwrap().status = Some(rv),
        };
        Some(WeaverNotification::Updated)
    }
}

impl<'a> Future for WeaverClient<'a> {
    type Item = ();
    type Error = tokio_serde_msgpack::DecodeError;
    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        if let Some(msg) = self.overflow.take() {
            if let Ok(AsyncSink::NotReady(msg)) = self.socket_tx.start_send(msg) {
                self.overflow = Some(msg);
            }
        }

        if self.overflow == None {
            const LINES_PER_TICK: usize = 10;
            for i in 0..LINES_PER_TICK {
                match self.commands_rx.poll().unwrap() {
                    Async::Ready(Some(msg)) => {
                        if let Ok(AsyncSink::NotReady(msg)) = self.socket_tx.start_send(msg) {
                            self.overflow = Some(msg);
                        }
                        if i + 1 == LINES_PER_TICK {
                            task::current().notify();
                        }
                    }
                    _ => break,
                }
            }
        }

        let _ = self.socket_tx.poll_complete();

        while let Async::Ready(msg) = self.socket_rx.poll()? {
            if let Some(msg) = msg {
                self.notifications
                    .send(WeaverNotification::Server(msg.clone())).unwrap();
                match self.do_update(msg) {
                    Some(notification) => self.notifications.send(notification).unwrap(),
                    None => {},
                };
            } else {
                return Ok(Async::Ready(()));
            }
        }
        Ok(Async::NotReady)
    }
}

struct WeaverStateWidget {
    state: Shared<WeaverState>,
}

impl Widget for WeaverStateWidget {
    fn render_children(&self, size: Size) -> Option<Vec<Pane>> {
        let mut rv = vec![];
        let height = size.height as usize;
        let mut ctr: usize = 0;
        for (i, cmd) in self.state.read().unwrap().command_history.iter().rev() {
            let status = match cmd.status {
                None => '…',
                Some(0) => '✔',
                _ => '❌',
            };
            let mut content = vec![];
            let command_line = format!("{} {}", status, cmd.cmd.clone());
            let command_line = text_to_lines(command_line, size.width as usize);
            ctr += command_line.len();
            content.extend(command_line);
            if cmd.stdout.len() > 0 {
                let stdout = text_to_lines(cmd.stdout.clone(), size.width as usize);
                ctr += stdout.len();
                content.extend(stdout);
            }
            let contentlen = content.len();
            if ctr >= height {
                let top_spill = ctr - height;
                content = content.split_off(top_spill);
                ctr = height;
            }
            let pos = Position::new(0,size.height - ctr as u16);
            rv.push(Pane::new(pos, content));
            if ctr == height {
                break;
            }
        }
        Some(rv)
    }
}

struct WeaverTui {
    log: Shared<Text>,
    input: Shared<TextInput>,
    vbox: Shared<Linear>,
    content: Shared<Linear>,
    state: Shared<WeaverState>,
    statew: Shared<WeaverStateWidget>,
    show_debug: bool,
}

impl WeaverTui {
    fn new(state: Arc<RwLock<WeaverState>>) -> WeaverTui {
        let log = shared(Text::new(vec![]));
        let input = shared(TextInput::new(""));
        let state: Shared<WeaverState> = state.into();
        let statew = shared(WeaverStateWidget{ state: state.clone() });
        let dbgdump = shared(DbgDump::new(&state));
        let show_debug = false;
        // XXX Ugly hack D:
        let mut contentbox = Linear::hbox();
        //contentbox.push(&log);
        //contentbox.push(&dbgdump);
        contentbox.push(&statew);
        let content = shared(contentbox);
        let mut mainbox = Linear::vbox();
        mainbox.push(&content);
        mainbox.push(&input);
        let vbox = shared(mainbox);
        WeaverTui {
            log,
            input,
            vbox,
            content,
            state,
            statew,
            show_debug,
        }
    }

    fn toggle_debug(&mut self) {
        let mut content = self.content.write().unwrap();
        match self.show_debug {
            true => {
                self.show_debug = false;
                content.contents.truncate(0);
                content.push(&self.statew);
            }
            false => {
                self.show_debug = true;
                content.contents.truncate(0);
                content.push(&self.statew);
                content.push(&shared(Line::vertical()));
                content.push(&self.log);
            }
        }
    }

    fn submit_input(&mut self) {
        let text = self.input.write().unwrap().submit();
        self.state
            .write()
            .unwrap()
            .run_command(text.clone())
            .unwrap();
        /*let lines = text.lines();
        let mut log = self.log.write().unwrap();
        for line in lines {
            log.push(line.to_owned());
        }*/
    }

    fn log_msg(&mut self, msg: &str) {
        let lines: Vec<String> = msg.lines().map(|l| l.to_owned()).collect();
        self.log.write().unwrap().lines.extend(lines);
    }

    fn input(&mut self, key: Key) {
        match key {
            Key::Char('\n') => self.submit_input(),
            k => self.input.write().unwrap().keypress(k),
        }
    }
}

impl App for WeaverTui {
    type UI = Shared<Linear>;
    type MyEvent = WeaverNotification;
    fn widget(&self) -> Self::UI {
        self.vbox.clone()
    }
    fn handle_event(&mut self, event: Event<Self::MyEvent>) -> Result<(), Option<String>> {
        match event {
            Event::InputEvent(i) => match i {
                Input::Key(Key::Esc) => Err(None),
                Input::Key(Key::Alt('d')) => {
                    self.toggle_debug();
                    Ok(())
                }
                Input::Key(k) => {
                    self.input(k);
                    Ok(())
                }
                _ => Ok(()),
            },
            Event::AppEvent(_) => {
                self.log_msg(&format!("{:?}", event));
                Ok(())
            }
        }
    }
}

fn main() {
    let be = Backend::new();
    let sender = be.sender.clone();
    let weaver = WeaverClient::new(sender);
    let mut app = WeaverTui::new(weaver.state.clone());
    thread::spawn(move || {
        tokio::run(weaver.map_err(|e| panic!("Client Error: {:#?}", e)));
    });
    app.log_msg("Esc to exit");
    be.run_app(&mut app);
}
<|endoftext|>


<commit_before>//! Applies pooling to the input.
//!
//! This layers looks at adjectant values of the input and then computes a
//! simple pooling operation over them (e.g. taking their maximum or average value).
//! *See [PoolingMode][pooling_mode]*
//!
//! [pooling_mode]: ./enum.PoolingMode.html
//!
//! ## Input Data
//!
//! The layer expects the input to be in either 4D NCHW (2 spatial dimensions)
//! or 5D NCDHW (3 spatial dimensions) format.
use std::rc::Rc;
use co::{IBackend, SharedTensor};
use conn;
use layer::*;
use util::{ArcLock, cast_vec_usize_to_i32};
use super::FilterLayer;
use leaf_capnp::pooling_config as capnp_config;
use leaf_capnp::PoolingMode as CapnpPoolingMode;
use capnp_util::*;

#[derive(Debug, Clone)]
/// [Pooling](./index.html) Layer
pub struct Pooling<T, B: conn::Pooling<T>> {
    mode: PoolingMode,

    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    pooling_configs: Vec<Rc<B::CPOOL>>,
}

impl<T, B: conn::Pooling<T>> Pooling<T, B> {
    /// Create a Pooling layer from a PoolingConfig.
    pub fn from_config(config: &PoolingConfig) -> Pooling<T, B> {
        Pooling {
            mode: config.mode,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            pooling_configs: vec![],
        }
    }
}

impl<T, B: conn::Pooling<T>> FilterLayer for Pooling<T, B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            5 => 3,
            _ => panic!("A pooling layer currently only supports 4D or 5D input.")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..2].to_vec() {
            output_shape.push(*dim);
        }
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Pooling<f32>> ILayer<B> for Pooling<f32, B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data[0].write().unwrap().resize(&output_shape).unwrap();
            output_gradient[0].write().unwrap().resize(&output_shape).unwrap();

            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let filter = cast_vec_usize_to_i32(self.spatial_filter_dims(num_spatial_dims));
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            let config = backend.new_pooling_config(&filter, &padding, &stride).unwrap();
            self.pooling_configs.push(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeOutput<f32, B> for Pooling<f32, B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max(input_data[0], output_data[0],
                                                    &*config).unwrap(),
            // TODO: implement average pooling
            // PoolingMode::Average => unimplemented!(),
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeInputGradient<f32, B> for Pooling<f32, B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              _weights_data: &[&SharedTensor<f32>],
                              output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_grad(
                output_data[0], output_gradients[0],
                input_data[0], input_gradients[0], config).unwrap()
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeParametersGradient<f32, B> for Pooling<f32, B> { }

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Pooling Layer.
pub struct PoolingConfig {
    /// The PoolingMode to use
    pub mode: PoolingMode,
    /// The shape of the filter
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
}

impl Into<LayerType> for PoolingConfig {
    fn into(self) -> LayerType {
        LayerType::Pooling(self)
    }
}

impl<'a> CapnpWrite<'a> for PoolingConfig {
    type Builder = capnp_config::Builder<'a>;

    /// Write the PoolingConfig into a capnp message.
    fn write_capnp(&self, builder: &mut Self::Builder) {
        builder.borrow().set_mode(self.mode.to_capnp());
        {
            let mut filter_shape = builder.borrow().init_filter_shape(self.filter_shape.len() as u32);
            for (i, dim) in self.filter_shape.iter().enumerate() {
                filter_shape.set(i as u32, *dim as u64);
            }
        }
        {
            let mut stride = builder.borrow().init_stride(self.stride.len() as u32);
            for (i, dim) in self.stride.iter().enumerate() {
                stride.set(i as u32, *dim as u64);
            }
        }
        {
            let mut padding = builder.borrow().init_padding(self.padding.len() as u32);
            for (i, dim) in self.padding.iter().enumerate() {
                padding.set(i as u32, *dim as u64);
            }
        }
    }
}

impl<'a> CapnpRead<'a> for PoolingConfig {
    type Reader = capnp_config::Reader<'a>;

    fn read_capnp(reader: Self::Reader) -> Self {
        let mode = PoolingMode::from_capnp(reader.get_mode().unwrap());

        let read_filter_shape = reader.get_filter_shape().unwrap();
        let mut filter_shape = Vec::new();
        for i in 0..read_filter_shape.len() {
            filter_shape.push(read_filter_shape.get(i) as usize)
        }
        let read_stride = reader.get_stride().unwrap();
        let mut stride = Vec::new();
        for i in 0..read_stride.len() {
            stride.push(read_stride.get(i) as usize)
        }
        let read_padding = reader.get_padding().unwrap();
        let mut padding = Vec::new();
        for i in 0..read_padding.len() {
            padding.push(read_padding.get(i) as usize)
        }

        PoolingConfig {
            mode: mode,
            filter_shape: filter_shape,
            stride: stride,
            padding: padding,
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// The different modes of pooling that can be calculated.
pub enum PoolingMode {
    /// The maximum value inside the pooling window will be used as result.
    Max,
    // /// The average of all values inside the pooling window will be used as result.
    // Average,
}

impl PoolingMode {
    /// Return the corresponding Cap'n Proto value.
    fn to_capnp(&self) -> CapnpPoolingMode {
        match *self {
            PoolingMode::Max => CapnpPoolingMode::Max,
        }
    }

    /// Return the enum value for a Cap'n Proto value.
    fn from_capnp(value: CapnpPoolingMode) -> Self {
        match value {
            CapnpPoolingMode::Max => PoolingMode::Max,
            CapnpPoolingMode::Average => unimplemented!(),
        }
    }
}
<commit_msg>feat/pooling: enable average pooling<commit_after>//! Applies pooling to the input.
//!
//! This layers looks at adjectant values of the input and then computes a
//! simple pooling operation over them (e.g. taking their maximum or average value).
//! *See [PoolingMode][pooling_mode]*
//!
//! [pooling_mode]: ./enum.PoolingMode.html
//!
//! ## Input Data
//!
//! The layer expects the input to be in either 4D NCHW (2 spatial dimensions)
//! or 5D NCDHW (3 spatial dimensions) format.
use std::rc::Rc;
use co::{IBackend, SharedTensor};
use conn;
use layer::*;
use util::{ArcLock, cast_vec_usize_to_i32};
use super::FilterLayer;
use leaf_capnp::pooling_config as capnp_config;
use leaf_capnp::PoolingMode as CapnpPoolingMode;
use capnp_util::*;

#[derive(Debug, Clone)]
/// [Pooling](./index.html) Layer
pub struct Pooling<T, B: conn::Pooling<T>> {
    mode: PoolingMode,

    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    pooling_configs: Vec<Rc<B::CPOOL>>,
}

impl<T, B: conn::Pooling<T>> Pooling<T, B> {
    /// Create a Pooling layer from a PoolingConfig.
    pub fn from_config(config: &PoolingConfig) -> Pooling<T, B> {
        Pooling {
            mode: config.mode,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            pooling_configs: vec![],
        }
    }
}

impl<T, B: conn::Pooling<T>> FilterLayer for Pooling<T, B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            5 => 3,
            _ => panic!("A pooling layer currently only supports 4D or 5D input.")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..2].to_vec() {
            output_shape.push(*dim);
        }
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Pooling<f32>> ILayer<B> for Pooling<f32, B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data[0].write().unwrap().resize(&output_shape).unwrap();
            output_gradient[0].write().unwrap().resize(&output_shape).unwrap();

            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let filter = cast_vec_usize_to_i32(self.spatial_filter_dims(num_spatial_dims));
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            let config = backend.new_pooling_config(&filter, &padding, &stride).unwrap();
            self.pooling_configs.push(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeOutput<f32, B> for Pooling<f32, B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max(input_data[0], output_data[0],
                                                    &*config).unwrap(),
            PoolingMode::Average => backend.pooling_avg(input_data[0], output_data[0],
                                                    &*config).unwrap(),
			_ => panic!("Unknown Parameter {} for PoolingMode", self.mode),
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeInputGradient<f32, B> for Pooling<f32, B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              _weights_data: &[&SharedTensor<f32>],
                              output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_grad(
                output_data[0], output_gradients[0],
                input_data[0], input_gradients[0], config).unwrap(),
            PoolingMode::Average => backend.pooling_avg_grad(
                output_data[0], output_gradients[0],
                input_data[0], input_gradients[0], config).unwrap(),
            _ => panic!("Unknown parameter {} for PoolingMode", self.mode)
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeParametersGradient<f32, B> for Pooling<f32, B> { }

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Pooling Layer.
pub struct PoolingConfig {
    /// The PoolingMode to use
    pub mode: PoolingMode,
    /// The shape of the filter
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
}

impl Into<LayerType> for PoolingConfig {
    fn into(self) -> LayerType {
        LayerType::Pooling(self)
    }
}

impl<'a> CapnpWrite<'a> for PoolingConfig {
    type Builder = capnp_config::Builder<'a>;

    /// Write the PoolingConfig into a capnp message.
    fn write_capnp(&self, builder: &mut Self::Builder) {
        builder.borrow().set_mode(self.mode.to_capnp());
        {
            let mut filter_shape = builder.borrow().init_filter_shape(self.filter_shape.len() as u32);
            for (i, dim) in self.filter_shape.iter().enumerate() {
                filter_shape.set(i as u32, *dim as u64);
            }
        }
        {
            let mut stride = builder.borrow().init_stride(self.stride.len() as u32);
            for (i, dim) in self.stride.iter().enumerate() {
                stride.set(i as u32, *dim as u64);
            }
        }
        {
            let mut padding = builder.borrow().init_padding(self.padding.len() as u32);
            for (i, dim) in self.padding.iter().enumerate() {
                padding.set(i as u32, *dim as u64);
            }
        }
    }
}

impl<'a> CapnpRead<'a> for PoolingConfig {
    type Reader = capnp_config::Reader<'a>;

    fn read_capnp(reader: Self::Reader) -> Self {
        let mode = PoolingMode::from_capnp(reader.get_mode().unwrap());

        let read_filter_shape = reader.get_filter_shape().unwrap();
        let mut filter_shape = Vec::new();
        for i in 0..read_filter_shape.len() {
            filter_shape.push(read_filter_shape.get(i) as usize)
        }
        let read_stride = reader.get_stride().unwrap();
        let mut stride = Vec::new();
        for i in 0..read_stride.len() {
            stride.push(read_stride.get(i) as usize)
        }
        let read_padding = reader.get_padding().unwrap();
        let mut padding = Vec::new();
        for i in 0..read_padding.len() {
            padding.push(read_padding.get(i) as usize)
        }

        PoolingConfig {
            mode: mode,
            filter_shape: filter_shape,
            stride: stride,
            padding: padding,
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// The different modes of pooling that can be calculated.
pub enum PoolingMode {
    /// The maximum value inside the pooling window will be used as result.
    Max,
    // /// The average of all values inside the pooling window will be used as result.
    // Average,
}

impl PoolingMode {
    /// Return the corresponding Cap'n Proto value.
    fn to_capnp(&self) -> CapnpPoolingMode {
        match *self {
            PoolingMode::Max => CapnpPoolingMode::Max,
        }
    }

    /// Return the enum value for a Cap'n Proto value.
    fn from_capnp(value: CapnpPoolingMode) -> Self {
        match value {
            CapnpPoolingMode::Max => PoolingMode::Max,
            CapnpPoolingMode::Average => unimplemented!(),
        }
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use libc::{self, c_char, c_float, c_uint, c_void, pid_t, size_t};
use std::borrow::BorrowMut;
use std::ffi::CString;
use {NetworkExt, Process, ProcessExt, ProcessorExt, System, SystemExt};

/// Equivalent of `System` struct.
pub type CSystem = *mut c_void;
/// Equivalent of `Process` struct.
pub type CProcess = *const c_void;
/// C string returned from `CString::into_raw`.
pub type RString = *const c_char;
/// Callback used by `get_process_list`.
pub type ProcessLoop = extern "C" fn(pid: pid_t, process: CProcess, data: *mut c_void) -> bool;

/// Equivalent of `System::new()`.
#[no_mangle]
pub extern "C" fn sysinfo_init() -> CSystem {
    let system = Box::new(System::new());
    Box::into_raw(system) as CSystem
}

/// Equivalent of `System::drop()`. Important in C to cleanup memory.
#[no_mangle]
pub extern "C" fn sysinfo_destroy(system: CSystem) {
    assert!(!system.is_null());
    unsafe {
        Box::from_raw(system as *mut System);
    }
}

/// Equivalent of `System::refresh_system()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_system(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_system();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_all()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_all(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_all();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_processes()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_processes(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_processes();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_process()`.
#[cfg(target_os = "linux")]
#[no_mangle]
pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: pid_t) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_process(pid);
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_disks()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_disks(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_disks();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_disk_list()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_disk_list(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_disk_list();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::get_total_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_total_memory(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_total_memory() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_free_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_free_memory(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_free_memory() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_used_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_used_memory(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_used_memory() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_total_swap()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_total_swap(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_total_swap() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_free_swap()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_free_swap(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_free_swap() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_used_swap()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_used_swap(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_used_swap() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `system::get_network().get_income()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_network_income(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_network().get_income() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `system::get_network().get_outcome()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_network_outcome(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_network().get_outcome() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_processors_usage()`.
///
/// * `length` will contain the number of cpu usage added into `procs`.
/// * `procs` will be allocated if it's null and will contain of cpu usage.
#[no_mangle]
pub extern "C" fn sysinfo_get_processors_usage(
    system: CSystem,
    length: *mut c_uint,
    procs: *mut *mut c_float,
) {
    assert!(!system.is_null());
    if procs.is_null() || length.is_null() {
        return;
    }
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let processors = system.get_processor_list();
        unsafe {
            if (*procs).is_null() {
                (*procs) = libc::malloc(::std::mem::size_of::<c_float>() * processors.len())
                    as *mut c_float;
            }
            for (pos, processor) in processors.iter().skip(1).enumerate() {
                (*(*procs).offset(pos as isize)) = processor.get_cpu_usage();
            }
            *length = processors.len() as c_uint - 1;
        }
    }
    Box::into_raw(system);
}

/// Equivalent of `System::get_process_list()`. Returns an array ended by a null pointer. Must
/// be freed.
///
/// # /!\ WARNING /!\
///
/// While having this method returned processes, you should *never* call any refresh method!
#[no_mangle]
pub extern "C" fn sysinfo_get_processes(
    system: CSystem,
    fn_pointer: Option<ProcessLoop>,
    data: *mut c_void,
) -> size_t {
    assert!(!system.is_null());
    if let Some(fn_pointer) = fn_pointer {
        let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
        let len = {
            let entries = system.get_process_list();
            for (pid, process) in entries {
                if !fn_pointer(*pid, process as *const Process as CProcess, data) {
                    break;
                }
            }
            entries.len() as size_t
        };
        Box::into_raw(system);
        len
    } else {
        0
    }
}

/// Equivalent of `System::get_process()`.
///
/// # /!\ WARNING /!\
///
/// While having this method returned process, you should *never* call any
/// refresh method!
#[no_mangle]
pub extern "C" fn sysinfo_get_process_by_pid(system: CSystem, pid: pid_t) -> CProcess {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = if let Some(process) = system.get_process(pid) {
        process as *const Process as CProcess
    } else {
        ::std::ptr::null()
    };
    Box::into_raw(system);
    ret
}

/// Equivalent of iterating over `Process::tasks()`.
///
/// # /!\ WARNING /!\
///
/// While having this method processes, you should *never* call any refresh method!
#[cfg(target_os = "linux")]
#[no_mangle]
pub extern "C" fn sysinfo_process_get_tasks(
    process: CProcess,
    fn_pointer: Option<ProcessLoop>,
    data: *mut c_void,
) -> size_t {
    assert!(!process.is_null());
    if let Some(fn_pointer) = fn_pointer {
        let process = process as *const Process;
        for (pid, process) in unsafe { (*process).tasks.iter() } {
            if !fn_pointer(*pid, process as *const Process as CProcess, data) {
                break;
            }
        }
        unsafe { (*process).tasks.len() as size_t }
    } else {
        0
    }
}

/// Equivalent of `Process::pid()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_pid(process: CProcess) -> pid_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).pid() }
}

/// Equivalent of `Process::parent()`.
///
/// In case there is no known parent, it returns `0`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_parent_pid(process: CProcess) -> pid_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).parent().unwrap_or_else(|| 0) }
}

/// Equivalent of `Process::cpu_usage()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_cpu_usage(process: CProcess) -> c_float {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).cpu_usage() }
}

/// Equivalent of `Process::memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_memory(process: CProcess) -> size_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).memory() as usize }
}

/// Equivalent of `Process::virtual_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_virtual_memory(process: CProcess) -> size_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).virtual_memory() as usize }
}

/// Equivalent of `Process::exe()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_executable_path(process: CProcess) -> RString {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe {
        if let Some(p) = (*process).exe().to_str() {
            if let Ok(c) = CString::new(p) {
                return c.into_raw() as _;
            }
        }
        ::std::ptr::null()
    }
}

/// Equivalent of `Process::root()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_root_directory(process: CProcess) -> RString {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe {
        if let Some(p) = (*process).root().to_str() {
            if let Ok(c) = CString::new(p) {
                return c.into_raw() as _;
            }
        }
        ::std::ptr::null()
    }
}

/// Equivalent of `Process::cwd()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_current_directory(process: CProcess) -> RString {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe {
        if let Some(p) = (*process).cwd().to_str() {
            if let Ok(c) = CString::new(p) {
                return c.into_raw() as _;
            }
        }
        ::std::ptr::null()
    }
}

/// Frees a C string created with `CString::into_raw()`.
#[no_mangle]
pub extern "C" fn sysinfo_rstring_free(s: RString) {
    if !s.is_null() {
        unsafe {
            let _ = CString::from_raw(s as usize as *mut i8);
        }
    }
}
<commit_msg>Add new refresh functions for the C interface<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use libc::{self, c_char, c_float, c_uint, c_void, pid_t, size_t};
use std::borrow::BorrowMut;
use std::ffi::CString;
use {NetworkExt, Process, ProcessExt, ProcessorExt, System, SystemExt};

/// Equivalent of `System` struct.
pub type CSystem = *mut c_void;
/// Equivalent of `Process` struct.
pub type CProcess = *const c_void;
/// C string returned from `CString::into_raw`.
pub type RString = *const c_char;
/// Callback used by `get_process_list`.
pub type ProcessLoop = extern "C" fn(pid: pid_t, process: CProcess, data: *mut c_void) -> bool;

/// Equivalent of `System::new()`.
#[no_mangle]
pub extern "C" fn sysinfo_init() -> CSystem {
    let system = Box::new(System::new());
    Box::into_raw(system) as CSystem
}

/// Equivalent of `System::drop()`. Important in C to cleanup memory.
#[no_mangle]
pub extern "C" fn sysinfo_destroy(system: CSystem) {
    assert!(!system.is_null());
    unsafe {
        Box::from_raw(system as *mut System);
    }
}

/// Equivalent of `System::refresh_system()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_system(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_system();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_memory(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_memory();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_cpu()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_cpu(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_cpu();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_cpu()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_temperatures(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_temperatures();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_all()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_all(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_all();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_processes()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_processes(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_processes();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_process()`.
#[cfg(target_os = "linux")]
#[no_mangle]
pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: pid_t) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_process(pid);
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_disks()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_disks(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_disks();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::refresh_disk_list()`.
#[no_mangle]
pub extern "C" fn sysinfo_refresh_disk_list(system: CSystem) {
    assert!(!system.is_null());
    let mut system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let system: &mut System = system.borrow_mut();
        system.refresh_disk_list();
    }
    Box::into_raw(system);
}

/// Equivalent of `System::get_total_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_total_memory(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_total_memory() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_free_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_free_memory(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_free_memory() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_used_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_used_memory(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_used_memory() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_total_swap()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_total_swap(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_total_swap() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_free_swap()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_free_swap(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_free_swap() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_used_swap()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_used_swap(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_used_swap() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `system::get_network().get_income()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_network_income(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_network().get_income() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `system::get_network().get_outcome()`.
#[no_mangle]
pub extern "C" fn sysinfo_get_network_outcome(system: CSystem) -> size_t {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = system.get_network().get_outcome() as size_t;
    Box::into_raw(system);
    ret
}

/// Equivalent of `System::get_processors_usage()`.
///
/// * `length` will contain the number of cpu usage added into `procs`.
/// * `procs` will be allocated if it's null and will contain of cpu usage.
#[no_mangle]
pub extern "C" fn sysinfo_get_processors_usage(
    system: CSystem,
    length: *mut c_uint,
    procs: *mut *mut c_float,
) {
    assert!(!system.is_null());
    if procs.is_null() || length.is_null() {
        return;
    }
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    {
        let processors = system.get_processor_list();
        unsafe {
            if (*procs).is_null() {
                (*procs) = libc::malloc(::std::mem::size_of::<c_float>() * processors.len())
                    as *mut c_float;
            }
            for (pos, processor) in processors.iter().skip(1).enumerate() {
                (*(*procs).offset(pos as isize)) = processor.get_cpu_usage();
            }
            *length = processors.len() as c_uint - 1;
        }
    }
    Box::into_raw(system);
}

/// Equivalent of `System::get_process_list()`. Returns an array ended by a null pointer. Must
/// be freed.
///
/// # /!\ WARNING /!\
///
/// While having this method returned processes, you should *never* call any refresh method!
#[no_mangle]
pub extern "C" fn sysinfo_get_processes(
    system: CSystem,
    fn_pointer: Option<ProcessLoop>,
    data: *mut c_void,
) -> size_t {
    assert!(!system.is_null());
    if let Some(fn_pointer) = fn_pointer {
        let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
        let len = {
            let entries = system.get_process_list();
            for (pid, process) in entries {
                if !fn_pointer(*pid, process as *const Process as CProcess, data) {
                    break;
                }
            }
            entries.len() as size_t
        };
        Box::into_raw(system);
        len
    } else {
        0
    }
}

/// Equivalent of `System::get_process()`.
///
/// # /!\ WARNING /!\
///
/// While having this method returned process, you should *never* call any
/// refresh method!
#[no_mangle]
pub extern "C" fn sysinfo_get_process_by_pid(system: CSystem, pid: pid_t) -> CProcess {
    assert!(!system.is_null());
    let system: Box<System> = unsafe { Box::from_raw(system as *mut System) };
    let ret = if let Some(process) = system.get_process(pid) {
        process as *const Process as CProcess
    } else {
        ::std::ptr::null()
    };
    Box::into_raw(system);
    ret
}

/// Equivalent of iterating over `Process::tasks()`.
///
/// # /!\ WARNING /!\
///
/// While having this method processes, you should *never* call any refresh method!
#[cfg(target_os = "linux")]
#[no_mangle]
pub extern "C" fn sysinfo_process_get_tasks(
    process: CProcess,
    fn_pointer: Option<ProcessLoop>,
    data: *mut c_void,
) -> size_t {
    assert!(!process.is_null());
    if let Some(fn_pointer) = fn_pointer {
        let process = process as *const Process;
        for (pid, process) in unsafe { (*process).tasks.iter() } {
            if !fn_pointer(*pid, process as *const Process as CProcess, data) {
                break;
            }
        }
        unsafe { (*process).tasks.len() as size_t }
    } else {
        0
    }
}

/// Equivalent of `Process::pid()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_pid(process: CProcess) -> pid_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).pid() }
}

/// Equivalent of `Process::parent()`.
///
/// In case there is no known parent, it returns `0`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_parent_pid(process: CProcess) -> pid_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).parent().unwrap_or_else(|| 0) }
}

/// Equivalent of `Process::cpu_usage()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_cpu_usage(process: CProcess) -> c_float {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).cpu_usage() }
}

/// Equivalent of `Process::memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_memory(process: CProcess) -> size_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).memory() as usize }
}

/// Equivalent of `Process::virtual_memory()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_virtual_memory(process: CProcess) -> size_t {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe { (*process).virtual_memory() as usize }
}

/// Equivalent of `Process::exe()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_executable_path(process: CProcess) -> RString {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe {
        if let Some(p) = (*process).exe().to_str() {
            if let Ok(c) = CString::new(p) {
                return c.into_raw() as _;
            }
        }
        ::std::ptr::null()
    }
}

/// Equivalent of `Process::root()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_root_directory(process: CProcess) -> RString {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe {
        if let Some(p) = (*process).root().to_str() {
            if let Ok(c) = CString::new(p) {
                return c.into_raw() as _;
            }
        }
        ::std::ptr::null()
    }
}

/// Equivalent of `Process::cwd()`.
#[no_mangle]
pub extern "C" fn sysinfo_process_get_current_directory(process: CProcess) -> RString {
    assert!(!process.is_null());
    let process = process as *const Process;
    unsafe {
        if let Some(p) = (*process).cwd().to_str() {
            if let Ok(c) = CString::new(p) {
                return c.into_raw() as _;
            }
        }
        ::std::ptr::null()
    }
}

/// Frees a C string created with `CString::into_raw()`.
#[no_mangle]
pub extern "C" fn sysinfo_rstring_free(s: RString) {
    if !s.is_null() {
        unsafe {
            let _ = CString::from_raw(s as usize as *mut i8);
        }
    }
}
<|endoftext|>


<commit_before>use heuristic::WLDHeuristic;
use heuristic::BasicHeuristic;
use heuristic::ScaledBasicHeuristic;
use heuristic::PatternHeuristic;
use heuristic::HandmadeHeuristic;
use bitboard::Board;
use bitboard::Move;
use bitboard::Turn;
use bitboard::empty_movelist;
use search::mtdf_id_timeout;
use search::NegamaxSearch;

use std::path::Path;
use std::time::Instant;

pub struct Player {
    phs     : [Box<PatternHeuristic>; 20],
    //phs     : [BasicHeuristic; 20],
}

const time_alloc : [f32; 64] = [
    0.00,   0.00,   0.00,   0.00,   0.01,   0.05,   0.05,   0.05,
    0.05,   0.05,   0.05,   0.05,   0.05,   0.05,   0.05,   0.05,
    0.03,   0.03,   0.03,   0.03,   0.03,   0.03,   0.03,   0.03,
    0.10,   0.10,   0.10,   0.10,   0.10,   0.10,   0.10,   0.10,
    0.12,   0.12,   0.12,   0.12,   0.12,   0.12,   0.12,   0.12,
    0.14,   0.14,   0.14,   0.14,   0.14,   0.14,   0.14,   0.14,
    0.15,   0.15,   0.15,   0.15,   0.30,   0.30,   0.30,   0.30,
    0.70,   0.70,   0.70,   0.70,   0.95,   0.95,   0.95,   0.95,
];

impl Player {
    pub fn new(s : Turn) -> Player {
        Player {
            phs     : [
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e01-03.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e04-06.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e07-09.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e10-12.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e13-15.json"))),

                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e16-18.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e19-21.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e22-24.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e25-27.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e28-30.json"))),

                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e31-33.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e34-36.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e37-39.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),

                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json")))
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e43-45.json"))),

                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e46-48.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e49-51.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e52-54.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e55-57.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e58-60.json")))
            ],
        }
    }

    pub fn do_move(&mut self, b : Board, ms_left : u64) -> Move {
        let pieces = b.count_pieces();
        let total = pieces.0 + pieces.1;
        let empty = (64 - total) as u64;

        let start = Instant::now();
        let alloc_time = (ms_left as f32 * time_alloc[total as usize]) as u64;

        let mut out_move = mtdf_id_timeout(b.copy(), &self.phs,
                                        Box::new(ScaledBasicHeuristic::new(10)),
                                        40, alloc_time);

        if out_move.is_null() {
            let mut ml = empty_movelist();
            b.get_moves(&mut ml);

            out_move = ml[0];
        }

        out_move

        // if empty > 18 {
        //     //somehow, this makes it play well...
        //     //optimizing for few pieces
        //     self.h_mid.piece_diff = ((16-empty)>>1) as i32;
        //     // If we are still in the mid-game, use MTD(f)
        //     self.se.mtdf_id(
        //         b.copy(), &mut self.h_mid, self.t, 21, 2*ms_left/empty
        //     )
        // } else {
        //     // If we are close to the end, try solving the game
        //     let mut to = false;
        //     let mut mv = Move::null();
        //     cerrln!("[COIN]: Trying solver...");
        //     let start = Instant::now();
        //     let (al,bt) = match self.t {
        //         Turn::BLACK => (0,2),
        //         Turn::WHITE => (-2,0),
        //     };

        //     //we allot a quarter of the remaining time to solving
        //     let g = self.se.alpha_beta_with_timeout(
        //         b.copy(),&mut self.h_end,self.t,al,bt,2*empty as u8,(ms_left/4),start,&mut to, &mut mv
        //     );

        //     if to || g >= bt || g <= al || mv.is_null() {
        //         if to {
        //             cerrln!("[COIN]: Solver TIMEOUT, reverting to MTD(f)");
        //         } else if g >= bt || g <= al {
        //             cerrln!("[COIN]: Bounds miss, reverting to MTD(f)");
        //         } else {
        //             cerrln!("[COIN]: Other error, reverting to MTD(f)");
        //         }
        //         //change the value of having more pieces as we get closer to the
        //         //end of the game
        //         //self.h_mid.piece_diff = ((24-empty)>>1) as i32;
        //         //we either timed out or couldn't find a guaranteed win so we
        //         //switch back to MTD(f) and try again next time.
        //         self.se.mtdf_id(
        //             b.copy(), &mut self.h_mid, self.t, 21, 3*ms_left/empty/2
        //         )
        //     } else {
        //         cerrln!("[COIN]: Found Solution, score: {}, move: {}", g, mv);
        //         mv
        //     }
        // }
    }
}
<commit_msg>added PVS to the player<commit_after>use heuristic::WLDHeuristic;
use heuristic::BasicHeuristic;
use heuristic::ScaledBasicHeuristic;
use heuristic::PatternHeuristic;
use heuristic::HandmadeHeuristic;
use bitboard::Board;
use bitboard::Move;
use bitboard::Turn;
use bitboard::empty_movelist;
use search::mtdf_id_timeout;
use search::NegamaxSearch;
use search;

use std::path::Path;
use std::time::Instant;

pub struct Player {
    phs     : [Box<PatternHeuristic>; 20],
    //phs     : [BasicHeuristic; 20],
}

const time_alloc : [f32; 64] = [
    0.00,   0.00,   0.00,   0.00,   0.01,   0.05,   0.05,   0.05,
    0.05,   0.05,   0.05,   0.05,   0.05,   0.05,   0.05,   0.05,
    0.03,   0.03,   0.03,   0.03,   0.03,   0.03,   0.03,   0.03,
    0.10,   0.10,   0.10,   0.10,   0.10,   0.10,   0.10,   0.10,
    0.12,   0.12,   0.12,   0.12,   0.12,   0.12,   0.12,   0.12,
    0.14,   0.14,   0.14,   0.14,   0.14,   0.14,   0.14,   0.14,
    0.15,   0.15,   0.15,   0.15,   0.30,   0.30,   0.30,   0.30,
    0.70,   0.70,   0.70,   0.70,   0.95,   0.95,   0.95,   0.95,
];

impl Player {
    pub fn new(s : Turn) -> Player {
        Player {
            phs     : [
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e01-03.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e04-06.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e07-09.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e10-12.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e13-15.json"))),

                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e16-18.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e19-21.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e22-24.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e25-27.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e28-30.json"))),

                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e31-33.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e34-36.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e37-39.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),

                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json"))),
                Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e40-42.json")))
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e43-45.json"))),

                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e46-48.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e49-51.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e52-54.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e55-57.json"))),
                // Box::new(PatternHeuristic::file(Path::new("./data/patterns_v2/pdesc_e58-60.json")))
            ],
        }
    }

    pub fn do_move(&mut self, b : Board, ms_left : u64) -> Move {
        let pieces = b.count_pieces();
        let total = pieces.0 + pieces.1;
        let empty = (64 - total) as u64;

        let start = Instant::now();
        let alloc_time = (ms_left as f32 * time_alloc[total as usize]) as u64;

        // let mut out_move = mtdf_id_timeout(b.copy(), &self.phs,
        //                                 Box::new(ScaledBasicHeuristic::new(10)),
        //                                 40, alloc_time);

        let mut out_move = search::pvs_id(b, &mut self.phs, &mut ScaledBasicHeuristic::new(10), 60, alloc_time);

        if out_move.is_null() {
            let mut ml = empty_movelist();
            b.get_moves(&mut ml);

            out_move = ml[0];
        }

        out_move

        // if empty > 18 {
        //     //somehow, this makes it play well...
        //     //optimizing for few pieces
        //     self.h_mid.piece_diff = ((16-empty)>>1) as i32;
        //     // If we are still in the mid-game, use MTD(f)
        //     self.se.mtdf_id(
        //         b.copy(), &mut self.h_mid, self.t, 21, 2*ms_left/empty
        //     )
        // } else {
        //     // If we are close to the end, try solving the game
        //     let mut to = false;
        //     let mut mv = Move::null();
        //     cerrln!("[COIN]: Trying solver...");
        //     let start = Instant::now();
        //     let (al,bt) = match self.t {
        //         Turn::BLACK => (0,2),
        //         Turn::WHITE => (-2,0),
        //     };

        //     //we allot a quarter of the remaining time to solving
        //     let g = self.se.alpha_beta_with_timeout(
        //         b.copy(),&mut self.h_end,self.t,al,bt,2*empty as u8,(ms_left/4),start,&mut to, &mut mv
        //     );

        //     if to || g >= bt || g <= al || mv.is_null() {
        //         if to {
        //             cerrln!("[COIN]: Solver TIMEOUT, reverting to MTD(f)");
        //         } else if g >= bt || g <= al {
        //             cerrln!("[COIN]: Bounds miss, reverting to MTD(f)");
        //         } else {
        //             cerrln!("[COIN]: Other error, reverting to MTD(f)");
        //         }
        //         //change the value of having more pieces as we get closer to the
        //         //end of the game
        //         //self.h_mid.piece_diff = ((24-empty)>>1) as i32;
        //         //we either timed out or couldn't find a guaranteed win so we
        //         //switch back to MTD(f) and try again next time.
        //         self.se.mtdf_id(
        //             b.copy(), &mut self.h_mid, self.t, 21, 3*ms_left/empty/2
        //         )
        //     } else {
        //         cerrln!("[COIN]: Found Solution, score: {}, move: {}", g, mv);
        //         mv
        //     }
        // }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

// WARNING: THIS IS A GENERATED FILE, DO NOT MODIFY
//          take a look at src/etc/mklldeps.py if you're interested

#[cfg(target_arch = "x86_64", target_os = "linux")]
#[link(name = "LLVMInstrumentation", kind = "static")]
#[link(name = "LLVMInterpreter", kind = "static")]
#[link(name = "LLVMMCJIT", kind = "static")]
#[link(name = "LLVMRuntimeDyld", kind = "static")]
#[link(name = "LLVMJIT", kind = "static")]
#[link(name = "LLVMExecutionEngine", kind = "static")]
#[link(name = "LLVMAsmParser", kind = "static")]
#[link(name = "LLVMLinker", kind = "static")]
#[link(name = "LLVMBitWriter", kind = "static")]
#[link(name = "LLVMipo", kind = "static")]
#[link(name = "LLVMVectorize", kind = "static")]
#[link(name = "LLVMMipsDisassembler", kind = "static")]
#[link(name = "LLVMMipsCodeGen", kind = "static")]
#[link(name = "LLVMMipsAsmParser", kind = "static")]
#[link(name = "LLVMMipsDesc", kind = "static")]
#[link(name = "LLVMMipsInfo", kind = "static")]
#[link(name = "LLVMMipsAsmPrinter", kind = "static")]
#[link(name = "LLVMARMDisassembler", kind = "static")]
#[link(name = "LLVMARMCodeGen", kind = "static")]
#[link(name = "LLVMARMAsmParser", kind = "static")]
#[link(name = "LLVMARMDesc", kind = "static")]
#[link(name = "LLVMARMInfo", kind = "static")]
#[link(name = "LLVMARMAsmPrinter", kind = "static")]
#[link(name = "LLVMX86Disassembler", kind = "static")]
#[link(name = "LLVMX86AsmParser", kind = "static")]
#[link(name = "LLVMX86CodeGen", kind = "static")]
#[link(name = "LLVMSelectionDAG", kind = "static")]
#[link(name = "LLVMAsmPrinter", kind = "static")]
#[link(name = "LLVMMCParser", kind = "static")]
#[link(name = "LLVMCodeGen", kind = "static")]
#[link(name = "LLVMScalarOpts", kind = "static")]
#[link(name = "LLVMInstCombine", kind = "static")]
#[link(name = "LLVMTransformUtils", kind = "static")]
#[link(name = "LLVMipa", kind = "static")]
#[link(name = "LLVMAnalysis", kind = "static")]
#[link(name = "LLVMTarget", kind = "static")]
#[link(name = "LLVMX86Desc", kind = "static")]
#[link(name = "LLVMX86Info", kind = "static")]
#[link(name = "LLVMX86AsmPrinter", kind = "static")]
#[link(name = "LLVMMC", kind = "static")]
#[link(name = "LLVMObject", kind = "static")]
#[link(name = "LLVMBitReader", kind = "static")]
#[link(name = "LLVMCore", kind = "static")]
#[link(name = "LLVMX86Utils", kind = "static")]
#[link(name = "LLVMSupport", kind = "static")]
#[link(name = "pthread")]
#[link(name = "dl")]
#[link(name = "m")]
#[link(name = "stdc++")]
extern {}
<commit_msg>Remove stray llvmdeps.rs<commit_after><|endoftext|>


<commit_before>use std::sync::atomic::{self, AtomicPtr};

pub struct Stack<T> {
    head: AtomicPtr<Node<T>>,
}

struct Node<T> {
    data: T,
    next: *mut Node<T>,
}

impl<T> Stack<T> {
    fn new() -> Stack<T> {
        Stack {
            head: AtomicPtr::default,
        }
    }

    fn push(&self, t: T) {
        // Allocate the node, and immediately turn it into a `*mut` pointer.
        let n = Box::into_raw(Box::new(Node {
            data: t,
            next: null_mut(),
        }));

        loop {
            // Snapshot current head.
            let head = self.head.load(atomic::Ordering::Relaxed);

            // Update `next` pointer with snapshot.
            unsafe { (*n).next = head; }

            // If snapshot is still good, link in new node.
            if self.head.compare_and_swap(head, n, atomic::Ordering::Release) == head {
                break
            }
        }
    }

    fn take_each(&self, f: F)
    where F: Fn(T) {
        // Replace the old head with a null pointer.
        let mut node = self.head.swap(AtomicPtr::default(), atomic::Ordering::Acquire);

        // We traverse every node until the pointer is null.
        while !node.is_null() {
            // Read the node into an owned box.
            let bx = unsafe { Box::from_raw(head) };
            // Apply the provided closure.
            f(bx.data);
            // Go to the next link.
            node = bx.next;
        }
    }
}

struct RawReader {
    active: *const AtomicBool,
    ptr: *const T,
}

impl RawReader {
    unsafe fn destroy(self) {
        // Drop the atomic boolean stored on the heap.
        mem::drop_in_place(self.active);
    }
}

struct Reader<'a, T> {
    raw: RawReader,
    _marker: PhantomData<'a>,
}

impl<'a, T> Reader<'a, T> {
    fn drop(&mut self) {
        self.raw.active.store(true);
    }
}

#[derive(Default)]
struct State {
    flags: AtomicUsize,
}

impl State {
    fn start_gc(&self) -> false {
        // Mark that a garbage collection is pending.
        if self.flags.fetch_or(1, atomic::Ordering::Relaxed) & 1 != 0 {
            // Another thread is pending to or currently garbage collecting, so we won't do the
            // same.
            return false;
        }

        // Spin until no thread is currently modifying the stacks. This prevents premature frees in
        // the thread which is currently pushing to `self.readers`.
        loop {
            // Read the flags, and if no readers or garbage collectors, activate garbage
            // collection.
            let flags = self.flags.compare_and_swap(1, 0b11, atomic::Ordering::Relaxed);
            if flags == 1 {
                // Currently, no one accesses the readers stack and the CAS above means that the
                // lowest bitflag have been set, indicating that a garbage collection is now
                // active.
                return true;
            }
        }
    }

    fn end_gc(&self) {
        self.flags.fetch_sub(1, atomic::Ordering::Relaxed);
    }

    fn start_read(&self) {
        // Increment the number of threads currently pushing to the readers stack. We add two to
        // account for the LSB being a separate bitflag.
        self.flags.fetch_add(2, atomic::Ordering::Relaxed);
    }

    fn end_read(&self) {
        self.flags.fetch_sub(2, atomic::Ordering::Relaxed);
    }
}

struct Atomic<T> {
    inner: AtomicPtr<T>,
    snapshots: Stack<Box<T>>,
    readers: Stack<RawReader>,
    state: State,
}

impl<T> Atomic<T> {
    fn new(inner: T) -> Atomic<T> {
        Atomic {
            inner: AtomicPtr::new(Box::into_raw(Box::new(inner))),
            snapshots: Stack::new(),
            readers: Stack::new(),
            flags: State::default(),
        }
    }

    fn gc(&self) {
        // Start the garbage collection.
        if !self.state.start_gc() {
            // Another thread is garbage collecting, so we short-circuit.
            return;
        }

        // Initially, every snapshot is marked unused.
        let mut unused = self.snapshots.collect();

        // Traverse the readers and update the reference counts.
        self.readers.take_each(|reader| {
            if reader.active.load() {
                // The reader is not released yet, and is thus considered active.

                // Remove the reader from the unused set and insert it back into the log (if it
                // exists in the unused set), as the snapshot is active.
                unused.remove(reader.ptr).map(|x| self.snapshots.insert(x));
                // Put the reader back in the structure.
                self.readers.insert(reader);
            } else {
                // The reader was released. Destroy it.
                reader.destroy();
            }
        });

        // End the garbage collection cycle.
        self.state.end_gc();
    }

    fn get(&self) -> Reader {
        // To avoid another thread freeing between reading and inserting into the readers stack, we
        // change the state to block garbage collecting for awhile.
        self.state.start_read();

        // Construct the raw reader.
        let reader = RawReader {
            // Load a snapshot of the pointer.
            ptr: self.inner.load(atomic::Ordering::Relaxed),
            // We allocate the atomic boolean on the heap as it is shared between the returned RAII
            // guard and the reader stack.
            released: Box::into_raw(Box::new(AtomicBool::new(false))),
        };

        // Register the reader through the reader stack, ensuring that it is not freed before the
        // RAII guard drops (`reader.release` is set to `true`).
        self.readers.push(reader);

        // Revert the original increment.
        self.state.end_read();

        Reader {
            raw: reader,
            _marker: PhantomData,
        }
    }

    fn set(&self, new: Box<T>) {
        // Replace the inner by the new value.
        let old = self.inner.swap(Box::into_raw(new), atomic::Ordering::Relaxed);
        // Push the old pointer to the snapshot stack.
        self.snapshots.push(Box::from_raw(old));
    }
}
<commit_msg>Make the garbage stack global.<commit_after>use std::sync::atomic::{self, AtomicPtr};

static GARBAGE: Stack<Box<Drop>> = Stack::new();
static READERS: Stack<RawReader> = Stack::new();
static STATE: State = State::new();

fn gc() {
    // Start the garbage collection.
    if !STATE.start_gc() {
        // Another thread is garbage collecting, so we short-circuit.
        return;
    }

    // Initially, every garbage is marked unused.
    let mut unused = GARBAGE.collect();

    // Traverse the readers and update the reference counts.
    READERS.take_each(|reader| {
        if reader.active.load() {
            // The reader is not released yet, and is thus considered active.

            // Remove the reader from the unused set and insert it back into the log (if it
            // exists in the unused set), as the garbage is active.
            unused.remove(reader.ptr).map(|x| GARBAGE.insert(x));
            // Put the reader back in the structure.
            READERS.insert(reader);
        } else {
            // The reader was released. Destroy it.
            reader.destroy();
        }
    });

    // End the garbage collection cycle.
    STATE.end_gc();
}

pub struct Stack<T> {
    head: AtomicPtr<Node<T>>,
}

struct Node<T> {
    data: T,
    next: *mut Node<T>,
}

impl<T> Stack<T> {
    const fn new() -> Stack<T> {
        Stack {
            head: AtomicPtr::new(0 as *const T),
        }
    }

    fn push(&self, t: T) {
        // Allocate the node, and immediately turn it into a `*mut` pointer.
        let n = Box::into_raw(Box::new(Node {
            data: t,
            next: null_mut(),
        }));

        loop {
            // Snapshot current head.
            let head = self.head.load(atomic::Ordering::Relaxed);

            // Update `next` pointer with snapshot.
            unsafe { (*n).next = head; }

            // If snapshot is still good, link in new node.
            if self.head.compare_and_swap(head, n, atomic::Ordering::Release) == head {
                break
            }
        }
    }

    fn take_each(&self, f: F)
    where F: Fn(T) {
        // Replace the old head with a null pointer.
        let mut node = self.head.swap(AtomicPtr::default(), atomic::Ordering::Acquire);

        // We traverse every node until the pointer is null.
        while !node.is_null() {
            // Read the node into an owned box.
            let bx = unsafe { Box::from_raw(head) };
            // Apply the provided closure.
            f(bx.data);
            // Go to the next link.
            node = bx.next;
        }
    }

    fn collect(&self) -> HashSet<T> {
        let mut hs = HashSet::new();
        self.take_each(|x| hs.insert(x));

        hs
    }
}

struct RawReader {
    active: *const AtomicBool,
    ptr: *const T,
}

impl RawReader {
    unsafe fn destroy(self) {
        // Drop the atomic boolean stored on the heap.
        mem::drop_in_place(self.active);
    }
}

struct Reader<'a, T> {
    raw: RawReader,
    _marker: PhantomData<'a>,
}

impl<'a, T> Reader<'a, T> {
    fn drop(&mut self) {
        self.raw.active.store(true);
    }
}

#[derive(Default)]
struct State {
    flags: AtomicUsize,
}

impl State {
    fn start_gc(&self) -> false {
        // Mark that a garbage collection is pending.
        if self.flags.fetch_or(1, atomic::Ordering::Relaxed) & 1 != 0 {
            // Another thread is pending to or currently garbage collecting, so we won't do the
            // same.
            return false;
        }

        // Spin until no thread is currently modifying the stacks. This prevents premature frees in
        // the thread which is currently pushing to `self.readers`.
        loop {
            // Read the flags, and if no readers or garbage collectors, activate garbage
            // collection.
            let flags = self.flags.compare_and_swap(1, 0b11, atomic::Ordering::Relaxed);
            if flags == 1 {
                // Currently, no one accesses the readers stack and the CAS above means that the
                // lowest bitflag have been set, indicating that a garbage collection is now
                // active.
                return true;
            }
        }
    }

    fn end_gc(&self) {
        self.flags.fetch_sub(1, atomic::Ordering::Relaxed);
    }

    fn start_read(&self) {
        // Increment the number of threads currently pushing to the readers stack. We add two to
        // account for the LSB being a separate bitflag.
        self.flags.fetch_add(2, atomic::Ordering::Relaxed);
    }

    fn end_read(&self) {
        self.flags.fetch_sub(2, atomic::Ordering::Relaxed);
    }
}

struct Atomic<T> {
    inner: AtomicPtr<T>,
    snapshots: Stack<Box<T>>,
    readers: Stack<RawReader>,
    state: State,
}

impl<T> Atomic<T> {
    fn new(inner: T) -> Atomic<T> {
        Atomic {
            inner: AtomicPtr::new(Box::into_raw(Box::new(inner))),
            snapshots: Stack::new(),
            readers: Stack::new(),
            flags: State::default(),
        }
    }

    fn get(&self) -> Reader {
        // To avoid another thread freeing between reading and inserting into the readers stack, we
        // change the state to block garbage collecting for awhile.
        STATE.start_read();

        // Construct the raw reader.
        let reader = RawReader {
            // Load a snapshot of the pointer.
            ptr: self.inner.load(atomic::Ordering::Relaxed),
            // We allocate the atomic boolean on the heap as it is shared between the returned RAII
            // guard and the reader stack.
            released: Box::into_raw(Box::new(AtomicBool::new(false))),
        };

        // Register the reader through the reader stack, ensuring that it is not freed before the
        // RAII guard drops (`reader.release` is set to `true`).
        READERS.push(reader);

        // Revert the original increment.
        STATE.end_read();

        Reader {
            raw: reader,
            _marker: PhantomData,
        }
    }

    fn set(&self, new: Box<T>) {
        // Replace the inner by the new value.
        let old = self.inner.swap(Box::into_raw(new), atomic::Ordering::Relaxed);
        // Push the old pointer to the garbage stack.
        GARBAGE.push(Box::from_raw(old));
    }
}
<|endoftext|>


<commit_before>// 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.

use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc};
use unstable::intrinsics::TyDesc;
use unstable::raw;
use mem::size_of;

extern {
    fn abort();
}

#[inline]
pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
    let header_size = size_of::<raw::Box<()>>();
    // FIXME (#2699): This alignment calculation is suspicious. Is it right?
    let total_size = align_to(header_size, body_align) + body_size;
    total_size
}

// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
// of two.
#[inline]
fn align_to(size: uint, align: uint) -> uint {
    assert!(align != 0);
    (size + align - 1) & !(align - 1)
}

/// A wrapper around libc::malloc, aborting on out-of-memory
pub unsafe fn malloc_raw(size: uint) -> *c_void {
    let p = malloc(size as size_t);
    if p.is_null() {
        // we need a non-allocating way to print an error here
        abort();
    }
    p
}

/// A wrapper around libc::realloc, aborting on out-of-memory
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
    let p = realloc(ptr, size as size_t);
    if p.is_null() {
        // we need a non-allocating way to print an error here
        abort();
    }
    p
}

/// The allocator for unique pointers without contained managed pointers.
#[cfg(not(test))]
#[lang="exchange_malloc"]
#[inline]
pub unsafe fn exchange_malloc(size: uintptr_t) -> *c_char {
    malloc_raw(size as uint) as *c_char
}

// FIXME: #7496
#[cfg(not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
pub unsafe fn closure_exchange_malloc_(td: *c_char, size: uintptr_t) -> *c_char {
    closure_exchange_malloc(td, size)
}

#[inline]
pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
    let td = td as *TyDesc;
    let size = size as uint;

    assert!(td.is_not_null());

    let total_size = get_box_size(size, (*td).align);
    let p = malloc_raw(total_size as uint);

    let box = p as *mut raw::Box<()>;
    (*box).type_desc = td;

    box as *c_char
}

// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler.
#[cfg(not(test))]
#[lang="exchange_free"]
#[inline]
pub unsafe fn exchange_free_(ptr: *c_char) {
    exchange_free(ptr)
}

pub unsafe fn exchange_free(ptr: *c_char) {
    free(ptr as *c_void);
}

#[cfg(test)]
mod bench {
    use extra::test::BenchHarness;

    #[bench]
    fn alloc_owned_small(bh: &mut BenchHarness) {
        do bh.iter {
            ~10;
        }
    }

    #[bench]
    fn alloc_owned_big(bh: &mut BenchHarness) {
        do bh.iter {
            ~[10, ..1000];
        }
    }
}
<commit_msg>auto merge of #10612 : pnkfelix/rust/remove-cut-and-pasted-rt-fixme, r=pcwalton<commit_after>// 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.

use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc};
use unstable::intrinsics::TyDesc;
use unstable::raw;
use mem::size_of;

extern {
    fn abort();
}

#[inline]
pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
    let header_size = size_of::<raw::Box<()>>();
    let total_size = align_to(header_size, body_align) + body_size;
    total_size
}

// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
// of two.
#[inline]
fn align_to(size: uint, align: uint) -> uint {
    assert!(align != 0);
    (size + align - 1) & !(align - 1)
}

/// A wrapper around libc::malloc, aborting on out-of-memory
pub unsafe fn malloc_raw(size: uint) -> *c_void {
    let p = malloc(size as size_t);
    if p.is_null() {
        // we need a non-allocating way to print an error here
        abort();
    }
    p
}

/// A wrapper around libc::realloc, aborting on out-of-memory
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
    let p = realloc(ptr, size as size_t);
    if p.is_null() {
        // we need a non-allocating way to print an error here
        abort();
    }
    p
}

/// The allocator for unique pointers without contained managed pointers.
#[cfg(not(test))]
#[lang="exchange_malloc"]
#[inline]
pub unsafe fn exchange_malloc(size: uintptr_t) -> *c_char {
    malloc_raw(size as uint) as *c_char
}

// FIXME: #7496
#[cfg(not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
pub unsafe fn closure_exchange_malloc_(td: *c_char, size: uintptr_t) -> *c_char {
    closure_exchange_malloc(td, size)
}

#[inline]
pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
    let td = td as *TyDesc;
    let size = size as uint;

    assert!(td.is_not_null());

    let total_size = get_box_size(size, (*td).align);
    let p = malloc_raw(total_size as uint);

    let box = p as *mut raw::Box<()>;
    (*box).type_desc = td;

    box as *c_char
}

// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler.
#[cfg(not(test))]
#[lang="exchange_free"]
#[inline]
pub unsafe fn exchange_free_(ptr: *c_char) {
    exchange_free(ptr)
}

pub unsafe fn exchange_free(ptr: *c_char) {
    free(ptr as *c_void);
}

#[cfg(test)]
mod bench {
    use extra::test::BenchHarness;

    #[bench]
    fn alloc_owned_small(bh: &mut BenchHarness) {
        do bh.iter {
            ~10;
        }
    }

    #[bench]
    fn alloc_owned_big(bh: &mut BenchHarness) {
        do bh.iter {
            ~[10, ..1000];
        }
    }
}
<|endoftext|>