<commit_before>#![allow(dead_code)]

use core::mem;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use super::CVoid;

#[repr(C)]
#[derive(Debug)]
pub struct MailboxRaw {
    msg_buf: *mut u8,
    msg_buf_len: u32,
    msg_size: u32,
    read_pos: u32,
    write_pos: u32,
    data_added: Option<extern "C" fn()>,
}

impl Default for MailboxRaw {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[repr(C)]
#[derive(Debug)]
pub struct Mailbox<'mem, T: 'mem> {
    mb: UnsafeCell<MailboxRaw>,
    _data: PhantomData<&'mem mut [T]>,
}

impl<'mem, T> Default for Mailbox<'mem, T> {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[link(name = "mouros")]
extern "C" {
    fn os_mailbox_init(
        mb: *mut MailboxRaw,
        msg_buf: *mut CVoid,
        msg_buf_len: u32,
        msg_size: u32,
        data_added_callback: Option<extern "C" fn()>,
    );

    fn os_mailbox_write(mb: *mut MailboxRaw, msg: *const CVoid) -> u8;

    fn os_mailbox_write_multiple(mb: *mut MailboxRaw, msgs: *const CVoid, msg_num: u32) -> u32;

    fn os_mailbox_read(mb: *mut MailboxRaw, out: *mut CVoid) -> u8;

    fn os_mailbox_read_multiple(mb: *mut MailboxRaw, out: *mut CVoid, out_msg_num: u32) -> u32;
}

impl<'mem, T> Mailbox<'mem, T> {
    pub fn new(buf: &'mem mut [T]) -> Mailbox<T> {
        let mut mb = Mailbox::default();

        unsafe {
            os_mailbox_init(
                mb.mb.get(),
                buf.as_mut_ptr() as *mut CVoid,
                buf.len() as u32,
                mem::size_of::<T>() as u32,
                None,
            );
        }

        mb
    }

    pub fn write(&self, msg: T) -> bool {
        unsafe { os_mailbox_write(self.mb.get(), &msg as *const T as *const CVoid) != 0 }
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        unsafe {
            os_mailbox_write_multiple(
                self.mb.get(),
                msgs.as_ptr() as *const CVoid,
                msgs.len() as u32,
            )
        }
    }

    pub fn read(&self) -> Option<T> {
        unsafe {
            let mut tmp = mem::zeroed();

            if os_mailbox_read(self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {
                Some(tmp)
            } else {
                None
            }
        }
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        unsafe {
            os_mailbox_read_multiple(
                self.mb.get(),
                out_buf.as_mut_ptr() as *mut CVoid,
                out_buf.len() as u32,
            )
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get()
    }
}

pub struct RxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> RxChannelSpsc<'mb, 'mem, T> {
    pub fn read(&self) -> Option<T> {
        self.mb.read()
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        self.mb.read_multiple(out_buf)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub struct TxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> TxChannelSpsc<'mb, 'mem, T> {
    pub fn write(&self, msg: T) -> bool {
        self.mb.write(msg)
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        self.mb.write_multiple(msgs)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub fn channel_spsc<'mb, 'mem, T>(
    mailbox: &'mb mut Mailbox<'mem, T>,
) -> (RxChannelSpsc<'mb, 'mem, T>, TxChannelSpsc<'mb, 'mem, T>) {
    (
        RxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
        TxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
    )
}
<commit_msg>Removed unnecessary mutable specifier<commit_after>#![allow(dead_code)]

use core::mem;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use super::CVoid;

#[repr(C)]
#[derive(Debug)]
pub struct MailboxRaw {
    msg_buf: *mut u8,
    msg_buf_len: u32,
    msg_size: u32,
    read_pos: u32,
    write_pos: u32,
    data_added: Option<extern "C" fn()>,
}

impl Default for MailboxRaw {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[repr(C)]
#[derive(Debug)]
pub struct Mailbox<'mem, T: 'mem> {
    mb: UnsafeCell<MailboxRaw>,
    _data: PhantomData<&'mem mut [T]>,
}

impl<'mem, T> Default for Mailbox<'mem, T> {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[link(name = "mouros")]
extern "C" {
    fn os_mailbox_init(
        mb: *mut MailboxRaw,
        msg_buf: *mut CVoid,
        msg_buf_len: u32,
        msg_size: u32,
        data_added_callback: Option<extern "C" fn()>,
    );

    fn os_mailbox_write(mb: *mut MailboxRaw, msg: *const CVoid) -> u8;

    fn os_mailbox_write_multiple(mb: *mut MailboxRaw, msgs: *const CVoid, msg_num: u32) -> u32;

    fn os_mailbox_read(mb: *mut MailboxRaw, out: *mut CVoid) -> u8;

    fn os_mailbox_read_multiple(mb: *mut MailboxRaw, out: *mut CVoid, out_msg_num: u32) -> u32;
}

impl<'mem, T> Mailbox<'mem, T> {
    pub fn new(buf: &'mem mut [T]) -> Mailbox<T> {
        let mb = Mailbox::default();

        unsafe {
            os_mailbox_init(
                mb.mb.get(),
                buf.as_mut_ptr() as *mut CVoid,
                buf.len() as u32,
                mem::size_of::<T>() as u32,
                None,
            );
        }

        mb
    }

    pub fn write(&self, msg: T) -> bool {
        unsafe { os_mailbox_write(self.mb.get(), &msg as *const T as *const CVoid) != 0 }
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        unsafe {
            os_mailbox_write_multiple(
                self.mb.get(),
                msgs.as_ptr() as *const CVoid,
                msgs.len() as u32,
            )
        }
    }

    pub fn read(&self) -> Option<T> {
        unsafe {
            let mut tmp = mem::zeroed();

            if os_mailbox_read(self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {
                Some(tmp)
            } else {
                None
            }
        }
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        unsafe {
            os_mailbox_read_multiple(
                self.mb.get(),
                out_buf.as_mut_ptr() as *mut CVoid,
                out_buf.len() as u32,
            )
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get()
    }
}

pub struct RxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> RxChannelSpsc<'mb, 'mem, T> {
    pub fn read(&self) -> Option<T> {
        self.mb.read()
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        self.mb.read_multiple(out_buf)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub struct TxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> TxChannelSpsc<'mb, 'mem, T> {
    pub fn write(&self, msg: T) -> bool {
        self.mb.write(msg)
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        self.mb.write_multiple(msgs)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub fn channel_spsc<'mb, 'mem, T>(
    mailbox: &'mb mut Mailbox<'mem, T>,
) -> (RxChannelSpsc<'mb, 'mem, T>, TxChannelSpsc<'mb, 'mem, T>) {
    (
        RxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
        TxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
    )
}
<|endoftext|>


<commit_before>use libc;
use cssparser::{Parser, ParserInput, Token, BasicParseError};
use glib::translate::*;
use glib_sys;

use std::f64::consts::*;
use std::mem;
use std::ptr;
use std::slice;
use std::str;

use util::utf8_cstr;

#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
    pub display: String
}

impl ParseError {
    pub fn new<T: AsRef<str>> (msg: T) -> ParseError {
        ParseError { display: msg.as_ref ().to_string () }
    }
}

impl<'a> From<BasicParseError<'a>> for ParseError {
    fn from (_: BasicParseError) -> ParseError {
        ParseError::new ("parse error")
    }
}

pub trait Parse: Sized {
    type Data;
    type Err;

    fn parse (s: &str, data: Self::Data) -> Result<Self, Self::Err>;
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
// Returns an f64 angle in degrees

pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let angle = {
        let token = parser.next ()
            .map_err (|_| ParseError::new ("expected angle"))?;

        match *token {
            Token::Number { value, .. } => f64::from(value),

            Token::Dimension { value, ref unit, .. } => {
                let value = f64::from(value);

                match unit.as_ref () {
                    "deg"  => value,
                    "grad" => value * 360.0 / 400.0,
                    "rad"  => value * 180.0 / PI,
                    _      => return Err (ParseError::new ("expected 'deg' | 'grad' | 'rad'"))
                }
            },

            _ => return Err (ParseError::new ("expected angle"))
        }
    };

    parser.expect_exhausted ().map_err (|_| ParseError::new ("expected angle"))?;

    Ok (angle)
}

pub fn optional_comma (parser: &mut Parser) {
    let _ = parser.try (|p| p.expect_comma ());
}

// number-optional-number
//
// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber

pub fn number_optional_number (s: &str) -> Result <(f64, f64), ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let x = f64::from(parser.expect_number ()?);

    if !parser.is_exhausted () {
        let state = parser.state ();

        match *parser.next ()? {
            Token::Comma => {},
            _ => parser.reset (&state)
        };

        let y = f64::from(parser.expect_number ()?);

        parser.expect_exhausted ()?;

        Ok ((x, y))
    } else {
        Ok ((x, x))
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_optional_number (s: *const libc::c_char,
                                                     out_x: *mut f64,
                                                     out_y: *mut f64) -> glib_sys::gboolean {
    assert! (!s.is_null ());
    assert! (!out_x.is_null ());
    assert! (!out_y.is_null ());

    let string = unsafe { utf8_cstr(s) };

    match number_optional_number (string) {
        Ok ((x, y)) => {
            unsafe {
                *out_x = x;
                *out_y = y;
            }
            true
        },

        Err (_) => {
            unsafe {
                *out_x = 0.0;
                *out_y = 0.0;
            }
            false
        }
    }.to_glib ()
}

// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF

pub fn list_of_points (string: &str) -> Result <Vec<(f64, f64)>, ParseError> {
    let mut input = ParserInput::new (string);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::new ();

    loop {
        let x = f64::from(parser.expect_number ()?);

        optional_comma (&mut parser);

        let y = f64::from(parser.expect_number ()?);

        v.push ((x, y));

        if parser.is_exhausted () {
            break;
        }

        match parser.next_including_whitespace () {
            Ok (&Token::WhiteSpace(_)) => (),
            _ => optional_comma (&mut parser)
        }
    }

    Ok (v)
}

// Lists of number values

pub enum ListLength {
    Exact (usize),
    Maximum (usize)
}

#[derive(Debug, PartialEq)]
pub enum NumberListError {
    IncorrectNumberOfElements,
    Parse (ParseError)
}

pub fn number_list (s: &str, length: ListLength) -> Result <Vec<f64>, NumberListError> {
    let n;

    match length {
        ListLength::Exact (l)   => { assert! (l > 0); n = l; }
        ListLength::Maximum (l) => { assert! (l > 0); n = l; }
    }

    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::<f64>::with_capacity (n);

    for i in 0..n {
        v.push (f64::from(parser.expect_number ().map_err (|_| NumberListError::Parse (ParseError::new ("expected number")))?));

        if i != n - 1 {
            optional_comma (&mut parser);
        }

        if parser.is_exhausted () {
            if let ListLength::Maximum (_) = length {
                break;
            }
        }
    }

    parser.expect_exhausted ().map_err (|_| NumberListError::IncorrectNumberOfElements)?;

    Ok(v)
}

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NumberListLength {
    Exact,
    Maximum
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_list (in_str:   *const libc::c_char,
                                          nlength:  NumberListLength,
                                          size:     libc::size_t,
                                          out_list: *mut *const libc::c_double,
                                          out_list_length: *mut libc::size_t) -> glib_sys::gboolean {
    assert! (!in_str.is_null ());
    assert! (!out_list.is_null ());
    assert! (!out_list_length.is_null ());

    let length = match nlength {
        NumberListLength::Exact   => ListLength::Exact (size),
        NumberListLength::Maximum => ListLength::Maximum (size)
    };

    let s = unsafe { utf8_cstr(in_str) };

    let result = number_list (&s, length);

    match result {
        Ok (number_list) => {
            let num_elems = number_list.len ();

            let c_array = unsafe {
                glib_sys::g_malloc_n (num_elems,
                                      mem::size_of::<libc::c_double> ())
                    as *mut libc::c_double
            };

            let array = unsafe { slice::from_raw_parts_mut (c_array, num_elems) };

            array.copy_from_slice (&number_list);

            unsafe {
                *out_list = c_array;
                *out_list_length = num_elems;
            }

            true
        },

        Err (_) => {
            unsafe {
                *out_list = ptr::null ();
                *out_list_length = 0;
            }
            false
        }
    }.to_glib ()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_number_optional_number () {
        assert_eq! (number_optional_number ("1, 2"), Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1 2"),  Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1"),    Ok ((1.0, 1.0)));

        assert_eq! (number_optional_number ("-1, -2"), Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1 -2"),  Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1"),     Ok ((-1.0, -1.0)));
    }

    #[test]
    fn invalid_number_optional_number () {
        assert! (number_optional_number ("").is_err ());
        assert! (number_optional_number ("1x").is_err ());
        assert! (number_optional_number ("x1").is_err ());
        assert! (number_optional_number ("1 x").is_err ());
        assert! (number_optional_number ("1 , x").is_err ());
        assert! (number_optional_number ("1 , 2x").is_err ());
        assert! (number_optional_number ("1 2 x").is_err ());
    }

    #[test]
    fn parses_list_of_points () {
        assert_eq! (list_of_points (" 1 2 "),      Ok (vec! [(1.0, 2.0)]));
        assert_eq! (list_of_points ("1 2 3 4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 -3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,-3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
    }

    #[test]
    fn errors_on_invalid_list_of_points () {
        assert! (list_of_points ("-1-2-3-4").is_err ());
        assert! (list_of_points ("1 2-3,-4").is_err ());
    }

    #[test]
    fn parses_angle () {
        assert_eq! (angle_degrees ("0"),        Ok (0.0));
        assert_eq! (angle_degrees ("15"),       Ok (15.0));
        assert_eq! (angle_degrees ("180.5deg"), Ok (180.5));
        assert_eq! (angle_degrees ("1rad"),     Ok (180.0 / PI));
        assert_eq! (angle_degrees ("-400grad"), Ok (-360.0));

        assert! (angle_degrees ("").is_err ());
        assert! (angle_degrees ("foo").is_err ());
        assert! (angle_degrees ("300foo").is_err ());
    }

    #[test]
    fn parses_number_list () {
        assert_eq! (number_list ("5", ListLength::Exact (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1 2 3 4", ListLength::Exact (4)),
                    Ok (vec! [1.0, 2.0, 3.0, 4.0]));

        assert_eq! (number_list ("5", ListLength::Maximum (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1.0, -2.5", ListLength::Maximum (2)),
                    Ok (vec! [1.0, -2.5]));

        assert_eq! (number_list ("5 6", ListLength::Maximum (3)),
                    Ok (vec! [5.0, 6.0]));
    }

    #[test]
    fn errors_on_invalid_number_list () {
        // empty
        assert! (number_list ("", ListLength::Exact (1)).is_err ());

        // garbage
        assert! (number_list ("foo", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo 2", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1,foo", ListLength::Exact (2)).is_err ());

        // too many
        assert! (number_list ("1 2", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1,2,3", ListLength::Maximum (2)).is_err ());

        // extra token
        assert! (number_list ("1,", ListLength::Exact (1)).is_err ());

        // too few
        assert! (number_list ("1", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 2", ListLength::Exact (3)).is_err ());
    }
}
<commit_msg>parsers::parse() - New function, to replace property_bag::parse_*()<commit_after>use libc;
use cssparser::{Parser, ParserInput, Token, BasicParseError};
use glib::translate::*;
use glib_sys;

use std::f64::consts::*;
use std::mem;
use std::ptr;
use std::slice;
use std::str;

use error::{AttributeError, NodeError};
use util::utf8_cstr;

#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
    pub display: String
}

impl ParseError {
    pub fn new<T: AsRef<str>> (msg: T) -> ParseError {
        ParseError { display: msg.as_ref ().to_string () }
    }
}

impl<'a> From<BasicParseError<'a>> for ParseError {
    fn from (_: BasicParseError) -> ParseError {
        ParseError::new ("parse error")
    }
}

pub trait Parse: Sized {
    type Data;
    type Err;

    fn parse (s: &str, data: Self::Data) -> Result<Self, Self::Err>;
}

/// Parses a `value` string into a type `T` with an optional validation function.
///
/// Some value types need some extra `data` to be parsed.  This
/// corresponds to the `<T as Parse>::Data` associated type.  For
/// example, an `RsvgLength` has an associated `type Data =
/// LengthDir`, so to parse a length value, you could specify
/// `LengthDir::Horizontal` for `data`, for example.
pub fn parse<T>(key: &str,
                value: &str,
                data: <T as Parse>::Data,
                validate: Option<fn(T) -> Result<T, AttributeError>>) -> Result <T, NodeError>
    where T: Parse<Err = AttributeError> + Copy
{
    T::parse (value, data)
        .and_then (|v|
                   if let Some(validate) = validate {
                       validate(v)
                   } else {
                       Ok(v)
                   })
        .map_err (|e| NodeError::attribute_error (key, e))
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
// Returns an f64 angle in degrees

pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let angle = {
        let token = parser.next ()
            .map_err (|_| ParseError::new ("expected angle"))?;

        match *token {
            Token::Number { value, .. } => f64::from(value),

            Token::Dimension { value, ref unit, .. } => {
                let value = f64::from(value);

                match unit.as_ref () {
                    "deg"  => value,
                    "grad" => value * 360.0 / 400.0,
                    "rad"  => value * 180.0 / PI,
                    _      => return Err (ParseError::new ("expected 'deg' | 'grad' | 'rad'"))
                }
            },

            _ => return Err (ParseError::new ("expected angle"))
        }
    };

    parser.expect_exhausted ().map_err (|_| ParseError::new ("expected angle"))?;

    Ok (angle)
}

pub fn optional_comma (parser: &mut Parser) {
    let _ = parser.try (|p| p.expect_comma ());
}

// number-optional-number
//
// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber

pub fn number_optional_number (s: &str) -> Result <(f64, f64), ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let x = f64::from(parser.expect_number ()?);

    if !parser.is_exhausted () {
        let state = parser.state ();

        match *parser.next ()? {
            Token::Comma => {},
            _ => parser.reset (&state)
        };

        let y = f64::from(parser.expect_number ()?);

        parser.expect_exhausted ()?;

        Ok ((x, y))
    } else {
        Ok ((x, x))
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_optional_number (s: *const libc::c_char,
                                                     out_x: *mut f64,
                                                     out_y: *mut f64) -> glib_sys::gboolean {
    assert! (!s.is_null ());
    assert! (!out_x.is_null ());
    assert! (!out_y.is_null ());

    let string = unsafe { utf8_cstr(s) };

    match number_optional_number (string) {
        Ok ((x, y)) => {
            unsafe {
                *out_x = x;
                *out_y = y;
            }
            true
        },

        Err (_) => {
            unsafe {
                *out_x = 0.0;
                *out_y = 0.0;
            }
            false
        }
    }.to_glib ()
}

// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF

pub fn list_of_points (string: &str) -> Result <Vec<(f64, f64)>, ParseError> {
    let mut input = ParserInput::new (string);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::new ();

    loop {
        let x = f64::from(parser.expect_number ()?);

        optional_comma (&mut parser);

        let y = f64::from(parser.expect_number ()?);

        v.push ((x, y));

        if parser.is_exhausted () {
            break;
        }

        match parser.next_including_whitespace () {
            Ok (&Token::WhiteSpace(_)) => (),
            _ => optional_comma (&mut parser)
        }
    }

    Ok (v)
}

// Lists of number values

pub enum ListLength {
    Exact (usize),
    Maximum (usize)
}

#[derive(Debug, PartialEq)]
pub enum NumberListError {
    IncorrectNumberOfElements,
    Parse (ParseError)
}

pub fn number_list (s: &str, length: ListLength) -> Result <Vec<f64>, NumberListError> {
    let n;

    match length {
        ListLength::Exact (l)   => { assert! (l > 0); n = l; }
        ListLength::Maximum (l) => { assert! (l > 0); n = l; }
    }

    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::<f64>::with_capacity (n);

    for i in 0..n {
        v.push (f64::from(parser.expect_number ().map_err (|_| NumberListError::Parse (ParseError::new ("expected number")))?));

        if i != n - 1 {
            optional_comma (&mut parser);
        }

        if parser.is_exhausted () {
            if let ListLength::Maximum (_) = length {
                break;
            }
        }
    }

    parser.expect_exhausted ().map_err (|_| NumberListError::IncorrectNumberOfElements)?;

    Ok(v)
}

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NumberListLength {
    Exact,
    Maximum
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_list (in_str:   *const libc::c_char,
                                          nlength:  NumberListLength,
                                          size:     libc::size_t,
                                          out_list: *mut *const libc::c_double,
                                          out_list_length: *mut libc::size_t) -> glib_sys::gboolean {
    assert! (!in_str.is_null ());
    assert! (!out_list.is_null ());
    assert! (!out_list_length.is_null ());

    let length = match nlength {
        NumberListLength::Exact   => ListLength::Exact (size),
        NumberListLength::Maximum => ListLength::Maximum (size)
    };

    let s = unsafe { utf8_cstr(in_str) };

    let result = number_list (&s, length);

    match result {
        Ok (number_list) => {
            let num_elems = number_list.len ();

            let c_array = unsafe {
                glib_sys::g_malloc_n (num_elems,
                                      mem::size_of::<libc::c_double> ())
                    as *mut libc::c_double
            };

            let array = unsafe { slice::from_raw_parts_mut (c_array, num_elems) };

            array.copy_from_slice (&number_list);

            unsafe {
                *out_list = c_array;
                *out_list_length = num_elems;
            }

            true
        },

        Err (_) => {
            unsafe {
                *out_list = ptr::null ();
                *out_list_length = 0;
            }
            false
        }
    }.to_glib ()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_number_optional_number () {
        assert_eq! (number_optional_number ("1, 2"), Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1 2"),  Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1"),    Ok ((1.0, 1.0)));

        assert_eq! (number_optional_number ("-1, -2"), Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1 -2"),  Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1"),     Ok ((-1.0, -1.0)));
    }

    #[test]
    fn invalid_number_optional_number () {
        assert! (number_optional_number ("").is_err ());
        assert! (number_optional_number ("1x").is_err ());
        assert! (number_optional_number ("x1").is_err ());
        assert! (number_optional_number ("1 x").is_err ());
        assert! (number_optional_number ("1 , x").is_err ());
        assert! (number_optional_number ("1 , 2x").is_err ());
        assert! (number_optional_number ("1 2 x").is_err ());
    }

    #[test]
    fn parses_list_of_points () {
        assert_eq! (list_of_points (" 1 2 "),      Ok (vec! [(1.0, 2.0)]));
        assert_eq! (list_of_points ("1 2 3 4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 -3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,-3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
    }

    #[test]
    fn errors_on_invalid_list_of_points () {
        assert! (list_of_points ("-1-2-3-4").is_err ());
        assert! (list_of_points ("1 2-3,-4").is_err ());
    }

    #[test]
    fn parses_angle () {
        assert_eq! (angle_degrees ("0"),        Ok (0.0));
        assert_eq! (angle_degrees ("15"),       Ok (15.0));
        assert_eq! (angle_degrees ("180.5deg"), Ok (180.5));
        assert_eq! (angle_degrees ("1rad"),     Ok (180.0 / PI));
        assert_eq! (angle_degrees ("-400grad"), Ok (-360.0));

        assert! (angle_degrees ("").is_err ());
        assert! (angle_degrees ("foo").is_err ());
        assert! (angle_degrees ("300foo").is_err ());
    }

    #[test]
    fn parses_number_list () {
        assert_eq! (number_list ("5", ListLength::Exact (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1 2 3 4", ListLength::Exact (4)),
                    Ok (vec! [1.0, 2.0, 3.0, 4.0]));

        assert_eq! (number_list ("5", ListLength::Maximum (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1.0, -2.5", ListLength::Maximum (2)),
                    Ok (vec! [1.0, -2.5]));

        assert_eq! (number_list ("5 6", ListLength::Maximum (3)),
                    Ok (vec! [5.0, 6.0]));
    }

    #[test]
    fn errors_on_invalid_number_list () {
        // empty
        assert! (number_list ("", ListLength::Exact (1)).is_err ());

        // garbage
        assert! (number_list ("foo", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo 2", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1,foo", ListLength::Exact (2)).is_err ());

        // too many
        assert! (number_list ("1 2", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1,2,3", ListLength::Maximum (2)).is_err ());

        // extra token
        assert! (number_list ("1,", ListLength::Exact (1)).is_err ());

        // too few
        assert! (number_list ("1", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 2", ListLength::Exact (3)).is_err ());
    }
}
<|endoftext|>


<commit_before>use crate::sites::*;
use std::collections::BTreeSet;

pub const LUT4_PIN_MAP : &[(&str, &str)] = &[
    ("A", "A"),
    ("B", "B"),
    ("C", "C"),
    ("D", "D"),
    ("Z", "F"),
];

// TODO: need to add an extra pip to use LUT->DI path
const FD1P3BX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];
const FD1P3DX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3IX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3JX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];

const IB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "B"),
    ("O", "O"),
];

const OB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "I"),
    ("O", "B"),
];

// TODO: add back DFFs once we have some constraints set up

const BEL_CELL_TYPES : &[(&str, &[&str])] = &[
    ("OXIDE_COMB", &["LUT4"]),
    ("OXIDE_FF", &["FD1P3BX", "FD1P3DX", "FD1P3IX", "FD1P3JX"]),
    ("SEIO33_CORE", &["IB", "OB"]),
    ("SEIO18_CORE", &["IB", "OB"]),
    ("DCC", &["DCC"]),
    ("OSC_CORE", &["OSC_CORE"]),
    ("OXIDE_EBR", &["DP16K_MODE", "PDP16K_MODE", "PDPSC16K_MODE"]),
];

fn conv_map(map: &[(&str, &str)]) -> Vec<(String, String)> {
    map.iter().map(|(c, b)| (c.to_string(), b.to_string())).collect()
}

fn auto_map(site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    bel.pins.iter().map(|p| &site.bel_pins[*p]).map(|p| (p.pin_name.to_string(), p.pin_name.to_string())).collect()
}

fn offset_bus(pin: &str, prefix: &str, rep: &str, offset: i32) -> String {
    let idx = pin[prefix.len()..].parse::<i32>().unwrap();
    format!("{}{}", rep, idx + offset)
}

fn bram_map(cell_type: &str, site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    let mut result = Vec::new();
    // PDP16K is a 1:1 map
    for bel_pin in bel.pins.iter().map(|p| &site.bel_pins[*p].pin_name) {
        let mut cell_pin = bel_pin.into();
        match &bel_pin[..] {
            "ONEERR" => { cell_pin = "ONEBITERR".into() },
            "TWOERR" => { cell_pin = "TWOBITERR".into() },
            _ => {},
        }
        match cell_type {
            "DP16K_MODE" => { /* all pins pass through */ }
            "PDPSC16K_MODE" | "PDP16K_MODE" => {
                if bel_pin.starts_with("ADA") { cell_pin = bel_pin.replace("ADA", "ADW") }
                else if bel_pin.starts_with("ADB") { cell_pin = bel_pin.replace("ADB", "ADR") }
                else if bel_pin.starts_with("CSA") { cell_pin = bel_pin.replace("CSA", "CSW") }
                else if bel_pin.starts_with("CSB") { cell_pin = bel_pin.replace("CSB", "CSR") }
                else if bel_pin == "CLKA" { cell_pin = if cell_type == "PDPSC16K_MODE" { "CLK" } else { "CLKW" }.into() }
                else if bel_pin == "CLKB" { cell_pin = if cell_type == "PDPSC16K_MODE" { "CLK" } else { "CLKR" }.into() }
                else if bel_pin == "CEA" { cell_pin = "CEW".into() }
                else if bel_pin == "CEB" { cell_pin = "CER".into() }
                else if bel_pin == "RSTA" || bel_pin == "RSTB" { cell_pin = "RST".into() }
                else if bel_pin.starts_with("DIA") { cell_pin = bel_pin.replace("DIA", "DI") }
                else if bel_pin.starts_with("DIB") { cell_pin = offset_bus(bel_pin, "DIA", "DI", 18) }
                else if bel_pin.starts_with("DOA") { cell_pin = offset_bus(bel_pin, "DOA", "DO", 18) }
                else if bel_pin.starts_with("DOB") { cell_pin = bel_pin.replace("DOB", "DO") }
            },
            _ => unimplemented!(),
        }
        result.push((cell_pin, bel_pin.to_string()))
    }
    result.extend(conv_map(&[
        ("VCC", "DWS0"),
        ("VCC", "DWS1"),
        ("VCC", "DWS2"),
        ("VCC", "DWS3"),
        ("VCC", "DWS4"),
    ]));
    result
}

fn get_map_for_cell_bel(cell_type: &str, site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    match cell_type {
        "LUT4" => conv_map(LUT4_PIN_MAP),
        "FD1P3BX" => conv_map(FD1P3BX_PIN_MAP),
        "FD1P3DX" => conv_map(FD1P3DX_PIN_MAP),
        "FD1P3IX" => conv_map(FD1P3IX_PIN_MAP),
        "FD1P3JX" => conv_map(FD1P3JX_PIN_MAP),
        "IB" => conv_map(IB_PIN_MAP),
        "OB" => conv_map(OB_PIN_MAP),
        "DCC" => auto_map(site, bel),
        "OSC_CORE" => auto_map(site, bel),
        "PDPSC16K_MODE" | "PDP16K_MODE" | "DP16K_MODE" => bram_map(cell_type, site, bel),
        _ => unimplemented!(),
    }
}

#[derive(Clone)]
pub struct PinMap {
    pub cell_type: String,
    pub bels: Vec<String>,
    pub pin_map: Vec<(String, String)>,
}

pub fn get_pin_maps(site: &Site) -> Vec<PinMap> {
    let mut map = Vec::new();
    let unique_bel_types : BTreeSet<String>
        = site.bels.iter().filter_map(|b| if b.bel_class == SiteBelClass::BEL { Some(b.bel_type.to_string()) } else { None }).collect();
    for bel_type in unique_bel_types.iter() {
        if let Some((_, cell_types)) = BEL_CELL_TYPES.iter().find(|(bt, _)| bt == bel_type) {
            for cell_type in cell_types.iter() {
                map.push(PinMap {
                    cell_type: cell_type.to_string(),
                    bels: site.bels.iter().filter_map(|b| if &b.bel_type == bel_type { Some(b.name.to_string()) } else { None }).collect(),
                    pin_map: get_map_for_cell_bel(cell_type, site, site.bels.iter().find(|b| &b.bel_type == bel_type).unwrap()),
                });
            }
        }
    }
    return map;
}
<commit_msg>interchange: Add constant connections for WE pins in PDP mode<commit_after>use crate::sites::*;
use std::collections::BTreeSet;

pub const LUT4_PIN_MAP : &[(&str, &str)] = &[
    ("A", "A"),
    ("B", "B"),
    ("C", "C"),
    ("D", "D"),
    ("Z", "F"),
];

// TODO: need to add an extra pip to use LUT->DI path
const FD1P3BX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];
const FD1P3DX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3IX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3JX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];

const IB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "B"),
    ("O", "O"),
];

const OB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "I"),
    ("O", "B"),
];

// TODO: add back DFFs once we have some constraints set up

const BEL_CELL_TYPES : &[(&str, &[&str])] = &[
    ("OXIDE_COMB", &["LUT4"]),
    ("OXIDE_FF", &["FD1P3BX", "FD1P3DX", "FD1P3IX", "FD1P3JX"]),
    ("SEIO33_CORE", &["IB", "OB"]),
    ("SEIO18_CORE", &["IB", "OB"]),
    ("DCC", &["DCC"]),
    ("OSC_CORE", &["OSC_CORE"]),
    ("OXIDE_EBR", &["DP16K_MODE", "PDP16K_MODE", "PDPSC16K_MODE"]),
];

fn conv_map(map: &[(&str, &str)]) -> Vec<(String, String)> {
    map.iter().map(|(c, b)| (c.to_string(), b.to_string())).collect()
}

fn auto_map(site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    bel.pins.iter().map(|p| &site.bel_pins[*p]).map(|p| (p.pin_name.to_string(), p.pin_name.to_string())).collect()
}

fn offset_bus(pin: &str, prefix: &str, rep: &str, offset: i32) -> String {
    let idx = pin[prefix.len()..].parse::<i32>().unwrap();
    format!("{}{}", rep, idx + offset)
}

fn bram_map(cell_type: &str, site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    let mut result = Vec::new();
    // PDP16K is a 1:1 map
    for bel_pin in bel.pins.iter().map(|p| &site.bel_pins[*p].pin_name) {
        let mut cell_pin = bel_pin.into();
        match &bel_pin[..] {
            "ONEERR" => { cell_pin = "ONEBITERR".into() },
            "TWOERR" => { cell_pin = "TWOBITERR".into() },
            _ => {},
        }
        match cell_type {
            "DP16K_MODE" => { /* all pins pass through */ }
            "PDPSC16K_MODE" | "PDP16K_MODE" => {
                if bel_pin.starts_with("ADA") { cell_pin = bel_pin.replace("ADA", "ADW") }
                else if bel_pin.starts_with("ADB") { cell_pin = bel_pin.replace("ADB", "ADR") }
                else if bel_pin.starts_with("CSA") { cell_pin = bel_pin.replace("CSA", "CSW") }
                else if bel_pin.starts_with("CSB") { cell_pin = bel_pin.replace("CSB", "CSR") }
                else if bel_pin == "CLKA" { cell_pin = if cell_type == "PDPSC16K_MODE" { "CLK" } else { "CLKW" }.into() }
                else if bel_pin == "CLKB" { cell_pin = if cell_type == "PDPSC16K_MODE" { "CLK" } else { "CLKR" }.into() }
                else if bel_pin == "CEA" { cell_pin = "CEW".into() }
                else if bel_pin == "CEB" { cell_pin = "CER".into() }
                else if bel_pin == "RSTA" || bel_pin == "RSTB" { cell_pin = "RST".into() }
                else if bel_pin.starts_with("DIA") { cell_pin = bel_pin.replace("DIA", "DI") }
                else if bel_pin.starts_with("DIB") { cell_pin = offset_bus(bel_pin, "DIA", "DI", 18) }
                else if bel_pin.starts_with("DOA") { cell_pin = offset_bus(bel_pin, "DOA", "DO", 18) }
                else if bel_pin.starts_with("DOB") { cell_pin = bel_pin.replace("DOB", "DO") }
                else if bel_pin == "WEA" { cell_pin = "VCC".into(); }
                else if bel_pin == "WEB" { cell_pin = "GND".into(); }
            },
            _ => unimplemented!(),
        }
        result.push((cell_pin, bel_pin.to_string()))
    }
    result.extend(conv_map(&[
        ("VCC", "DWS0"),
        ("VCC", "DWS1"),
        ("VCC", "DWS2"),
        ("VCC", "DWS3"),
        ("VCC", "DWS4"),
    ]));
    result
}

fn get_map_for_cell_bel(cell_type: &str, site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    match cell_type {
        "LUT4" => conv_map(LUT4_PIN_MAP),
        "FD1P3BX" => conv_map(FD1P3BX_PIN_MAP),
        "FD1P3DX" => conv_map(FD1P3DX_PIN_MAP),
        "FD1P3IX" => conv_map(FD1P3IX_PIN_MAP),
        "FD1P3JX" => conv_map(FD1P3JX_PIN_MAP),
        "IB" => conv_map(IB_PIN_MAP),
        "OB" => conv_map(OB_PIN_MAP),
        "DCC" => auto_map(site, bel),
        "OSC_CORE" => auto_map(site, bel),
        "PDPSC16K_MODE" | "PDP16K_MODE" | "DP16K_MODE" => bram_map(cell_type, site, bel),
        _ => unimplemented!(),
    }
}

#[derive(Clone)]
pub struct PinMap {
    pub cell_type: String,
    pub bels: Vec<String>,
    pub pin_map: Vec<(String, String)>,
}

pub fn get_pin_maps(site: &Site) -> Vec<PinMap> {
    let mut map = Vec::new();
    let unique_bel_types : BTreeSet<String>
        = site.bels.iter().filter_map(|b| if b.bel_class == SiteBelClass::BEL { Some(b.bel_type.to_string()) } else { None }).collect();
    for bel_type in unique_bel_types.iter() {
        if let Some((_, cell_types)) = BEL_CELL_TYPES.iter().find(|(bt, _)| bt == bel_type) {
            for cell_type in cell_types.iter() {
                map.push(PinMap {
                    cell_type: cell_type.to_string(),
                    bels: site.bels.iter().filter_map(|b| if &b.bel_type == bel_type { Some(b.name.to_string()) } else { None }).collect(),
                    pin_map: get_map_for_cell_bel(cell_type, site, site.bels.iter().find(|b| &b.bel_type == bel_type).unwrap()),
                });
            }
        }
    }
    return map;
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) kwantam <kwantam@gmail.com>
// *     * 20150507 ~ added big_ routines to prevent overflow when num > 2^63
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::mem::swap;
use std::num::Wrapping;

pub fn gcd(mut a: u64, mut b: u64) -> u64 {
    while b > 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

pub(crate) trait Arithmetic: Copy + Sized {
    type I: Copy + Sized + Eq;

    fn new(m: u64) -> Self;
    fn modulus(&self) -> u64;
    fn from_u64(&self, n: u64) -> Self::I;
    fn to_u64(&self, n: Self::I) -> u64;
    fn add(&self, a: Self::I, b: Self::I) -> Self::I;
    fn mul(&self, a: Self::I, b: Self::I) -> Self::I;

    fn pow(&self, mut a: Self::I, mut b: u64) -> Self::I {
        let (_a, _b) = (a, b);
        let mut result = self.one();
        while b > 0 {
            if b & 1 != 0 {
                result = self.mul(result, a);
            }
            a = self.mul(a, a);
            b >>= 1;
        }

        // Check that r (reduced back to the usual representation) equals
        //  a^b % n, unless the latter computation overflows
        // Temporarily commented-out, as there u64::checked_pow is not available
        //  on the minimum supported Rust version, nor is an appropriate method
        //  for compiling the check conditionally.
        //debug_assert!(self
        //    .to_u64(_a)
        //    .checked_pow(_b as u32)
        //    .map(|r| r % self.modulus() == self.to_u64(result))
        //    .unwrap_or(true));

        result
    }

    fn one(&self) -> Self::I {
        self.from_u64(1)
    }
    fn minus_one(&self) -> Self::I {
        self.from_u64(self.modulus() - 1)
    }
    fn zero(&self) -> Self::I {
        self.from_u64(0)
    }
}

#[derive(Clone, Copy, Debug)]
pub(crate) struct Montgomery {
    a: u64,
    n: u64,
}

impl Montgomery {
    /// computes x/R mod n efficiently
    fn reduce(&self, x: u64) -> u64 {
        // TODO: optimiiiiiiise
        let Montgomery { a, n } = self;
        let t = x.wrapping_mul(*a);
        let nt = (*n as u128) * (t as u128);
        let y = ((x as u128 + nt) >> 64) as u64;
        if y >= *n {
            y - n
        } else {
            y
        }
    }
}

impl Arithmetic for Montgomery {
    // Montgomery transform, R=2⁶⁴
    // Provides fast arithmetic mod n (n odd, u64)
    type I = Wrapping<u64>;

    fn new(n: u64) -> Self {
        let a = inv_mod_u64(n).wrapping_neg();
        debug_assert_eq!(n.wrapping_mul(a), 1_u64.wrapping_neg());
        Montgomery { a, n }
    }

    fn modulus(&self) -> u64 {
        self.n
    }

    fn from_u64(&self, x: u64) -> Self::I {
        // TODO: optimise!
        assert!(x < self.n);
        let r = Wrapping((((x as u128) << 64) % self.n as u128) as u64);
        debug_assert_eq!(x, self.to_u64(r));
        r
    }

    fn to_u64(&self, n: Self::I) -> u64 {
        self.reduce(n.0)
    }

    fn add(&self, a: Self::I, b: Self::I) -> Self::I {
        let r = a + b;

        // Check that r (reduced back to the usual representation) equals
        // a+b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2 = (((a_r as u128) + (b_r as u128)) % (self.n as u128)) as u64;
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} + {} = [{}] + [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }

    fn mul(&self, a: Self::I, b: Self::I) -> Self::I {
        let r = Wrapping(self.reduce((a * b).0));

        // Check that r (reduced back to the usual representation) equals
        // a*b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2 = (((a_r as u128) * (b_r as u128)) % (self.n as u128)) as u64;
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} * {} = [{}] * [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }
}

// extended Euclid algorithm
// precondition: a is odd
pub(crate) fn inv_mod_u64(a: u64) -> u64 {
    assert!(a % 2 == 1);
    let mut t = 0u64;
    let mut newt = 1u64;
    let mut r = 0u64;
    let mut newr = a;

    while newr != 0 {
        let quot = if r == 0 {
            // special case when we're just starting out
            // This works because we know that
            // a does not divide 2^64, so floor(2^64 / a) == floor((2^64-1) / a);
            std::u64::MAX
        } else {
            r
        } / newr;

        let newtp = t.wrapping_sub(quot.wrapping_mul(newt));
        t = newt;
        newt = newtp;

        let newrp = r.wrapping_sub(quot.wrapping_mul(newr));
        r = newr;
        newr = newrp;
    }

    assert_eq!(r, 1);
    t
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_inverter() {
        // All odd integers from 1 to 20 000
        let mut test_values = (0..10_000u64).map(|i| 2 * i + 1);

        assert!(test_values.all(|x| x.wrapping_mul(inv_mod_u64(x)) == 1));
    }

    #[test]
    fn test_montgomery_add() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = Montgomery::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
                    assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_montgomery_mult() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = Montgomery::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_montgomery_roundtrip() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = Montgomery::new(n);
            for x in 0..n {
                let x_ = m.from_u64(x);
                assert_eq!(x, m.to_u64(x_));
            }
        }
    }
}
<commit_msg>factor::numeric: Simplify `Montgomery` (remove superfluous Wrapping)<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) kwantam <kwantam@gmail.com>
// *     * 20150507 ~ added big_ routines to prevent overflow when num > 2^63
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::mem::swap;

pub fn gcd(mut a: u64, mut b: u64) -> u64 {
    while b > 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

pub(crate) trait Arithmetic: Copy + Sized {
    type I: Copy + Sized + Eq;

    fn new(m: u64) -> Self;
    fn modulus(&self) -> u64;
    fn from_u64(&self, n: u64) -> Self::I;
    fn to_u64(&self, n: Self::I) -> u64;
    fn add(&self, a: Self::I, b: Self::I) -> Self::I;
    fn mul(&self, a: Self::I, b: Self::I) -> Self::I;

    fn pow(&self, mut a: Self::I, mut b: u64) -> Self::I {
        let (_a, _b) = (a, b);
        let mut result = self.one();
        while b > 0 {
            if b & 1 != 0 {
                result = self.mul(result, a);
            }
            a = self.mul(a, a);
            b >>= 1;
        }

        // Check that r (reduced back to the usual representation) equals
        //  a^b % n, unless the latter computation overflows
        // Temporarily commented-out, as there u64::checked_pow is not available
        //  on the minimum supported Rust version, nor is an appropriate method
        //  for compiling the check conditionally.
        //debug_assert!(self
        //    .to_u64(_a)
        //    .checked_pow(_b as u32)
        //    .map(|r| r % self.modulus() == self.to_u64(result))
        //    .unwrap_or(true));

        result
    }

    fn one(&self) -> Self::I {
        self.from_u64(1)
    }
    fn minus_one(&self) -> Self::I {
        self.from_u64(self.modulus() - 1)
    }
    fn zero(&self) -> Self::I {
        self.from_u64(0)
    }
}

#[derive(Clone, Copy, Debug)]
pub(crate) struct Montgomery {
    a: u64,
    n: u64,
}

impl Montgomery {
    /// computes x/R mod n efficiently
    fn reduce(&self, x: u64) -> u64 {
        // TODO: optimiiiiiiise
        let Montgomery { a, n } = self;
        let t = x.wrapping_mul(*a);
        let nt = (*n as u128) * (t as u128);
        let y = ((x as u128 + nt) >> 64) as u64;
        if y >= *n {
            y - n
        } else {
            y
        }
    }
}

impl Arithmetic for Montgomery {
    // Montgomery transform, R=2⁶⁴
    // Provides fast arithmetic mod n (n odd, u64)
    type I = u64;

    fn new(n: u64) -> Self {
        let a = inv_mod_u64(n).wrapping_neg();
        debug_assert_eq!(n.wrapping_mul(a), 1_u64.wrapping_neg());
        Montgomery { a, n }
    }

    fn modulus(&self) -> u64 {
        self.n
    }

    fn from_u64(&self, x: u64) -> Self::I {
        // TODO: optimise!
        assert!(x < self.n);
        let r = (((x as u128) << 64) % self.n as u128) as u64;
        debug_assert_eq!(x, self.to_u64(r));
        r
    }

    fn to_u64(&self, n: Self::I) -> u64 {
        self.reduce(n)
    }

    fn add(&self, a: Self::I, b: Self::I) -> Self::I {
        let r = a + b;

        // Check that r (reduced back to the usual representation) equals
        // a+b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2 = (((a_r as u128) + (b_r as u128)) % (self.n as u128)) as u64;
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} + {} = [{}] + [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }

    fn mul(&self, a: Self::I, b: Self::I) -> Self::I {
        let r = self.reduce(a.wrapping_mul(b));

        // Check that r (reduced back to the usual representation) equals
        // a*b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2 = (((a_r as u128) * (b_r as u128)) % (self.n as u128)) as u64;
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} * {} = [{}] * [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }
}

// extended Euclid algorithm
// precondition: a is odd
pub(crate) fn inv_mod_u64(a: u64) -> u64 {
    assert!(a % 2 == 1);
    let mut t = 0u64;
    let mut newt = 1u64;
    let mut r = 0u64;
    let mut newr = a;

    while newr != 0 {
        let quot = if r == 0 {
            // special case when we're just starting out
            // This works because we know that
            // a does not divide 2^64, so floor(2^64 / a) == floor((2^64-1) / a);
            std::u64::MAX
        } else {
            r
        } / newr;

        let newtp = t.wrapping_sub(quot.wrapping_mul(newt));
        t = newt;
        newt = newtp;

        let newrp = r.wrapping_sub(quot.wrapping_mul(newr));
        r = newr;
        newr = newrp;
    }

    assert_eq!(r, 1);
    t
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_inverter() {
        // All odd integers from 1 to 20 000
        let mut test_values = (0..10_000u64).map(|i| 2 * i + 1);

        assert!(test_values.all(|x| x.wrapping_mul(inv_mod_u64(x)) == 1));
    }

    #[test]
    fn test_montgomery_add() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = Montgomery::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
                    assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_montgomery_mult() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = Montgomery::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_montgomery_roundtrip() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = Montgomery::new(n);
            for x in 0..n {
                let x_ = m.from_u64(x);
                assert_eq!(x, m.to_u64(x_));
            }
        }
    }
}
<|endoftext|>


<commit_before>use num_cpus;
use std::slice::{Chunks, ChunksMut};
use num::traits::Float;
use simple_parallel::Pool;
use std::ops::Range;
use std::sync::Mutex;
use std::mem;
use super::RealNumber;

/// Indicates how complex an operation is and determines how many cores
/// will be used since operations with smaller complexity are memory bus bound
/// and not CPU bound
#[derive(Copy)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum Complexity {
	Small,
    Medium,
    Large
}

/// Hold parameters which specifiy how multiple cores are used
/// to execute an operation.
#[derive(Debug)]
pub struct MultiCoreSettings {
    #[allow(dead_code)]
    core_limit: usize
    // TODO: Specify and use options such as core/thread limits
}

impl MultiCoreSettings {
    pub fn new() -> MultiCoreSettings {
        // Initialize the pool
        let _pool = Chunk::get_static_pool();
        MultiCoreSettings {
            core_limit: num_cpus::get()
        }
    }
}

impl Clone for MultiCoreSettings {
    fn clone(&self) -> Self {
        MultiCoreSettings {
            core_limit: self.core_limit
        }
    }

    fn clone_from(&mut self, source: &Self) {
        self.core_limit = source.core_limit;
    }
}

/// Contains logic which helps to perform an operation
/// in parallel by dividing an array into chunks.
pub struct Chunk;
#[allow(dead_code)]
impl Chunk
{
    /// Gives access to the thread pool singleton
	fn get_static_pool() -> &'static mut Pool
	{
		use std::mem::transmute;
		use std::sync::{Once, ONCE_INIT};
		unsafe
		{
			static mut pool: *mut Pool = 0 as *mut Pool;
			static mut ONCE: Once = ONCE_INIT;
			ONCE.call_once(||
			{
				pool = transmute::<Box<Pool>, *mut Pool>(Box::new(Pool::new(num_cpus::get())));
			});

			let mut static_pool = &mut *pool;
			static_pool
		}
	}

    /// Figures out how many threads make use for the an operation with the given complexity on
    /// an array with the given size.
    ///
    /// This method tries to balance the expected performance gain vs. CPU utilization since there is in most cases
    /// no point to keep all CPU cores busy only to get 5 to 10% performance gain.
    /// The expected performance gain is roughly estimated based on three factors:
    /// 1. More cores improves the calculation speed according to Amdahl's law (`https://en.wikipedia.org/wiki/Amdahl's_law`)
    /// 2. Spawning a thread consumes time and so the array length must be large enough to so that the expected performance
    ///    gain justifies the effort to spawn a thread/invoke the thread pool.
    /// 3. The CPU is not the only resource and if one of the other resources is a bottleneck then Amdahl's law won't be applicable.
    ///    The memory bus speed is limited (20GB/s in case of a typical 2015 consumer laptop in the price range of $1000) and
    ///    for operations which only require a few CPU cycles already one or two cores will process data faster than the
    ///    memory bus is able to provide and to transport back. Using more cores then only creates heat but no performance benefit.
	#[inline]
	fn determine_number_of_chunks(array_length: usize, complexity: Complexity) -> usize
	{
        let cores = num_cpus::get();
        if complexity == Complexity::Large || cores == 1 {
            cores
        }
        else if complexity == Complexity::Small  {
            if array_length < 500000 {
                1
            }
            else {
                2
            }
        }
        else { // complexity == medium
            if array_length < 10000 {
                1
            }
            else if array_length < 50000 {
                2
            }
            else {
                cores
            }
        }
	}

    /// Partitions an array into the given number of chunks. It makes sure that all chunks have the same size
    /// and so it will happen that some elements at the end of the array are not part of any chunk.
	#[inline]
	fn partition<T>(array: &[T], array_length: usize, step_size: usize, number_of_chunks: usize) -> Chunks<T>
		where T : Float + Copy + Clone + Send
	{
		let chunk_size = Chunk::calc_chunk_size(array_length, step_size, number_of_chunks);
		array[0 .. array_length].chunks(chunk_size)
	}

    /// Partitions an array into the given number of chunks. It makes sure that all chunks have the same size
    /// and so it will happen that some elements at the end of the array are not part of any chunk.
	#[inline]
	fn partition_mut<T>(array: &mut [T], array_length: usize, step_size: usize, number_of_chunks: usize) -> ChunksMut<T>
		where T : Float + Copy + Clone + Send
	{
		let chunk_size = Chunk::calc_chunk_size(array_length, step_size, number_of_chunks);
		array[0 .. array_length].chunks_mut(chunk_size)
	}

	#[inline]
	fn calc_chunk_size(array_length: usize, step_size: usize, number_of_chunks: usize) -> usize
	{
		let mut chunk_size = (array_length as f64/ number_of_chunks as f64).ceil() as usize;
		let remainder = chunk_size % step_size;
		if remainder > 0
		{
			chunk_size += step_size - chunk_size % step_size;
		}

		chunk_size
	}

    /// This function returns the ranges which correspond to the chunks generated by `partition_in_number`.
	#[inline]
	fn partition_in_ranges(array_length: usize, step_size: usize, number_of_chunks: usize) -> Vec<Range<usize>>
	{
		let chunk_size = Chunk::calc_chunk_size(array_length, step_size, number_of_chunks);
		let mut ranges = Vec::with_capacity(number_of_chunks);
		let mut sum = 0;
		for i in 0..number_of_chunks {
			let new_sum = if i < number_of_chunks - 1 { sum + chunk_size } else { array_length };
			ranges.push(Range { start: sum, end: new_sum - 1 });
			sum = new_sum;
		}

		ranges
	}

    /// Executes the given function on the all elements of the array in parallel.
	#[inline]
	pub fn execute<F, T>(complexity: Complexity, array: &mut [T], step_size: usize, function: F)
		where F: Fn(&mut [T]) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync
	{
		let array_length = array.len();
		Chunk::execute_partial(complexity, array, array_length, step_size, function);
	}

    /// Executes the given function on the first `array_length` elements of the given array in parallel.
	#[inline]
	pub fn execute_partial<F, T>(complexity: Complexity, array: &mut [T], array_length: usize, step_size: usize, function: F)
		where F: Fn(&mut [T]) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync
	{
        let number_of_chunks = Chunk::determine_number_of_chunks(array_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(array, array_length, step_size, number_of_chunks);
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks, |chunk|
				{
					function(chunk);
				});
		}
		else
		{
			function(&mut array[0..array_length]);
		}
	}

    /// Executes the given function on the first `array_length` elements of the given array in parallel and passes
    /// the argument to all function calls.
	#[inline]
	pub fn execute_partial_with_arguments<T,S,F>(
            complexity: Complexity,
            array: &mut [T], array_length: usize, step_size: usize,
            arguments:S, function: F)
		where F: Fn(&mut [T], S) + 'static + Sync,
			  T: RealNumber,
			  S: Sync + Copy
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(array_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(array, array_length, step_size, number_of_chunks);
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks, |chunk|
				{
					function(chunk, arguments);
				});
		}
		else
		{
			function(&mut array[0..array_length], arguments);
		}
	}

    /// Executes the given function on the all elements of the array in parallel. Results are intended to be stored in the target array.
	#[inline]
	pub fn execute_original_to_target<F, T>(
            complexity: Complexity,
            original: &[T], original_length: usize, original_step: usize,
            target: &mut [T], target_length: usize, target_step: usize,
            function: F)
		where F: Fn(&[T], Range<usize>, &mut [T]) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(original_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(target, target_length, target_step, number_of_chunks);
			let ranges = Chunk::partition_in_ranges(original_length, original_step, chunks.len());
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks.zip(ranges), |chunk|
				{
					function(original, chunk.1, chunk.0);
				});
		}
		else
		{
			function(original, Range { start: 0, end: original_length }, &mut target[0..target_length]);
		}
	}

    /// Executes the given function on the all elements of the array in parallel. A result is
    /// returned for each chunk.
	#[inline]
	pub fn get_a_fold_b<F, T, R>(
            complexity: Complexity,
            a: &[T], a_len: usize, a_step: usize,
            b: &[T], b_len: usize, b_step: usize,
            function: F) -> Vec<R>
		where F: Fn(&[T], Range<usize>, &[T]) -> R + 'static + Sync,
			  T: Float + Copy + Clone + Send + Sync,
              R: Send
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(a_len, complexity);
		if number_of_chunks > 10
		{
			let chunks = Chunk::partition(b, b_len, b_step, number_of_chunks);
			let ranges = Chunk::partition_in_ranges(a_len, a_step, chunks.len());
			let ref mut pool = Chunk::get_static_pool();
            let result = Vec::with_capacity(chunks.len());
            let stack_array = Mutex::new(result);
            pool.for_(chunks.zip(ranges), |chunk|
                {
                    let r = function(a, chunk.1, chunk.0);
                    stack_array.lock().unwrap().push(r);
                });
            let mut guard = stack_array.lock().unwrap();
            mem::replace(&mut guard, Vec::new())
		}
		else
		{
			let result = function(a, Range { start: 0, end: a_len }, &b[0..b_len]);
            vec![result]
		}
	}

    /// Executes the given function on the all elements of the array in parallel and passes
    /// the argument to all function calls.. Results are intended to be stored in the target array.
	#[inline]
	pub fn execute_original_to_target_with_arguments<T,S,F>(
            complexity: Complexity,
            original: &[T], original_length: usize, original_step: usize,
            target: &mut [T], target_length: usize, target_step: usize,
            arguments: S, function: F)
		where F: Fn(&[T], Range<usize>, &mut [T], S) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync,
			  S: Sync + Copy
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(original_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(target, target_length, target_step, number_of_chunks);
			let ranges = Chunk::partition_in_ranges(original_length, original_step, chunks.len());
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks.zip(ranges), |chunk|
				{
					function(original, chunk.1, chunk.0, arguments);
				});
		}
		else
		{
			function(original, Range { start: 0, end: original_length }, &mut target[0..target_length], arguments);
		}
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use std::ops::Range;

	#[test]
	fn partition_array()
	{
		let mut array = [0.0; 256];
		let chunks = Chunk::partition_mut(&mut array, 256, 4, 2);
		assert_eq!(chunks.len(), 2);
		for chunk in chunks
		{
			assert_eq!(chunk.len(), 128);
		}
	}

	#[test]
	fn partition_array_8_cores()
	{
		let mut array = [0.0; 1023];
		let chunks = Chunk::partition_mut(&mut array, 1023, 4, 8);
		assert_eq!(chunks.len(), 8);
		let mut i = 0;
		for chunk in chunks
		{
			let expected = if i >= 7 { 127 } else { 128 };
			assert_eq!(chunk.len(), expected);
			i += 1;
		}
	}

	#[test]
	fn partitionin_ranges()
	{
		let ranges = Chunk::partition_in_ranges(1023, 4, 2);
		assert_eq!(ranges.len(), 2);
		assert_eq!(ranges[0], Range { start: 0, end: 511 });
		assert_eq!(ranges[1], Range { start: 512, end: 1022 });
	}
}<commit_msg>Changed pool initialization slightly<commit_after>use num_cpus;
use std::slice::{Chunks, ChunksMut};
use num::traits::Float;
use simple_parallel::Pool;
use std::ops::Range;
use std::sync::Mutex;
use std::mem;
use super::RealNumber;

/// Indicates how complex an operation is and determines how many cores
/// will be used since operations with smaller complexity are memory bus bound
/// and not CPU bound
#[derive(Copy)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum Complexity {
	Small,
    Medium,
    Large
}

/// Hold parameters which specifiy how multiple cores are used
/// to execute an operation.
#[derive(Debug)]
pub struct MultiCoreSettings {
    #[allow(dead_code)]
    core_limit: usize
    // TODO: Specify and use options such as core/thread limits
}

impl MultiCoreSettings {
    pub fn new() -> MultiCoreSettings {
        // Initialize the pool
        Chunk::init_static_pool();
        MultiCoreSettings {
            core_limit: num_cpus::get()
        }
    }
}

impl Clone for MultiCoreSettings {
    fn clone(&self) -> Self {
        MultiCoreSettings {
            core_limit: self.core_limit
        }
    }

    fn clone_from(&mut self, source: &Self) {
        self.core_limit = source.core_limit;
    }
}

static mut POOL: *mut Pool = 0 as *mut Pool;

/// Contains logic which helps to perform an operation
/// in parallel by dividing an array into chunks.
pub struct Chunk;
#[allow(dead_code)]
impl Chunk
{
    fn init_static_pool() {
        use std::mem::transmute;
		use std::sync::{Once, ONCE_INIT};
		unsafe
		{
			static mut ONCE: Once = ONCE_INIT;
			ONCE.call_once(||
			{
				POOL = transmute::<Box<Pool>, *mut Pool>(Box::new(Pool::new(num_cpus::get())));
			});
		}
    }

    /// Gives access to the thread pool singleton
	fn get_static_pool() -> &'static mut Pool
	{
		unsafe
		{
			let mut static_pool = &mut *POOL;
			static_pool
		}
	}

    /// Figures out how many threads make use for the an operation with the given complexity on
    /// an array with the given size.
    ///
    /// This method tries to balance the expected performance gain vs. CPU utilization since there is in most cases
    /// no point to keep all CPU cores busy only to get 5 to 10% performance gain.
    /// The expected performance gain is roughly estimated based on three factors:
    /// 1. More cores improves the calculation speed according to Amdahl's law (`https://en.wikipedia.org/wiki/Amdahl's_law`)
    /// 2. Spawning a thread consumes time and so the array length must be large enough to so that the expected performance
    ///    gain justifies the effort to spawn a thread/invoke the thread pool.
    /// 3. The CPU is not the only resource and if one of the other resources is a bottleneck then Amdahl's law won't be applicable.
    ///    The memory bus speed is limited (20GB/s in case of a typical 2015 consumer laptop in the price range of $1000) and
    ///    for operations which only require a few CPU cycles already one or two cores will process data faster than the
    ///    memory bus is able to provide and to transport back. Using more cores then only creates heat but no performance benefit.
	#[inline]
	fn determine_number_of_chunks(array_length: usize, complexity: Complexity) -> usize
	{
        let cores = num_cpus::get();
        if complexity == Complexity::Large || cores == 1 {
            cores
        }
        else if complexity == Complexity::Small  {
            if array_length < 500000 {
                1
            }
            else {
                2
            }
        }
        else { // complexity == medium
            if array_length < 10000 {
                1
            }
            else if array_length < 50000 {
                2
            }
            else {
                cores
            }
        }
	}

    /// Partitions an array into the given number of chunks. It makes sure that all chunks have the same size
    /// and so it will happen that some elements at the end of the array are not part of any chunk.
	#[inline]
	fn partition<T>(array: &[T], array_length: usize, step_size: usize, number_of_chunks: usize) -> Chunks<T>
		where T : Float + Copy + Clone + Send
	{
		let chunk_size = Chunk::calc_chunk_size(array_length, step_size, number_of_chunks);
		array[0 .. array_length].chunks(chunk_size)
	}

    /// Partitions an array into the given number of chunks. It makes sure that all chunks have the same size
    /// and so it will happen that some elements at the end of the array are not part of any chunk.
	#[inline]
	fn partition_mut<T>(array: &mut [T], array_length: usize, step_size: usize, number_of_chunks: usize) -> ChunksMut<T>
		where T : Float + Copy + Clone + Send
	{
		let chunk_size = Chunk::calc_chunk_size(array_length, step_size, number_of_chunks);
		array[0 .. array_length].chunks_mut(chunk_size)
	}

	#[inline]
	fn calc_chunk_size(array_length: usize, step_size: usize, number_of_chunks: usize) -> usize
	{
		let mut chunk_size = (array_length as f64/ number_of_chunks as f64).ceil() as usize;
		let remainder = chunk_size % step_size;
		if remainder > 0
		{
			chunk_size += step_size - chunk_size % step_size;
		}

		chunk_size
	}

    /// This function returns the ranges which correspond to the chunks generated by `partition_in_number`.
	#[inline]
	fn partition_in_ranges(array_length: usize, step_size: usize, number_of_chunks: usize) -> Vec<Range<usize>>
	{
		let chunk_size = Chunk::calc_chunk_size(array_length, step_size, number_of_chunks);
		let mut ranges = Vec::with_capacity(number_of_chunks);
		let mut sum = 0;
		for i in 0..number_of_chunks {
			let new_sum = if i < number_of_chunks - 1 { sum + chunk_size } else { array_length };
			ranges.push(Range { start: sum, end: new_sum - 1 });
			sum = new_sum;
		}

		ranges
	}

    /// Executes the given function on the all elements of the array in parallel.
	#[inline]
	pub fn execute<F, T>(complexity: Complexity, array: &mut [T], step_size: usize, function: F)
		where F: Fn(&mut [T]) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync
	{
		let array_length = array.len();
		Chunk::execute_partial(complexity, array, array_length, step_size, function);
	}

    /// Executes the given function on the first `array_length` elements of the given array in parallel.
	#[inline]
	pub fn execute_partial<F, T>(complexity: Complexity, array: &mut [T], array_length: usize, step_size: usize, function: F)
		where F: Fn(&mut [T]) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync
	{
        let number_of_chunks = Chunk::determine_number_of_chunks(array_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(array, array_length, step_size, number_of_chunks);
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks, |chunk|
				{
					function(chunk);
				});
		}
		else
		{
			function(&mut array[0..array_length]);
		}
	}

    /// Executes the given function on the first `array_length` elements of the given array in parallel and passes
    /// the argument to all function calls.
	#[inline]
	pub fn execute_partial_with_arguments<T,S,F>(
            complexity: Complexity,
            array: &mut [T], array_length: usize, step_size: usize,
            arguments:S, function: F)
		where F: Fn(&mut [T], S) + 'static + Sync,
			  T: RealNumber,
			  S: Sync + Copy
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(array_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(array, array_length, step_size, number_of_chunks);
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks, |chunk|
				{
					function(chunk, arguments);
				});
		}
		else
		{
			function(&mut array[0..array_length], arguments);
		}
	}

    /// Executes the given function on the all elements of the array in parallel. Results are intended to be stored in the target array.
	#[inline]
	pub fn execute_original_to_target<F, T>(
            complexity: Complexity,
            original: &[T], original_length: usize, original_step: usize,
            target: &mut [T], target_length: usize, target_step: usize,
            function: F)
		where F: Fn(&[T], Range<usize>, &mut [T]) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(original_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(target, target_length, target_step, number_of_chunks);
			let ranges = Chunk::partition_in_ranges(original_length, original_step, chunks.len());
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks.zip(ranges), |chunk|
				{
					function(original, chunk.1, chunk.0);
				});
		}
		else
		{
			function(original, Range { start: 0, end: original_length }, &mut target[0..target_length]);
		}
	}

    /// Executes the given function on the all elements of the array in parallel. A result is
    /// returned for each chunk.
	#[inline]
	pub fn get_a_fold_b<F, T, R>(
            complexity: Complexity,
            a: &[T], a_len: usize, a_step: usize,
            b: &[T], b_len: usize, b_step: usize,
            function: F) -> Vec<R>
		where F: Fn(&[T], Range<usize>, &[T]) -> R + 'static + Sync,
			  T: Float + Copy + Clone + Send + Sync,
              R: Send
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(a_len, complexity);
		if number_of_chunks > 10
		{
			let chunks = Chunk::partition(b, b_len, b_step, number_of_chunks);
			let ranges = Chunk::partition_in_ranges(a_len, a_step, chunks.len());
			let ref mut pool = Chunk::get_static_pool();
            let result = Vec::with_capacity(chunks.len());
            let stack_array = Mutex::new(result);
            pool.for_(chunks.zip(ranges), |chunk|
                {
                    let r = function(a, chunk.1, chunk.0);
                    stack_array.lock().unwrap().push(r);
                });
            let mut guard = stack_array.lock().unwrap();
            mem::replace(&mut guard, Vec::new())
		}
		else
		{
			let result = function(a, Range { start: 0, end: a_len }, &b[0..b_len]);
            vec![result]
		}
	}

    /// Executes the given function on the all elements of the array in parallel and passes
    /// the argument to all function calls.. Results are intended to be stored in the target array.
	#[inline]
	pub fn execute_original_to_target_with_arguments<T,S,F>(
            complexity: Complexity,
            original: &[T], original_length: usize, original_step: usize,
            target: &mut [T], target_length: usize, target_step: usize,
            arguments: S, function: F)
		where F: Fn(&[T], Range<usize>, &mut [T], S) + 'static + Sync,
			  T : Float + Copy + Clone + Send + Sync,
			  S: Sync + Copy
	{
		let number_of_chunks = Chunk::determine_number_of_chunks(original_length, complexity);
		if number_of_chunks > 1
		{
			let chunks = Chunk::partition_mut(target, target_length, target_step, number_of_chunks);
			let ranges = Chunk::partition_in_ranges(original_length, original_step, chunks.len());
			let ref mut pool = Chunk::get_static_pool();
			pool.for_(chunks.zip(ranges), |chunk|
				{
					function(original, chunk.1, chunk.0, arguments);
				});
		}
		else
		{
			function(original, Range { start: 0, end: original_length }, &mut target[0..target_length], arguments);
		}
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use std::ops::Range;

	#[test]
	fn partition_array()
	{
		let mut array = [0.0; 256];
		let chunks = Chunk::partition_mut(&mut array, 256, 4, 2);
		assert_eq!(chunks.len(), 2);
		for chunk in chunks
		{
			assert_eq!(chunk.len(), 128);
		}
	}

	#[test]
	fn partition_array_8_cores()
	{
		let mut array = [0.0; 1023];
		let chunks = Chunk::partition_mut(&mut array, 1023, 4, 8);
		assert_eq!(chunks.len(), 8);
		let mut i = 0;
		for chunk in chunks
		{
			let expected = if i >= 7 { 127 } else { 128 };
			assert_eq!(chunk.len(), expected);
			i += 1;
		}
	}

	#[test]
	fn partitionin_ranges()
	{
		let ranges = Chunk::partition_in_ranges(1023, 4, 2);
		assert_eq!(ranges.len(), 2);
		assert_eq!(ranges[0], Range { start: 0, end: 511 });
		assert_eq!(ranges[1], Range { start: 512, end: 1022 });
	}
}<|endoftext|>


<commit_before>use std::collections::{HashMap, hash_map};
use tensor::Tensor;
use autograd::Variable;
use std::vec::IntoIter;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use nn;

pub type Parameters<T> = Box<Iterator<Item = ModRefMut<'static, nn::Parameter<T>>>>;

pub trait ModuleStruct {
    fn init_module(self) -> Self;
}
pub struct ModRefMut<'a, T: 'a + ?Sized> {
    value: *mut T,
    phantom: PhantomData<&'a T>,
}

impl<'a, T> ModRefMut<'a, T> {
    pub fn new(value: *mut T) -> Self {
        ModRefMut {
            value: value,
            phantom: PhantomData,
        }
    }
}

impl<'a, T> From<&'a mut T> for ModRefMut<'a, T> {
    fn from(value: &mut T) -> Self {
        ModRefMut::new(value as *mut T)
    }
}
impl<'a, T> From<*mut T> for ModRefMut<'a, T> {
    fn from(value: *mut T) -> Self {
        ModRefMut::new(value)
    }
}

impl<'a, T> Deref for ModRefMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.value as &T }
    }
}
impl<'a, T> DerefMut for ModRefMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.value as &mut T }
    }
}

pub struct Module<T: Copy> {
    pub _name: String,
    pub training: bool,
    //_backend: TorchBackend,
    //	_backward_hooks:
    //	_forward_hooks:
    _buffers: HashMap<String, Tensor<T>>,
    _params: HashMap<String, *mut nn::Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

pub struct ParamIter<'a, T: Copy + 'a> {
    pub modules: Vec<*mut Module<T>>,
    pub mod_iter: IntoIter<*mut Module<T>>,
    pub iter: Box<Iterator<Item = *mut nn::Parameter<T>>>,
    phantom: PhantomData<&'a T>,
}
fn mod_accum<T: Copy>(module: &mut Module<T>, arg: &mut Vec<*mut Module<T>>) {
    arg.push((module));
}
impl<'a, T: 'static + Copy> ParamIter<'a, T> {
    pub fn new(root: &mut Module<T>) -> Self {
        let mut mods = Vec::new();
        root.apply_arg(&mut mods, mod_accum);
        let mut module = unsafe { &mut *mods[0] as &mut Module<T> };
        ParamIter {
            modules: mods.clone(),
            mod_iter: mods.into_iter(),
            iter: Box::new(module._params.iter_mut().map(|(_, d)| *d)),
            phantom: PhantomData,
        }
    }
}

impl<'a, T: Copy + 'static> Iterator for ParamIter<'a, T> {
    type Item = ModRefMut<'a, nn::Parameter<T>>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(t) = self.iter.next() {
            Some(ModRefMut::new(t))
        } else if let Some(modulep) = self.mod_iter.next() {
            let mut module = unsafe { &mut *modulep as &mut Module<T> };
            self.iter = Box::new(module._params.iter_mut().map(|(_, d)| *d));
            self.next()
        } else {
            None
        }
    }
}

impl<'a, T: Copy + 'static> Clone for Box<ParamIter<'a, T>> {
    fn clone(&self) -> Self {
        let mut new_mod_list = self.modules.clone();
        let param_iter = Box::new(unsafe { &mut *new_mod_list[0] }
                                      ._params
                                      .iter_mut()
                                      .map(|(_, d)| *d));
        Box::new(ParamIter {
                     modules: new_mod_list,
                     mod_iter: self.modules.clone().into_iter(),
                     iter: param_iter,
                     phantom: PhantomData,
                 })
    }
}

impl<T: Copy> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut nn::Parameter<T>) {
        self._params.insert(name.into(), param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<nn::Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    pub fn parameters(&mut self) -> Parameters<T> {
        Box::new(ParamIter::new(self))
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    pub fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    fn apply_arg<Ta>(&mut self, arg: &mut Ta, callback: fn(&mut Self, &mut Ta)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply_arg(arg, callback)
        }
        callback(self, arg)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }
    }
}

pub trait ModDelegate<T: Copy> {
    fn delegate(&mut self) -> &mut Module<T>;
}

pub trait ModIntf<T: Copy>: ModDelegate<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
    fn parameters(&mut self) -> Box<Iterator<Item = ModRefMut<'static, nn::Parameter<T>>>> {
        self.delegate().parameters()
    }
}

pub trait ModIntfV<T: Copy>: ModDelegate<T> {
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<commit_msg>do apply on grad variables<commit_after>use std::collections::{HashMap, hash_map};
use tensor::Tensor;
use autograd::Variable;
use std::vec::IntoIter;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use nn;

pub type Parameters<T> = Box<Iterator<Item = ModRefMut<'static, nn::Parameter<T>>>>;

pub trait ModuleStruct {
    fn init_module(self) -> Self;
}
pub struct ModRefMut<'a, T: 'a + ?Sized> {
    value: *mut T,
    phantom: PhantomData<&'a T>,
}

impl<'a, T> ModRefMut<'a, T> {
    pub fn new(value: *mut T) -> Self {
        ModRefMut {
            value: value,
            phantom: PhantomData,
        }
    }
}

impl<'a, T> From<&'a mut T> for ModRefMut<'a, T> {
    fn from(value: &mut T) -> Self {
        ModRefMut::new(value as *mut T)
    }
}
impl<'a, T> From<*mut T> for ModRefMut<'a, T> {
    fn from(value: *mut T) -> Self {
        ModRefMut::new(value)
    }
}

impl<'a, T> Deref for ModRefMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.value as &T }
    }
}
impl<'a, T> DerefMut for ModRefMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.value as &mut T }
    }
}

pub struct Module<T: Copy> {
    pub _name: String,
    pub training: bool,
    //_backend: TorchBackend,
    //	_backward_hooks:
    //	_forward_hooks:
    _buffers: HashMap<String, Tensor<T>>,
    _params: HashMap<String, *mut nn::Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

pub struct ParamIter<'a, T: Copy + 'a> {
    pub modules: Vec<*mut Module<T>>,
    pub mod_iter: IntoIter<*mut Module<T>>,
    pub iter: Box<Iterator<Item = *mut nn::Parameter<T>>>,
    phantom: PhantomData<&'a T>,
}
fn mod_accum<T: Copy>(module: &mut Module<T>, arg: &mut Vec<*mut Module<T>>) {
    arg.push((module));
}
impl<'a, T: 'static + Copy> ParamIter<'a, T> {
    pub fn new(root: &mut Module<T>) -> Self {
        let mut mods = Vec::new();
        root.apply_arg(&mut mods, mod_accum);
        let mut module = unsafe { &mut *mods[0] as &mut Module<T> };
        ParamIter {
            modules: mods.clone(),
            mod_iter: mods.into_iter(),
            iter: Box::new(module._params.iter_mut().map(|(_, d)| *d)),
            phantom: PhantomData,
        }
    }
}

impl<'a, T: Copy + 'static> Iterator for ParamIter<'a, T> {
    type Item = ModRefMut<'a, nn::Parameter<T>>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(t) = self.iter.next() {
            Some(ModRefMut::new(t))
        } else if let Some(modulep) = self.mod_iter.next() {
            let mut module = unsafe { &mut *modulep as &mut Module<T> };
            self.iter = Box::new(module._params.iter_mut().map(|(_, d)| *d));
            self.next()
        } else {
            None
        }
    }
}

impl<'a, T: Copy + 'static> Clone for Box<ParamIter<'a, T>> {
    fn clone(&self) -> Self {
        let mut new_mod_list = self.modules.clone();
        let param_iter = Box::new(unsafe { &mut *new_mod_list[0] }
                                      ._params
                                      .iter_mut()
                                      .map(|(_, d)| *d));
        Box::new(ParamIter {
                     modules: new_mod_list,
                     mod_iter: self.modules.clone().into_iter(),
                     iter: param_iter,
                     phantom: PhantomData,
                 })
    }
}

impl<T: Copy> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut nn::Parameter<T>) {
        self._params.insert(name.into(), param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<nn::Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    pub fn parameters(&mut self) -> Parameters<T> {
        Box::new(ParamIter::new(self))
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback);
            if let &mut Some(ref mut g) = param.v.grad() {
                g.apply(callback)
            }
            /* see also _buffers */
        }
    }
    pub fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    fn apply_arg<Ta>(&mut self, arg: &mut Ta, callback: fn(&mut Self, &mut Ta)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply_arg(arg, callback)
        }
        callback(self, arg)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }
    }
}

pub trait ModDelegate<T: Copy> {
    fn delegate(&mut self) -> &mut Module<T>;
}

pub trait ModIntf<T: Copy>: ModDelegate<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
    fn parameters(&mut self) -> Box<Iterator<Item = ModRefMut<'static, nn::Parameter<T>>>> {
        self.delegate().parameters()
    }
}

pub trait ModIntfV<T: Copy>: ModDelegate<T> {
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<|endoftext|>