<commit_before>/**
 * At the moment, this is a partial hashmap implementation, not yet fit for
 * use, but useful as a stress test for rustboot.
 */

import std._int;
import std.sys;
import std.util;
import std._vec;

type hashfn[K] = fn(&K) -> uint;
type eqfn[K] = fn(&K, &K) -> bool;

type hashmap[K, V] = obj {
  fn insert(&K key, &V val) -> bool;
  fn contains_key(&K key) -> bool;
  fn get(&K key) -> V;
  fn find(&K key) -> util.option[V];
  fn remove(&K key) -> util.option[V];
  fn rehash();
};

fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {

  let uint initial_capacity = 32u; // 2^5
  let util.rational load_factor = rec(num=3, den=4);

  type bucket[K, V] = tag(nil(), deleted(), some(K, V));

  fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
    ret _vec.init_elt[mutable bucket[K, V]](nil[K, V](), nbkts);
  }

  // Derive two hash functions from the one given by taking the upper
  // half and lower half of the uint bits.  Our bucket probing
  // sequence is then defined by
  //
  //   hash(key, i) := hashl(key) + i * hashr(key)   for i = 0, 1, 2, ...
  //
  // Tearing the hash function apart this way is kosher in practice
  // as, assuming 32-bit uints, the table would have to be at 2^32
  // buckets before the resulting pair of hash functions no longer
  // probes all buckets for a fixed key.  Note that hashr is made to
  // output odd numbers (hence coprime to the number of nbkts, which
  // is always a power of 2), so that all buckets are probed for a
  // fixed key.

  fn hashl[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
    ret (hasher(key) >>> (sys.rustrt.size_of[uint]() * 8u / 2u));
  }

  fn hashr[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
    ret ((((~ 0u) >>> (sys.rustrt.size_of[uint]() * 8u / 2u))
          & hasher(key)) * 2u + 1u);
  }

  fn hash[K](&hashfn[K] hasher, uint nbkts, &K key, uint i) -> uint {
    ret (hashl[K](hasher, nbkts, key)
         + i * hashr[K](hasher, nbkts, key)) % nbkts;
  }

  /**
   * We attempt to never call this with a full table.  If we do, it
   * will fail.
   */
  fn insert_common[K, V](&hashfn[K] hasher,
                         &eqfn[K] eqer,
                         vec[mutable bucket[K, V]] bkts,
                         uint nbkts,
                         &K key,
                         &V val)
    -> bool
  {
    let uint i = 0u;
    while (i < nbkts) {
      let uint j = (hash[K](hasher, nbkts, key, i));
      alt (bkts.(j)) {
        case (some[K, V](k, _)) {
          if (eqer(key, k)) {
            bkts.(j) = some[K, V](k, val);
            ret false;
          }
          i += 1u;
        }
        case (_) {
          bkts.(j) = some[K, V](key, val);
          ret true;
        }
      }
    }
    fail; // full table
  }

  fn find_common[K, V](&hashfn[K] hasher,
                       &eqfn[K] eqer,
                       vec[mutable bucket[K, V]] bkts,
                       uint nbkts,
                       &K key)
    -> util.option[V]
  {
    let uint i = 0u;
    while (i < nbkts) {
      let uint j = (hash[K](hasher, nbkts, key, i));
      alt (bkts.(j)) {
        case (some[K, V](k, v)) {
          if (eqer(key, k)) {
            ret util.some[V](v);
          }
        }
        case (nil[K, V]()) {
          ret util.none[V]();
        }
        case (deleted[K, V]()) { }
      }
      i += 1u;
    }
    ret util.none[V]();
  }

  fn rehash[K, V](&hashfn[K] hasher,
                  &eqfn[K] eqer,
                  vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
                  vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
  {
    for (bucket[K, V] b in oldbkts) {
      alt (b) {
        case (some[K, V](k, v)) {
          insert_common[K, V](hasher, eqer, newbkts, nnewbkts, k, v);
        }
        case (_) { }
      }
    }
  }

  obj hashmap[K, V](hashfn[K] hasher,
                    eqfn[K] eqer,
                    mutable vec[mutable bucket[K, V]] bkts,
                    mutable uint nbkts,
                    mutable uint nelts,
                    util.rational lf)
  {
    fn insert(&K key, &V val) -> bool {
      let util.rational load = rec(num=(nelts + 1u) as int, den=nbkts as int);
      if (!util.rational_leq(load, lf)) {
        let uint nnewbkts = _uint.next_power_of_two(nbkts + 1u);

        let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nnewbkts);
        rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
      }
      if (insert_common[K, V](hasher, eqer, bkts, nbkts, key, val)) {
        nelts += 1u;
        ret true;
      }
      ret false;
    }

    fn contains_key(&K key) -> bool {
      alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
        case (util.some[V](_)) { ret true; }
        case (_) { ret false; }
      }
    }

    fn get(&K key) -> V {
      alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
        case (util.some[V](val)) { ret val; }
        case (_) { fail; }
      }
    }

    fn find(&K key) -> util.option[V] {
      be find_common[K, V](hasher, eqer, bkts, nbkts, key);
    }

    fn remove(&K key) -> util.option[V] {
      let uint i = 0u;
      while (i < nbkts) {
        let uint j = (hash[K](hasher, nbkts, key, i));
        alt (bkts.(j)) {
          case (some[K, V](_, val)) {
            bkts.(j) = deleted[K, V]();
            ret util.some[V](val);
          }
          case (deleted[K, V]()) {
            nelts += 1u;
          }
          case (nil[K, V]()) {
            ret util.none[V]();
          }
        }
      }
      ret util.none[V]();
    }

    fn rehash() {
      let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nbkts);
      rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
      bkts = newbkts;
    }
  }

  let vec[mutable bucket[K, V]] bkts = make_buckets[K, V](initial_capacity);

  ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}
<commit_msg>Actually switch to using the bigger hashmap once a it finishes growing and rehashing.<commit_after>/**
 * At the moment, this is a partial hashmap implementation, not yet fit for
 * use, but useful as a stress test for rustboot.
 */

import std._int;
import std.sys;
import std.util;
import std._vec;

type hashfn[K] = fn(&K) -> uint;
type eqfn[K] = fn(&K, &K) -> bool;

type hashmap[K, V] = obj {
  fn insert(&K key, &V val) -> bool;
  fn contains_key(&K key) -> bool;
  fn get(&K key) -> V;
  fn find(&K key) -> util.option[V];
  fn remove(&K key) -> util.option[V];
  fn rehash();
};

fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {

  let uint initial_capacity = 32u; // 2^5
  let util.rational load_factor = rec(num=3, den=4);

  type bucket[K, V] = tag(nil(), deleted(), some(K, V));

  fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
    ret _vec.init_elt[mutable bucket[K, V]](nil[K, V](), nbkts);
  }

  // Derive two hash functions from the one given by taking the upper
  // half and lower half of the uint bits.  Our bucket probing
  // sequence is then defined by
  //
  //   hash(key, i) := hashl(key) + i * hashr(key)   for i = 0, 1, 2, ...
  //
  // Tearing the hash function apart this way is kosher in practice
  // as, assuming 32-bit uints, the table would have to be at 2^32
  // buckets before the resulting pair of hash functions no longer
  // probes all buckets for a fixed key.  Note that hashr is made to
  // output odd numbers (hence coprime to the number of nbkts, which
  // is always a power of 2), so that all buckets are probed for a
  // fixed key.

  fn hashl[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
    ret (hasher(key) >>> (sys.rustrt.size_of[uint]() * 8u / 2u));
  }

  fn hashr[K](&hashfn[K] hasher, uint nbkts, &K key) -> uint {
    ret ((((~ 0u) >>> (sys.rustrt.size_of[uint]() * 8u / 2u))
          & hasher(key)) * 2u + 1u);
  }

  fn hash[K](&hashfn[K] hasher, uint nbkts, &K key, uint i) -> uint {
    ret (hashl[K](hasher, nbkts, key)
         + i * hashr[K](hasher, nbkts, key)) % nbkts;
  }

  /**
   * We attempt to never call this with a full table.  If we do, it
   * will fail.
   */
  fn insert_common[K, V](&hashfn[K] hasher,
                         &eqfn[K] eqer,
                         vec[mutable bucket[K, V]] bkts,
                         uint nbkts,
                         &K key,
                         &V val)
    -> bool
  {
    let uint i = 0u;
    while (i < nbkts) {
      let uint j = hash[K](hasher, nbkts, key, i);
      alt (bkts.(j)) {
        case (some[K, V](k, _)) {
          if (eqer(key, k)) {
            bkts.(j) = some[K, V](k, val);
            ret false;
          }
          i += 1u;
        }
        case (_) {
          bkts.(j) = some[K, V](key, val);
          ret true;
        }
      }
    }
    fail; // full table
  }

  fn find_common[K, V](&hashfn[K] hasher,
                       &eqfn[K] eqer,
                       vec[mutable bucket[K, V]] bkts,
                       uint nbkts,
                       &K key)
    -> util.option[V]
  {
    let uint i = 0u;
    while (i < nbkts) {
      let uint j = (hash[K](hasher, nbkts, key, i));
      alt (bkts.(j)) {
        case (some[K, V](k, v)) {
          if (eqer(key, k)) {
            ret util.some[V](v);
          }
        }
        case (nil[K, V]()) {
          ret util.none[V]();
        }
        case (deleted[K, V]()) { }
      }
      i += 1u;
    }
    ret util.none[V]();
  }

  fn rehash[K, V](&hashfn[K] hasher,
                  &eqfn[K] eqer,
                  vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
                  vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
  {
    for (bucket[K, V] b in oldbkts) {
      alt (b) {
        case (some[K, V](k, v)) {
          insert_common[K, V](hasher, eqer, newbkts, nnewbkts, k, v);
        }
        case (_) { }
      }
    }
  }

  obj hashmap[K, V](hashfn[K] hasher,
                    eqfn[K] eqer,
                    mutable vec[mutable bucket[K, V]] bkts,
                    mutable uint nbkts,
                    mutable uint nelts,
                    util.rational lf)
  {
    fn insert(&K key, &V val) -> bool {
      let util.rational load = rec(num=(nelts + 1u) as int, den=nbkts as int);
      if (!util.rational_leq(load, lf)) {
        let uint nnewbkts = _uint.next_power_of_two(nbkts + 1u);
        let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nnewbkts);
        rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
        bkts = newbkts;
        nbkts = nnewbkts;
      }

      if (insert_common[K, V](hasher, eqer, bkts, nbkts, key, val)) {
        nelts += 1u;
        ret true;
      }
      ret false;
    }

    fn contains_key(&K key) -> bool {
      alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
        case (util.some[V](_)) { ret true; }
        case (_) { ret false; }
      }
    }

    fn get(&K key) -> V {
      alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
        case (util.some[V](val)) { ret val; }
        case (_) { fail; }
      }
    }

    fn find(&K key) -> util.option[V] {
      be find_common[K, V](hasher, eqer, bkts, nbkts, key);
    }

    fn remove(&K key) -> util.option[V] {
      let uint i = 0u;
      while (i < nbkts) {
        let uint j = (hash[K](hasher, nbkts, key, i));
        alt (bkts.(j)) {
          case (some[K, V](_, val)) {
            bkts.(j) = deleted[K, V]();
            ret util.some[V](val);
          }
          case (deleted[K, V]()) {
            nelts += 1u;
          }
          case (nil[K, V]()) {
            ret util.none[V]();
          }
        }
      }
      ret util.none[V]();
    }

    fn rehash() {
      let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nbkts);
      rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
      bkts = newbkts;
    }
  }

  let vec[mutable bucket[K, V]] bkts = make_buckets[K, V](initial_capacity);

  ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write, Read};

#[derive(Debug)]
pub enum MessageError {
    IoError(io::Error),
    InvalidCRC,
}

impl From<io::Error> for MessageError {
    fn from(e: io::Error) -> MessageError {
        MessageError::IoError(e)
    }
}

macro_rules! read_n {
    ($reader:expr, $buf:expr, $size:expr, $err_msg:expr) => ({

        match $reader.read(&mut $buf) {
            Ok(s) if s == $size => (),
            Ok(_) => return Err(
                MessageError::IoError(
                    io::Error::new(io::ErrorKind::UnexpectedEof, $err_msg))),
            Err(e) => return Err(MessageError::IoError(e)),
        }
    })
}

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
#[derive(Debug)]
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    pub fn read<R>(reader: &mut R) -> Result<Message, MessageError>
        where R: Read
    {
        let mut offset_buf = vec![0; 8];
        read_n!(reader, offset_buf, 8, "Unable to read offset");
        let mut size_buf = vec![0; 4];
        read_n!(reader, size_buf, 4, "Unable to read size");
        let mut crc_buf = vec![0; 4];
        read_n!(reader, crc_buf, 4, "Unable to read CRC");

        let size = BigEndian::read_u32(&size_buf) as usize;
        let crc = BigEndian::read_u32(&crc_buf);

        let mut bytes = vec![0; 16 + size];
        read_n!(reader, bytes[16..], size, "Unable to read message payload");

        let payload_crc = checksum_ieee(&bytes[16..]);
        if payload_crc != crc {
            return Err(MessageError::InvalidCRC);
        }

        bytes[0..8].copy_from_slice(&offset_buf);
        bytes[8..12].copy_from_slice(&size_buf);
        bytes[12..16].copy_from_slice(&crc_buf);

        Ok(Message { bytes: bytes })
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    #[allow(dead_code)]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

/// A segment is a portion of the commit log. Segments are append-only logs written
/// until the maximum size is reached.
pub struct Segment {
    /// File descriptor
    file: File,
    /// Maximum number of bytes permitted to be appended to the log
    max_bytes: usize,
    /// current file position for the write
    pos: usize,

    /// Next offset of the log
    next_offset: u64,
    /// Base offset of the log
    base_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

/// Holds the pair of offset written to file position in the segment file.
#[derive(Copy, Clone, Debug)]
pub struct LogEntryMetadata {
    offset: u64,
    file_pos: u32,
}

impl LogEntryMetadata {
    #[inline]
    pub fn offset(&self) -> u64 {
        self.offset
    }

    #[inline]
    pub fn file_pos(&self) -> u32 {
        self.file_pos
    }
}

impl Segment {
    // TODO: open variant for reading

    pub fn new<P>(log_dir: P, base_offset: u64, max_bytes: usize) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log_path = {
            // the log is of the form BASE_OFFSET.log
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("log");
            path_buf
        };

        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(&log_path));

        Ok(Segment {
            file: f,
            max_bytes: max_bytes,
            pos: 0,

            next_offset: base_offset,
            base_offset: base_offset,
        })
    }

    #[inline]
    pub fn next_offset(&self) -> u64 {
        self.next_offset
    }

    #[inline]
    #[allow(dead_code)]
    pub fn starting_offset(&self) -> u64 {
        self.base_offset
    }

    pub fn append(&mut self, payload: &[u8]) -> Result<LogEntryMetadata, SegmentAppendError> {
        let off = self.next_offset;
        let msg = Message::new(payload, off);
        // ensure we have the capacity
        if msg.bytes().len() + self.pos > self.max_bytes {
            return Err(SegmentAppendError::LogFull);
        }

        try!(self.file.write_all(msg.bytes()));
        let write_pos = self.pos;

        self.pos += msg.bytes().len();
        self.next_offset += 1;

        Ok(LogEntryMetadata {
            offset: off,
            file_pos: write_pos as u32,
        })
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use super::super::testutil::*;
    use std::io;

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn message_read() {
        let msg = Message::new(b"123456789", 1234567u64);
        let mut buf_reader = io::BufReader::new(msg.bytes());
        let read_msg_result = Message::read(&mut buf_reader);
        assert!(read_msg_result.is_ok(), "result = {:?}", read_msg_result);

        let read_msg = read_msg_result.unwrap();
        assert_eq!(read_msg.offset(), 1234567u64);
        assert_eq!(read_msg.payload(), b"123456789");
        assert_eq!(read_msg.crc(), 0xcbf43926);
        assert_eq!(read_msg.size(), 9u32);
    }

    #[test]
    fn message_read_invalid_crc() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // mess with the payload such that the CRC does not match
        let last_ind = msg.len() - 1;
        msg[last_ind] += 1u8;

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::InvalidCRC) => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    fn message_read_invalid_payload_length() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // pop the last byte
        msg.pop();

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    pub fn log() {
        let path = TestDir::new();
        let mut f = Segment::new(path, 0, 1024).unwrap();

        let p0 = f.append(b"12345").unwrap();
        assert_eq!(p0.offset(), 0);
        assert_eq!(p0.file_pos(), 0);

        let p1 = f.append(b"66666").unwrap();
        assert_eq!(p1.offset(), 1);
        assert_eq!(p1.file_pos(), 21);

        f.flush_sync().unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let path = TestDir::new();

        let mut seg = Segment::new(path, 100u64, 100 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });
    }
}
<commit_msg>Adding segment mode<commit_after>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write, Read};

pub static SEGMENT_FILE_NAME_LEN: usize = 20;
pub static SEGMENT_FILE_NAME_EXTENSION: &'static str = "log";

#[derive(Debug)]
pub enum MessageError {
    IoError(io::Error),
    InvalidCRC,
}

impl From<io::Error> for MessageError {
    fn from(e: io::Error) -> MessageError {
        MessageError::IoError(e)
    }
}

macro_rules! read_n {
    ($reader:expr, $buf:expr, $size:expr, $err_msg:expr) => ({

        match $reader.read(&mut $buf) {
            Ok(s) if s == $size => (),
            Ok(_) => return Err(
                MessageError::IoError(
                    io::Error::new(io::ErrorKind::UnexpectedEof, $err_msg))),
            Err(e) => return Err(MessageError::IoError(e)),
        }
    })
}

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
#[derive(Debug)]
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    pub fn read<R>(reader: &mut R) -> Result<Message, MessageError>
        where R: Read
    {
        let mut offset_buf = vec![0; 8];
        read_n!(reader, offset_buf, 8, "Unable to read offset");
        let mut size_buf = vec![0; 4];
        read_n!(reader, size_buf, 4, "Unable to read size");
        let mut crc_buf = vec![0; 4];
        read_n!(reader, crc_buf, 4, "Unable to read CRC");

        let size = BigEndian::read_u32(&size_buf) as usize;
        let crc = BigEndian::read_u32(&crc_buf);

        let mut bytes = vec![0; 16 + size];
        read_n!(reader, bytes[16..], size, "Unable to read message payload");

        let payload_crc = checksum_ieee(&bytes[16..]);
        if payload_crc != crc {
            return Err(MessageError::InvalidCRC);
        }

        bytes[0..8].copy_from_slice(&offset_buf);
        bytes[8..12].copy_from_slice(&size_buf);
        bytes[12..16].copy_from_slice(&crc_buf);

        Ok(Message { bytes: bytes })
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    #[allow(dead_code)]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

enum SegmentMode {
    ReadWrite {
        /// current file position for the write
        write_pos: usize,

        /// Next offset of the log
        next_offset: u64,

        /// Maximum number of bytes permitted to be appended to the log
        max_bytes: usize,
    },
    Read,
}

/// A segment is a portion of the commit log. Segments are append-only logs written
/// until the maximum size is reached.
pub struct Segment {
    /// File descriptor
    file: File,

    mode: SegmentMode,

    /// Base offset of the log
    base_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

/// Holds the pair of offset written to file position in the segment file.
#[derive(Copy, Clone, Debug)]
pub struct LogEntryMetadata {
    offset: u64,
    file_pos: u32,
}

impl LogEntryMetadata {
    #[inline]
    pub fn offset(&self) -> u64 {
        self.offset
    }

    #[inline]
    pub fn file_pos(&self) -> u32 {
        self.file_pos
    }
}

impl Segment {
    pub fn new<P>(log_dir: P, base_offset: u64, max_bytes: usize) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log_path = {
            // the log is of the form BASE_OFFSET.log
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension(SEGMENT_FILE_NAME_EXTENSION);
            path_buf
        };

        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(&log_path));

        Ok(Segment {
            file: f,

            mode: SegmentMode::ReadWrite {
                write_pos: 0,
                next_offset: base_offset,
                max_bytes: max_bytes,
            },

            base_offset: base_offset,
        })
    }

    pub fn open<P>(seg_path: P) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let seg_file = try!(OpenOptions::new()
            .read(true)
            .write(false)
            .append(false)
            .open(&seg_path));

        let filename = seg_path.as_ref().file_name().unwrap().to_str().unwrap();
        let base_offset = match u64::from_str_radix(&filename[0..SEGMENT_FILE_NAME_LEN], 10) {
            Ok(v) => v,
            Err(_) => {
                return Err(io::Error::new(io::ErrorKind::InvalidData,
                                          "Segment file name does not parse as u64"))
            }
        };

        Ok(Segment {
            file: seg_file,
            mode: SegmentMode::Read,
            base_offset: base_offset,
        })
    }

    // TODO: doesn't make sense
    pub fn next_offset(&self) -> u64 {
        match self.mode {
            SegmentMode::ReadWrite { write_pos, next_offset, max_bytes } => next_offset,
            _ => 0
        }
    }

    #[inline]
    #[allow(dead_code)]
    pub fn starting_offset(&self) -> u64 {
        self.base_offset
    }

    pub fn append(&mut self, payload: &[u8]) -> Result<LogEntryMetadata, SegmentAppendError> {
        let (write_pos, off, max_bytes) = match self.mode {
            SegmentMode::ReadWrite { write_pos, next_offset, max_bytes } =>
                (write_pos, next_offset, max_bytes),
            _ => return Err(SegmentAppendError::LogFull),
        };

        let msg = Message::new(payload, off);
        // ensure we have the capacity
        if msg.bytes().len() + write_pos > max_bytes {
            return Err(SegmentAppendError::LogFull);
        }

        try!(self.file.write_all(msg.bytes()));
        self.mode = SegmentMode::ReadWrite {
            write_pos: write_pos + msg.bytes().len(),
            next_offset: off + 1,
            max_bytes: max_bytes,
        };
        Ok(LogEntryMetadata {
            offset: off,
            file_pos: write_pos as u32,
        })
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        self.file.flush()
    }

    /*pub fn read_at_pos(&mut self, pos: u32) -> Result<Message, MessageError> {

    }*/
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use super::super::testutil::*;
    use std::io;

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn message_read() {
        let msg = Message::new(b"123456789", 1234567u64);
        let mut buf_reader = io::BufReader::new(msg.bytes());
        let read_msg_result = Message::read(&mut buf_reader);
        assert!(read_msg_result.is_ok(), "result = {:?}", read_msg_result);

        let read_msg = read_msg_result.unwrap();
        assert_eq!(read_msg.offset(), 1234567u64);
        assert_eq!(read_msg.payload(), b"123456789");
        assert_eq!(read_msg.crc(), 0xcbf43926);
        assert_eq!(read_msg.size(), 9u32);
    }

    #[test]
    fn message_read_invalid_crc() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // mess with the payload such that the CRC does not match
        let last_ind = msg.len() - 1;
        msg[last_ind] += 1u8;

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::InvalidCRC) => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    fn message_read_invalid_payload_length() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // pop the last byte
        msg.pop();

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    pub fn log() {
        let path = TestDir::new();
        let mut f = Segment::new(path, 0, 1024).unwrap();

        let p0 = f.append(b"12345").unwrap();
        assert_eq!(p0.offset(), 0);
        assert_eq!(p0.file_pos(), 0);

        let p1 = f.append(b"66666").unwrap();
        assert_eq!(p1.offset(), 1);
        assert_eq!(p1.file_pos(), 21);

        f.flush_sync().unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let path = TestDir::new();

        let mut seg = Segment::new(path, 100u64, 100 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });
    }
}
<|endoftext|>


<commit_before>use proptest::{prelude::*, proptest, proptest_helper};
use text_unit::{TextUnit, TextRange};
use crate::AtomTextEdit;

pub fn arb_text() -> proptest::string::RegexGeneratorStrategy<String> {
    // generate multiple newlines
    proptest::string::string_regex("(.*\n?)*").unwrap()
}

fn text_offsets(text: &str) -> Vec<TextUnit> {
    text.char_indices()
        .map(|(i, _)| TextUnit::from_usize(i))
        .collect()
}

pub fn arb_offset(text: &str) -> BoxedStrategy<TextUnit> {
    let offsets = text_offsets(text);
    // this is necessary to avoid "Uniform::new called with `low >= high`" panic
    if offsets.is_empty() {
        Just(TextUnit::from(0)).boxed()
    } else {
        prop::sample::select(offsets).boxed()
    }
}

pub fn arb_edits(text: &str) -> BoxedStrategy<Vec<AtomTextEdit>> {
    let offsets = text_offsets(text);
    let offsets_len = offsets.len();

    if offsets_len == 0 {
        return proptest::bool::ANY
            .prop_flat_map(|b| {
                // only valid edits
                if b {
                    arb_text()
                        .prop_map(|text| vec![AtomTextEdit::insert(TextUnit::from(0), text)])
                        .boxed()
                } else {
                    Just(vec![]).boxed()
                }
            })
            .boxed();
    }

    proptest::sample::subsequence(offsets, 0..offsets_len)
        .prop_flat_map(|xs| {
            let strategies: Vec<_> = xs
                .chunks(2)
                .map(|chunk| match chunk {
                    &[from, to] => {
                        let range = TextRange::from_to(from, to);
                        (proptest::bool::ANY)
                            .prop_flat_map(move |b| {
                                if b {
                                    Just(AtomTextEdit::delete(range)).boxed()
                                } else {
                                    arb_text()
                                        .prop_map(move |text| AtomTextEdit::replace(range, text))
                                        .boxed()
                                }
                            })
                            .boxed()
                    }
                    &[x] => arb_text()
                        .prop_map(move |text| AtomTextEdit::insert(x, text))
                        .boxed(),
                    _ => unreachable!(),
                })
                .collect();
            strategies
        })
        .boxed()
}

fn arb_text_with_edits() -> BoxedStrategy<(String, Vec<AtomTextEdit>)> {
    let text = arb_text();
    text.prop_flat_map(|s| {
        let edits = arb_edits(&s);
        (Just(s), edits)
    })
    .boxed()
}

fn intersect(r1: TextRange, r2: TextRange) -> Option<TextRange> {
    let start = r1.start().max(r2.start());
    let end = r1.end().min(r2.end());
    if start <= end {
        Some(TextRange::from_to(start, end))
    } else {
        None
    }
}

proptest! {
#[test]
    fn atom_text_edits_are_valid((text, edits) in arb_text_with_edits()) {
        proptest_atom_text_edits_are_valid(text, edits)
    }
}

fn proptest_atom_text_edits_are_valid(text: String, edits: Vec<AtomTextEdit>) {
    // slicing doesn't panic
    for e in &edits {
        let _ = &text[e.delete];
    }
    // ranges do not overlap
    for (i1, e1) in edits.iter().skip(1).enumerate() {
        for e2 in &edits[0..i1] {
            if intersect(e1.delete, e2.delete).is_some() {
                assert!(false, "Overlapping ranges {} {}", e1.delete, e2.delete);
            }
        }
    }
}
<commit_msg>simplify and reduce number of values explored<commit_after>use proptest::{prelude::*, proptest, proptest_helper};
use text_unit::{TextUnit, TextRange};
use crate::AtomTextEdit;

pub fn arb_text() -> proptest::string::RegexGeneratorStrategy<String> {
    // generate multiple newlines
    proptest::string::string_regex("(.*\n?)*").unwrap()
}

fn text_offsets(text: &str) -> Vec<TextUnit> {
    text.char_indices()
        .map(|(i, _)| TextUnit::from_usize(i))
        .collect()
}

pub fn arb_offset(text: &str) -> BoxedStrategy<TextUnit> {
    let offsets = text_offsets(text);
    // this is necessary to avoid "Uniform::new called with `low >= high`" panic
    if offsets.is_empty() {
        Just(TextUnit::from(0)).boxed()
    } else {
        prop::sample::select(offsets).boxed()
    }
}

pub fn arb_edits(text: &str) -> BoxedStrategy<Vec<AtomTextEdit>> {
    if text.is_empty() {
        // only valid edits
        return Just(vec![])
            .boxed()
            .prop_union(
                arb_text()
                    .prop_map(|text| vec![AtomTextEdit::insert(TextUnit::from(0), text)])
                    .boxed(),
            )
            .boxed();
    }

    let offsets = text_offsets(text);
    let max_cuts = offsets.len().min(7);

    proptest::sample::subsequence(offsets, 0..max_cuts)
        .prop_flat_map(|cuts| {
            let strategies: Vec<_> = cuts
                .chunks(2)
                .map(|chunk| match chunk {
                    &[from, to] => {
                        let range = TextRange::from_to(from, to);
                        Just(AtomTextEdit::delete(range))
                            .boxed()
                            .prop_union(
                                arb_text()
                                    .prop_map(move |text| AtomTextEdit::replace(range, text))
                                    .boxed(),
                            )
                            .boxed()
                    }
                    &[x] => arb_text()
                        .prop_map(move |text| AtomTextEdit::insert(x, text))
                        .boxed(),
                    _ => unreachable!(),
                })
                .collect();
            strategies
        })
        .boxed()
}

fn arb_text_with_edits() -> BoxedStrategy<(String, Vec<AtomTextEdit>)> {
    let text = arb_text();
    text.prop_flat_map(|s| {
        let edits = arb_edits(&s);
        (Just(s), edits)
    })
    .boxed()
}

fn intersect(r1: TextRange, r2: TextRange) -> Option<TextRange> {
    let start = r1.start().max(r2.start());
    let end = r1.end().min(r2.end());
    if start <= end {
        Some(TextRange::from_to(start, end))
    } else {
        None
    }
}

proptest! {
    #[test]
    fn atom_text_edits_are_valid((text, edits) in arb_text_with_edits()) {
        proptest_atom_text_edits_are_valid(text, edits)
    }
}

fn proptest_atom_text_edits_are_valid(text: String, edits: Vec<AtomTextEdit>) {
    // slicing doesn't panic
    for e in &edits {
        let _ = &text[e.delete];
    }
    // ranges do not overlap
    for (i1, e1) in edits.iter().skip(1).enumerate() {
        for e2 in &edits[0..i1] {
            if intersect(e1.delete, e2.delete).is_some() {
                assert!(false, "Overlapping ranges {} {}", e1.delete, e2.delete);
            }
        }
    }
}
<|endoftext|>


<commit_before>// A separator used to break the code into two parts to aid memorability.
pub const SEPARATOR: char = '+';

// The number of characters to place before the separator.
pub const SEPARATOR_POSITION: usize = 8;

// The character used to pad codes.
pub const PADDING_CHAR: char = '0';
pub const PADDING_CHAR_STR: &'static str = "0";

// The character set used to encode the values.
pub const CODE_ALPHABET: [char; 20] = [
    '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'F', 'G', 'H', 'J', 'M', 'P', 'Q', 'R', 'V', 'W',
    'X',
];

// The base to use to convert numbers to/from.
pub const ENCODING_BASE: usize = 20;

// The maximum value for latitude in degrees.
pub const LATITUDE_MAX: f64 = 90f64;

// The maximum value for longitude in degrees.
pub const LONGITUDE_MAX: f64 = 180f64;

// Maximum number of digits to process for plus codes.
pub const MAX_CODE_LENGTH: usize = 15;

// Maximum code length using lat/lng pair encoding. The area of such a
// code is approximately 13x13 meters (at the equator), and should be suitable
// for identifying buildings. This excludes prefix and separator characters.
pub const PAIR_CODE_LENGTH: usize = 10;

// Digits in the grid encoding..
pub const GRID_CODE_LENGTH: usize = 5;

// The resolution values in degrees for each position in the lat/lng pair
// encoding. These give the place value of each position, and therefore the
// dimensions of the resulting area.
pub const PAIR_RESOLUTIONS: [f64; 5] = [20.0f64, 1.0f64, 0.05f64, 0.0025f64, 0.000125f64];

// Number of columns in the grid refinement method.
pub const GRID_COLUMNS: usize = 4;

// Number of rows in the grid refinement method.
pub const GRID_ROWS: usize = 5;

// Minimum length of a code that can be shortened.
pub const MIN_TRIMMABLE_CODE_LEN: usize = 6;

// What to multiple latitude degrees by to get an integer value. There are three pairs representing
// decimal digits, and five digits in the grid.
pub const LAT_INTEGER_MULTIPLIER: i64 = (ENCODING_BASE
    * ENCODING_BASE
    * ENCODING_BASE
    * GRID_ROWS
    * GRID_ROWS
    * GRID_ROWS
    * GRID_ROWS
    * GRID_ROWS) as i64;

// What to multiple longitude degrees by to get an integer value. There are three pairs representing
// decimal digits, and five digits in the grid.
pub const LNG_INTEGER_MULTIPLIER: i64 = (ENCODING_BASE
    * ENCODING_BASE
    * ENCODING_BASE
    * GRID_COLUMNS
    * GRID_COLUMNS
    * GRID_COLUMNS
    * GRID_COLUMNS
    * GRID_COLUMNS) as i64;
<commit_msg>Redundant static lifetime<commit_after>// A separator used to break the code into two parts to aid memorability.
pub const SEPARATOR: char = '+';

// The number of characters to place before the separator.
pub const SEPARATOR_POSITION: usize = 8;

// The character used to pad codes.
pub const PADDING_CHAR: char = '0';
pub const PADDING_CHAR_STR: &str = "0";

// The character set used to encode the values.
pub const CODE_ALPHABET: [char; 20] = [
    '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'F', 'G', 'H', 'J', 'M', 'P', 'Q', 'R', 'V', 'W',
    'X',
];

// The base to use to convert numbers to/from.
pub const ENCODING_BASE: usize = 20;

// The maximum value for latitude in degrees.
pub const LATITUDE_MAX: f64 = 90f64;

// The maximum value for longitude in degrees.
pub const LONGITUDE_MAX: f64 = 180f64;

// Maximum number of digits to process for plus codes.
pub const MAX_CODE_LENGTH: usize = 15;

// Maximum code length using lat/lng pair encoding. The area of such a
// code is approximately 13x13 meters (at the equator), and should be suitable
// for identifying buildings. This excludes prefix and separator characters.
pub const PAIR_CODE_LENGTH: usize = 10;

// Digits in the grid encoding..
pub const GRID_CODE_LENGTH: usize = 5;

// The resolution values in degrees for each position in the lat/lng pair
// encoding. These give the place value of each position, and therefore the
// dimensions of the resulting area.
pub const PAIR_RESOLUTIONS: [f64; 5] = [20.0f64, 1.0f64, 0.05f64, 0.0025f64, 0.000125f64];

// Number of columns in the grid refinement method.
pub const GRID_COLUMNS: usize = 4;

// Number of rows in the grid refinement method.
pub const GRID_ROWS: usize = 5;

// Minimum length of a code that can be shortened.
pub const MIN_TRIMMABLE_CODE_LEN: usize = 6;

// What to multiple latitude degrees by to get an integer value. There are three pairs representing
// decimal digits, and five digits in the grid.
pub const LAT_INTEGER_MULTIPLIER: i64 = (ENCODING_BASE
    * ENCODING_BASE
    * ENCODING_BASE
    * GRID_ROWS
    * GRID_ROWS
    * GRID_ROWS
    * GRID_ROWS
    * GRID_ROWS) as i64;

// What to multiple longitude degrees by to get an integer value. There are three pairs representing
// decimal digits, and five digits in the grid.
pub const LNG_INTEGER_MULTIPLIER: i64 = (ENCODING_BASE
    * ENCODING_BASE
    * ENCODING_BASE
    * GRID_COLUMNS
    * GRID_COLUMNS
    * GRID_COLUMNS
    * GRID_COLUMNS
    * GRID_COLUMNS) as i64;
<|endoftext|>


<commit_before>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f32;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

// TODO Dimension type alias
// TODO OwnedArray

// TODO call this OrthoNMFBlas
pub struct OrthogonalNMFBlas {
    pub hidden: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights: ArrayBase<Vec<FloatT>, (usize, usize)>,

    // these hold temporary results during an iteration.
    // kept in struct to prevent unnecessary memory allocations.
    pub weights_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights_divisor_reconstruction: ArrayBase<Vec<FloatT>, (usize, usize)>,

    pub hidden_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub hidden_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub hidden_divisor_partial: ArrayBase<Vec<FloatT>, (usize, usize)>,

    pub gamma: ArrayBase<Vec<FloatT>, (usize, usize)>,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    // TODO type alias for that ArrayBase stuff

    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = ArrayBase::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = ArrayBase::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: ArrayBase<Vec<FloatT>, (usize, usize)>, weights: ArrayBase<Vec<FloatT>, (usize, usize)>) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,
            weights_dividend: ArrayBase::zeros(weights_shape),
            weights_divisor: ArrayBase::zeros(weights_shape),
            weights_divisor_reconstruction: ArrayBase::zeros(samples_shape),
            hidden_dividend: ArrayBase::zeros(hidden_shape),
            hidden_divisor: ArrayBase::zeros(hidden_shape),
            hidden_divisor_partial: ArrayBase::zeros((nhidden, nhidden)),
            gamma: OrthogonalNMFBlas::gamma(nhidden),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    /// gamma is a symetric matrix with diagonal elements equal to zero
    /// and other elements equal to 1
    pub fn gamma(size: usize) -> ArrayBase<Vec<FloatT>, (usize, usize)> {
        let mut gamma = ArrayBase::<Vec<FloatT>, (usize, usize)>::from_elem((size, size), 1.);
        for x in gamma.diag_mut().iter_mut() {
            *x = 0.
        }
        gamma
    }

    /// `samples * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_dividend(&mut self, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_dividend.blas());

    }

    /// `weights * hidden * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_divisor(&mut self) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor_reconstruction.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor.blas());
    }

    /// `weights.transpose() * samples`
    #[inline]
    pub fn iterate_hidden_dividend(&mut self, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.hidden_dividend.blas());
    }

    /// `weights.transpose() * weights * hidden + alpha * gamma * hidden`
    #[inline]
    pub fn iterate_hidden_divisor(&mut self, alpha: FloatT) {
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        // TODO is there away to prevent this
        // maybe use clone_from here
        let mut weights_copy = self.weights.clone();
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut self.hidden_divisor_partial.blas());
        Gemm::gemm(
            &alpha,
            Transpose::NoTrans, &self.gamma.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.hidden_divisor.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.hidden_divisor_partial.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            // add to previous contents of self.hidden_divisor
            &1.,
            &mut self.hidden_divisor.blas());
    }

    // TODO better name
    // per element division
    /// `result(i,j) <- result(i,j) * dividend(i,j) / divisor(i,j)`
    #[inline]
    pub fn update(
        dividend: &ArrayBase<Vec<FloatT>, (usize, usize)>,
        divisor: &ArrayBase<Vec<FloatT>, (usize, usize)>,
        result: &mut ArrayBase<Vec<FloatT>, (usize, usize)>,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, dividend.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any zero in any of the matrizes
                // self.weights or self.hidden then
                // divisor will be zero.
                // we can't divide by zero
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= dividend.uget(index) / div;
                }
                // TODO maybe also zero adjust the final weight
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        // TODO benchmark these individually
        // TODO add little descriptions like
        // X <- X^T
        // TODO also add them to docstrings
        // TODO maybe pass in all data explicitely
        self.iterate_weights_dividend(samples);
        self.iterate_weights_divisor();
        self.iterate_hidden_dividend(samples);
        self.iterate_hidden_divisor(alpha);

        OrthogonalNMFBlas::update(
            &self.weights_dividend,
            &self.weights_divisor,
            &mut self.weights);
        OrthogonalNMFBlas::update(
            &self.hidden_dividend,
            &self.hidden_divisor,
            &mut self.hidden);
    }
}
<commit_msg>ortho nmf blas: clean up a bit using type aliases<commit_after>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f32;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

pub type Ix = (usize, usize);
pub type MyMatrix = ArrayBase<Vec<FloatT>, Ix>;

// TODO call this OrthoNMFBlas
pub struct OrthogonalNMFBlas {
    pub hidden: MyMatrix,
    pub weights: MyMatrix,

    // these hold temporary results during an iteration.
    // kept in this struct to prevent unnecessary memory allocations.
    pub weights_dividend: MyMatrix,
    pub weights_divisor: MyMatrix,
    pub weights_divisor_reconstruction: MyMatrix,

    pub hidden_dividend: MyMatrix,
    pub hidden_divisor: MyMatrix,
    pub hidden_divisor_partial: MyMatrix,

    pub gamma: MyMatrix,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = MyMatrix::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = MyMatrix::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: MyMatrix, weights: MyMatrix) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,

            weights_dividend: MyMatrix::zeros(weights_shape),
            weights_divisor: MyMatrix::zeros(weights_shape),
            weights_divisor_reconstruction: MyMatrix::zeros(samples_shape),

            hidden_dividend: MyMatrix::zeros(hidden_shape),
            hidden_divisor: MyMatrix::zeros(hidden_shape),
            hidden_divisor_partial: MyMatrix::zeros((nhidden, nhidden)),

            gamma: OrthogonalNMFBlas::gamma(nhidden),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    /// gamma is a symetric matrix with diagonal elements equal to zero
    /// and other elements equal to 1
    pub fn gamma(size: usize) -> MyMatrix {
        let mut gamma = MyMatrix::from_elem((size, size), 1.);
        for x in gamma.diag_mut().iter_mut() {
            *x = 0.
        }
        gamma
    }

    /// `samples * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_dividend(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_dividend.blas());

    }

    /// `weights * hidden * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_divisor(&mut self) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor_reconstruction.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor.blas());
    }

    /// `weights.transpose() * samples`
    #[inline]
    pub fn iterate_hidden_dividend(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.hidden_dividend.blas());
    }

    /// `weights.transpose() * weights * hidden + alpha * gamma * hidden`
    #[inline]
    pub fn iterate_hidden_divisor(&mut self, alpha: FloatT) {
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        // TODO this will be solved once
        // https://github.com/bluss/rust-ndarray/pull/40
        // is merged.
        let mut weights_copy = self.weights.clone();
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut self.hidden_divisor_partial.blas());
        Gemm::gemm(
            &alpha,
            Transpose::NoTrans, &self.gamma.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.hidden_divisor.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.hidden_divisor_partial.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            // add to previous contents of self.hidden_divisor
            &1.,
            &mut self.hidden_divisor.blas());
    }

    // TODO better name
    // per element division
    /// `result(i,j) <- result(i,j) * dividend(i,j) / divisor(i,j)`
    #[inline]
    pub fn update(
        dividend: &MyMatrix,
        divisor: &MyMatrix,
        result: &mut MyMatrix,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, dividend.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any 0 in any of the matrixes
                // self.weights or self.hidden then
                // divisor will be 0.
                // we can't divide by 0.
                // so we change them to the min positive value.
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= dividend.uget(index) / div;
                }
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut MyMatrix) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        self.iterate_weights_dividend(samples);
        self.iterate_weights_divisor();
        self.iterate_hidden_dividend(samples);
        self.iterate_hidden_divisor(alpha);

        OrthogonalNMFBlas::update(
            &self.weights_dividend,
            &self.weights_divisor,
            &mut self.weights);
        OrthogonalNMFBlas::update(
            &self.hidden_dividend,
            &self.hidden_divisor,
            &mut self.hidden);
    }
}
<|endoftext|>


<commit_before>use metrics::metric::Metric;
use registry::{Registry, StdRegistry};
use std::time::Duration;
use std::thread;
use std::sync::Arc;
use metrics::meter::Meter;
use reporter::base::Reporter;
use metrics::counter::StdCounter;
use metrics::gauge::StdGauge;
use metrics::meter::MeterSnapshot;
use histogram::Histogram;
use time;
use time::Timespec;

use iron::{Iron, Request, Response, IronResult, AfterMiddleware, Chain};
use iron::error::{IronError};
use iron::status;
use router::{Router, NoRoute};
use std::result;
use iron;

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        println!("Hitting custom 404 middleware");

        if let Some(_) = err.error.downcast::<NoRoute>() {
            Ok(Response::with((status::NotFound, "Custom 404 response")))
        } else {
            Err(err)
        }
    }
}

pub struct PrometheusReporter {
    host_and_port: &'static str,
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str
}

impl Reporter for PrometheusReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

impl PrometheusReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: &'static str,
               prefix: &'static str)
               -> PrometheusReporter {
        PrometheusReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    pub fn start(self) -> thread::JoinHandle<()> {
        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/", handler);
            let mut chain = Chain::new(router);
            chain.link_after(Custom404);
            // TODO -> Result<iron::Listening, iron::error::Error>
            Iron::new(chain).http(self.host_and_port).unwrap();
        })
    }

}

fn handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Handling response")))
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::prometheus::PrometheusReporter;
    use std::sync::Arc;
    use histogram::*;

    #[test]
    fn add_some_stats_and_slurp_them_with_http() {
        extern crate hyper;
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0f64 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1);

        let mut r = StdRegistry::new();
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        let reporter = PrometheusReporter::new(arc_registry.clone(),
                            "test",
                            "0.0.0.0:8080",
                            "asd.asdf");
        reporter.start();

        let client = hyper::client::Client::new();

        let res = client.get("http://127.0.0.1:8080").send().unwrap();

    }
}
<commit_msg>An automatic format<commit_after>use metrics::metric::Metric;
use registry::{Registry, StdRegistry};
use std::time::Duration;
use std::thread;
use std::sync::Arc;
use metrics::meter::Meter;
use reporter::base::Reporter;
use metrics::counter::StdCounter;
use metrics::gauge::StdGauge;
use metrics::meter::MeterSnapshot;
use histogram::Histogram;
use time;
use time::Timespec;

use iron::{Iron, Request, Response, IronResult, AfterMiddleware, Chain};
use iron::error::IronError;
use iron::status;
use router::{Router, NoRoute};
use std::result;
use iron;

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        println!("Hitting custom 404 middleware");

        if let Some(_) = err.error.downcast::<NoRoute>() {
            Ok(Response::with((status::NotFound, "Custom 404 response")))
        } else {
            Err(err)
        }
    }
}

pub struct PrometheusReporter {
    host_and_port: &'static str,
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl Reporter for PrometheusReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

impl PrometheusReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: &'static str,
               prefix: &'static str)
               -> PrometheusReporter {
        PrometheusReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    pub fn start(self) -> thread::JoinHandle<()> {
        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/", handler);
            let mut chain = Chain::new(router);
            chain.link_after(Custom404);
            // TODO -> Result<iron::Listening, iron::error::Error>
            Iron::new(chain).http(self.host_and_port).unwrap();
        })
    }
}

fn handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Handling response")))
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::prometheus::PrometheusReporter;
    use std::sync::Arc;
    use histogram::*;

    #[test]
    fn add_some_stats_and_slurp_them_with_http() {
        extern crate hyper;
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0f64 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1);

        let mut r = StdRegistry::new();
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        let reporter =
            PrometheusReporter::new(arc_registry.clone(), "test", "0.0.0.0:8080", "asd.asdf");
        reporter.start();

        let client = hyper::client::Client::new();

        let res = client.get("http://127.0.0.1:8080").send().unwrap();

    }
}
<|endoftext|>


<commit_before>
use num::*;
use vec::Vec3;
use std::ops::*;

/// A matrix which is layed out in column major format in memory
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Mat4<T: Num + Copy> {
    // The order in which the components are defined here is inverse of
    // the way they are typically would be used, as the matrix should
    // be stored in collumn major format for opengl interoparability
    pub a11: T, pub a21: T, pub a31: T, pub a41: T,
    pub a12: T, pub a22: T, pub a32: T, pub a42: T,
    pub a13: T, pub a23: T, pub a33: T, pub a43: T,
    pub a14: T, pub a24: T, pub a34: T, pub a44: T,
}

impl<T: Num + Copy> Mat4<T> {
    /// Creates a new Mat4 with all values set to 0
    pub fn new() -> Mat4<T> {
        Mat4 {
            a11: T::zero(), a12: T::zero(), a13: T::zero(), a14: T::zero(),
            a21: T::zero(), a22: T::zero(), a23: T::zero(), a24: T::zero(),
            a31: T::zero(), a32: T::zero(), a33: T::zero(), a34: T::zero(),
            a41: T::zero(), a42: T::zero(), a43: T::zero(), a44: T::zero(),
        }
    }

    /// Creates a new identity matrix
    pub fn identity() -> Mat4<T> {
        Mat4 {
            a11: T::one(),  a12: T::zero(), a13: T::zero(), a14: T::zero(),
            a21: T::zero(), a22: T::one(),  a23: T::zero(), a24: T::zero(),
            a31: T::zero(), a32: T::zero(), a33: T::one(),  a34: T::zero(),
            a41: T::zero(), a42: T::zero(), a43: T::zero(), a44: T::one(),
        }
    }

    /// Creates a new orthographic projection matrix
    pub fn ortho(left: T, right: T, top: T, bottom: T, near: T, far: T) -> Mat4<T> {
        let two = T::one() + T::one();
        let a11 = two / (right-left);
        let a22 = two / (top-left);
        let a33 = two / (near-far);

        let a14 = T::zero() - ((right+left) / (right-left));
        let a24 = T::zero() - ((top+bottom) / (top-bottom));
        let a34 = T::zero() - ((far+near) / (far - near));

        Mat4 {
            a11: a11, a12: T::zero(), a13: T::zero(), a14: a14,
            a21: T::zero(), a22: a22, a23: T::zero(), a24: a24,
            a31: T::zero(), a32: T::zero(), a33: a33, a34: a34,
            a41: T::zero(), a42: T::zero(), a43: T::zero(), a44: T::one()
        }
    }

    /// Creates a translation matrix
    pub fn translation(translation: Vec3<T>) -> Mat4<T> {
        Mat4 {
            a14: translation.x, a24: translation.y, a34: translation.z,
            .. Mat4::identity()
        }
    }
}

// Multiplication (Ugly code)
impl<T: Num + Copy> Mul for Mat4<T> {
    type Output = Self;

    fn mul(self, other: Self) -> Self {
        let a = self;
        let b = other;

        Mat4 {
            a11: a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41,
            a12: a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42,
            a13: a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43,
            a14: a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44,

            a21: a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41,
            a22: a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42,
            a23: a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43,
            a24: a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44,

            a31: a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41,
            a32: a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42,
            a33: a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43,
            a34: a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44,

            a41: a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41,
            a42: a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42,
            a43: a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43,
            a44: a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44,
        }
    }
}
impl<T: Num + Copy> MulAssign for Mat4<T> {
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other;
    }
}
<commit_msg>Added matrix multiplication tests<commit_after>
use num::*;
use vec::Vec3;
use std::ops::*;

/// A matrix which is layed out in column major format in memory
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Mat4<T: Num + Copy> {
    // The order in which the components are defined here is inverse of
    // the way they are typically would be used, as the matrix should
    // be stored in collumn major format for opengl interoparability
    pub a11: T, pub a21: T, pub a31: T, pub a41: T,
    pub a12: T, pub a22: T, pub a32: T, pub a42: T,
    pub a13: T, pub a23: T, pub a33: T, pub a43: T,
    pub a14: T, pub a24: T, pub a34: T, pub a44: T,
}

impl<T: Num + Copy> Mat4<T> {
    /// Creates a new Mat4 with all values set to 0
    pub fn zero() -> Mat4<T> {
        Mat4 {
            a11: T::zero(), a12: T::zero(), a13: T::zero(), a14: T::zero(),
            a21: T::zero(), a22: T::zero(), a23: T::zero(), a24: T::zero(),
            a31: T::zero(), a32: T::zero(), a33: T::zero(), a34: T::zero(),
            a41: T::zero(), a42: T::zero(), a43: T::zero(), a44: T::zero(),
        }
    }

    /// Creates a new identity matrix
    pub fn identity() -> Mat4<T> {
        Mat4 {
            a11: T::one(),  a12: T::zero(), a13: T::zero(), a14: T::zero(),
            a21: T::zero(), a22: T::one(),  a23: T::zero(), a24: T::zero(),
            a31: T::zero(), a32: T::zero(), a33: T::one(),  a34: T::zero(),
            a41: T::zero(), a42: T::zero(), a43: T::zero(), a44: T::one(),
        }
    }

    /// Creates a new matrix with the given values. The values are specified
    /// row by row.
    pub fn with_values(a11: T, a12: T, a13: T, a14: T,
                       a21: T, a22: T, a23: T, a24: T,
                       a31: T, a32: T, a33: T, a34: T,
                       a41: T, a42: T, a43: T, a44: T)
                       -> Mat4<T> {
        Mat4 {
            a11: a11, a12: a12, a13: a13, a14: a14,
            a21: a21, a22: a22, a23: a23, a24: a24,
            a31: a31, a32: a32, a33: a33, a34: a34,
            a41: a41, a42: a42, a43: a43, a44: a44
        }
    }

    /// Creates a new orthographic projection matrix
    pub fn ortho(left: T, right: T, top: T, bottom: T, near: T, far: T) -> Mat4<T> {
        let two = T::one() + T::one();
        let a11 = two / (right-left);
        let a22 = two / (top-left);
        let a33 = two / (near-far);

        let a14 = T::zero() - ((right+left) / (right-left));
        let a24 = T::zero() - ((top+bottom) / (top-bottom));
        let a34 = T::zero() - ((far+near) / (far - near));

        Mat4 {
            a11: a11, a12: T::zero(), a13: T::zero(), a14: a14,
            a21: T::zero(), a22: a22, a23: T::zero(), a24: a24,
            a31: T::zero(), a32: T::zero(), a33: a33, a34: a34,
            a41: T::zero(), a42: T::zero(), a43: T::zero(), a44: T::one()
        }
    }

    /// Creates a translation matrix
    pub fn translation(translation: Vec3<T>) -> Mat4<T> {
        Mat4 {
            a14: translation.x, a24: translation.y, a34: translation.z,
            .. Mat4::identity()
        }
    }
}

// Multiplication
impl<T: Num + Copy> Mul for Mat4<T> {
    type Output = Self;

    fn mul(self, other: Self) -> Self {
        let a = self;
        let b = other;

        Mat4 {
            a11: a.a11*b.a11 + a.a12*b.a21 + a.a13*b.a31 + a.a14*b.a41,
            a12: a.a11*b.a12 + a.a12*b.a22 + a.a13*b.a32 + a.a14*b.a42,
            a13: a.a11*b.a13 + a.a12*b.a23 + a.a13*b.a33 + a.a14*b.a43,
            a14: a.a11*b.a14 + a.a12*b.a24 + a.a13*b.a34 + a.a14*b.a44,

            a21: a.a21*b.a11 + a.a22*b.a21 + a.a23*b.a31 + a.a24*b.a41,
            a22: a.a21*b.a12 + a.a22*b.a22 + a.a23*b.a32 + a.a24*b.a42,
            a23: a.a21*b.a13 + a.a22*b.a23 + a.a23*b.a33 + a.a24*b.a43,
            a24: a.a21*b.a14 + a.a22*b.a24 + a.a23*b.a34 + a.a24*b.a44,

            a31: a.a31*b.a11 + a.a32*b.a21 + a.a33*b.a31 + a.a34*b.a41,
            a32: a.a31*b.a12 + a.a32*b.a22 + a.a33*b.a32 + a.a34*b.a42,
            a33: a.a31*b.a13 + a.a32*b.a23 + a.a33*b.a33 + a.a34*b.a43,
            a34: a.a31*b.a14 + a.a32*b.a24 + a.a33*b.a34 + a.a34*b.a44,

            a41: a.a41*b.a11 + a.a42*b.a21 + a.a43*b.a31 + a.a44*b.a41,
            a42: a.a41*b.a12 + a.a42*b.a22 + a.a43*b.a32 + a.a44*b.a42,
            a43: a.a41*b.a13 + a.a42*b.a23 + a.a43*b.a33 + a.a44*b.a43,
            a44: a.a41*b.a14 + a.a42*b.a24 + a.a43*b.a34 + a.a44*b.a44,
        }
    }
}
impl<T: Num + Copy> MulAssign for Mat4<T> {
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other;
    }
}

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

    // Function for generating random testing matrices
    fn mat_a() -> Mat4<f32> {
        Mat4::with_values(1.0, 7.0, 4.0, 3.0,
                          5.0, 6.0, 7.0, 8.0,
                          9.0, 2.0, 3.0, 1.0,
                          6.0, 6.0, 2.0, 7.0)
    }
    fn mat_b() -> Mat4<f32> {
        Mat4::with_values(7.0, 8.0, 2.0, 9.0,
                          1.0, 3.0, 5.0, 2.0,
                          3.0, 6.0, 3.0, 7.0,
                          2.0, 7.0, 3.0, 8.0)
    }
    fn mat_c() -> Mat4<f32> {
        Mat4::with_values(5.0, 7.0, 1.0, 2.0,
                          3.0, 1.0, 8.0, 4.0,
                          9.0, 2.0, 0.0, 1.0,
                          3.0, 7.0, 1.0, 8.0)
    }

    #[test]
    fn identity() {
        let a = mat_a();
        let b = mat_b();
        let c = mat_c();
        let identity = Mat4::identity();

        assert_eq!(a, a * identity);
        assert_eq!(b, b * identity);
        assert_eq!(c, c * identity);

        assert_eq!(a, identity * a);
        assert_eq!(b, identity * b);
        assert_eq!(c, identity * c);

        assert_ne!(identity * a, identity * b);
        assert_ne!(identity * b, identity * c);
        assert_ne!(identity * a, identity * c);

    }

    #[test]
    fn zero() {
        let a = mat_a();
        let b = mat_b();
        let c = mat_c();
        let identity = Mat4::identity();
        let zero = Mat4::zero();

        assert_eq!(identity * zero, zero);

        assert_eq!(zero, a * zero);
        assert_eq!(zero, b * zero);
        assert_eq!(zero, c * zero);
    }

    #[test]
    fn mul() {
        let a = mat_a();
        let b = mat_b();
        let ab = Mat4::with_values(32.0, 74.0, 58.0, 75.0,
                                   78.0, 156.0, 85.0, 170.0,
                                   76.0, 103.0, 40.0, 114.0,
                                   68.0, 127.0, 69.0, 136.0);

        assert_eq!(ab, a * b);

        let mut c = a;
        c *= b;

        assert_eq!(ab, c);

        let ba = Mat4::with_values(119.0, 155.0, 108.0, 150.0,
                                   73.0, 47.0, 44.0, 46.0,
                                   102.0, 105.0, 77.0, 109.0,
                                   112.0, 110.0, 82.0, 121.0);
        assert_eq!(ba, b * a);

        assert_ne!(b * a, a * b);
    }
}

<|endoftext|>


<commit_before>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::sync::Arc;
use table::{Static, StaticSet, StaticSetIterator};

use {Get, Set, ToEntity};

/// A common set of data owned by an `Entity`
#[derive(Clone, Default, RustcEncodable, RustcDecodable, Copy)]
pub struct Object {
    /// Who is the parent of this object
    pub parent: Entity,
}

/// A key to connect Entities across Systems
pub type Entity = u32;

/// CommonData is a container that contains all the information needed
/// to implement the Common root of `snowmews`'s entity systems
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct CommonData {
    last_oid:       Entity,
    objects:        Static<Object>,
    parent_child:   Static<StaticSet>,
    scene_children: Static<StaticSet>,
    freelist:       Arc<Vec<Entity>>
}

impl CommonData {
    /// Create CommonData for use with the `Common` trait
    pub fn new() -> CommonData {
        CommonData {
            last_oid: 1,
            objects: Static::new(),
            parent_child: Static::new(),
            scene_children: Static::new(),
            freelist: Arc::new(Vec::new())
        }
    }

    fn new_key(&mut self) -> Entity {
        if !self.freelist.is_empty() {
            return self.freelist.make_unique().pop().expect("missing entry...");
        }
        let new_key = self.last_oid;
        self.last_oid += 1;
        new_key
    }

    fn update_parent_child(&mut self, parent: Entity, child: Entity) {
        let new = match self.parent_child.get_mut(parent) {
            Some(child_list) => {
                child_list.insert(child);
                None
            },
            None => {
                let mut child_list = StaticSet::new();
                child_list.insert(child);
                Some(child_list)
            }
        };

        match new {
            Some(child_list) => {self.parent_child.insert(parent, child_list);},
            None => (),
        }
    }
}

/// Common is a trait that your `GameData` needs to implement as the
/// root system for the entity manager.
pub trait Common {
    /// get a non-mutable pointer to the `CommonData` of `GameData`
    fn get_common<'a>(&'a self) -> &'a CommonData;
    /// get a mutable pointer to the `CommonData` from the `GameData`
    fn get_common_mut<'a>(&'a mut self) -> &'a mut CommonData;

    /// Create a new scene.
    fn new_scene(&mut self) -> Scene {
        let oid = self.new_object(None);
        self.get_common_mut().scene_children.insert(oid, StaticSet::new());
        Scene(oid)
    }

    /// Create a new object, if a parent is supplied the object
    /// is owned by the parent. This can be used to create parent-child
    /// bonding between objects
    fn new_object(&mut self, parent: Option<Entity>) -> Entity {
        let new_key = self.get_common_mut().new_key();
        let mut parent = match parent {
            Some(key) => key,
            None => 0
        };

        let object = Object {
            parent: parent
        };

        self.get_common_mut().objects.insert(new_key, object);
        self.get_common_mut().update_parent_child(parent, new_key);

        let mut scene_id = None;
        while parent != 0 {
            match self.get_common().scene_children.get(parent) {
                None => {
                    parent = self.get_common().objects.get(parent).unwrap().parent;
                }
                Some(_) => {
                    scene_id = Some(parent);
                    parent = 0;
                }
            }
        }

        match scene_id {
            Some(id) => {
                let sc = self.get_common_mut().scene_children.get_mut(id).unwrap();
                sc.insert(new_key);
            }
            None => ()
        }

        new_key
    }

    /// Create an Iterator that iterators over the scene supplied.
    fn scene_iter<'a>(&'a self, oid: Scene) -> StaticSetIterator<'a> {
        let Scene(oid) = oid;
        let sc = self.get_common().scene_children.get(oid)
            .expect("Failed to get scene");
        sc.iter()
    }

    /// Get the object metadata for Entity
    fn object<'a>(&'a self, oid: Entity) -> Option<&'a Object> {
        self.get_common().objects.get(oid)
    }
}

/// Duplicate all components owned by `src` into `dst`
pub trait Duplicate {
    fn duplicate(&mut self, src: Entity, dst: Entity);
}

/// Delete all components owned by the `Entity`
pub trait Delete {
    fn delete(&mut self, oid: Entity) -> bool;
}

impl Delete for CommonData {
    fn delete(&mut self, oid: Entity) -> bool {
        let o = self.objects.get(oid).map(|x| *x);
        match o {
            Some(o) => {
                self.freelist.make_unique().push(oid);
                self.objects.remove(oid)                      |
                self.parent_child.remove(oid)                 |
                self.scene_children.remove(oid)               |
                (self.parent_child.get_mut(o.parent)
                    .map(|x| { x.remove(oid) }) == Some(true)) |
                (self.scene_children.get_mut(o.parent)
                    .map(|x| { x.remove(oid) }) == Some(true))
            }
            None => false
        }
    }
}

impl Common for CommonData {
    fn get_common<'a>(&'a self) -> &'a CommonData {self}
    fn get_common_mut<'a>(&'a mut self) -> &'a mut CommonData {self}
}

#[derive(RustcEncodable, RustcDecodable, Copy, Clone)]
pub struct Parent<T>(pub T);

impl Get<Entity> for CommonData {
    type Value = Parent<Entity>;

    fn get(&self, key: Entity) -> Option<Parent<Entity>> {
        self.objects.get(key).map(|o| Parent(o.parent))
    }
}

impl Set<Entity, Parent<Entity>> for CommonData {
    fn set(&mut self, key: Entity, Parent(value): Parent<Entity>) {
        self.objects.get_mut(key).map(|o| {
            o.parent = value;
        });
    }
}

#[derive(RustcEncodable, RustcDecodable, Copy, Clone)]
pub struct Scene(pub Entity);

impl ToEntity for Scene {
    fn to_entity(self) -> Entity {
        let Scene(eid) = self;
        eid
    }
}<commit_msg>remove object from Common<commit_after>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::sync::Arc;
use table::{Static, StaticSet, StaticSetIterator};

use {Get, Set, ToEntity};

/// A common set of data owned by an `Entity`
#[derive(Clone, Default, RustcEncodable, RustcDecodable, Copy)]
pub struct Object {
    /// Who is the parent of this object
    pub parent: Entity,
}

/// A key to connect Entities across Systems
pub type Entity = u32;

/// CommonData is a container that contains all the information needed
/// to implement the Common root of `snowmews`'s entity systems
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct CommonData {
    last_oid:       Entity,
    objects:        Static<Object>,
    parent_child:   Static<StaticSet>,
    scene_children: Static<StaticSet>,
    freelist:       Arc<Vec<Entity>>
}

impl CommonData {
    /// Create CommonData for use with the `Common` trait
    pub fn new() -> CommonData {
        CommonData {
            last_oid: 1,
            objects: Static::new(),
            parent_child: Static::new(),
            scene_children: Static::new(),
            freelist: Arc::new(Vec::new())
        }
    }

    fn new_key(&mut self) -> Entity {
        if !self.freelist.is_empty() {
            return self.freelist.make_unique().pop().expect("missing entry...");
        }
        let new_key = self.last_oid;
        self.last_oid += 1;
        new_key
    }

    fn update_parent_child(&mut self, parent: Entity, child: Entity) {
        let new = match self.parent_child.get_mut(parent) {
            Some(child_list) => {
                child_list.insert(child);
                None
            },
            None => {
                let mut child_list = StaticSet::new();
                child_list.insert(child);
                Some(child_list)
            }
        };

        match new {
            Some(child_list) => {self.parent_child.insert(parent, child_list);},
            None => (),
        }
    }
}

/// Common is a trait that your `GameData` needs to implement as the
/// root system for the entity manager.
pub trait Common {
    /// get a non-mutable pointer to the `CommonData` of `GameData`
    fn get_common<'a>(&'a self) -> &'a CommonData;
    /// get a mutable pointer to the `CommonData` from the `GameData`
    fn get_common_mut<'a>(&'a mut self) -> &'a mut CommonData;

    /// Create a new scene.
    fn new_scene(&mut self) -> Scene {
        let oid = self.new_object(None);
        self.get_common_mut().scene_children.insert(oid, StaticSet::new());
        Scene(oid)
    }

    /// Create a new object, if a parent is supplied the object
    /// is owned by the parent. This can be used to create parent-child
    /// bonding between objects
    fn new_object(&mut self, parent: Option<Entity>) -> Entity {
        let new_key = self.get_common_mut().new_key();
        let mut parent = match parent {
            Some(key) => key,
            None => 0
        };

        let object = Object {
            parent: parent
        };

        self.get_common_mut().objects.insert(new_key, object);
        self.get_common_mut().update_parent_child(parent, new_key);

        let mut scene_id = None;
        while parent != 0 {
            match self.get_common().scene_children.get(parent) {
                None => {
                    parent = self.get_common().objects.get(parent).unwrap().parent;
                }
                Some(_) => {
                    scene_id = Some(parent);
                    parent = 0;
                }
            }
        }

        match scene_id {
            Some(id) => {
                let sc = self.get_common_mut().scene_children.get_mut(id).unwrap();
                sc.insert(new_key);
            }
            None => ()
        }

        new_key
    }

    /// Create an Iterator that iterators over the scene supplied.
    fn scene_iter<'a>(&'a self, oid: Scene) -> StaticSetIterator<'a> {
        let Scene(oid) = oid;
        let sc = self.get_common().scene_children.get(oid)
            .expect("Failed to get scene");
        sc.iter()
    }
}

/// Duplicate all components owned by `src` into `dst`
pub trait Duplicate {
    fn duplicate(&mut self, src: Entity, dst: Entity);
}

/// Delete all components owned by the `Entity`
pub trait Delete {
    fn delete(&mut self, oid: Entity) -> bool;
}

impl Delete for CommonData {
    fn delete(&mut self, oid: Entity) -> bool {
        let o = self.objects.get(oid).map(|x| *x);
        match o {
            Some(o) => {
                self.freelist.make_unique().push(oid);
                self.objects.remove(oid)                      |
                self.parent_child.remove(oid)                 |
                self.scene_children.remove(oid)               |
                (self.parent_child.get_mut(o.parent)
                    .map(|x| { x.remove(oid) }) == Some(true)) |
                (self.scene_children.get_mut(o.parent)
                    .map(|x| { x.remove(oid) }) == Some(true))
            }
            None => false
        }
    }
}

impl Common for CommonData {
    fn get_common<'a>(&'a self) -> &'a CommonData {self}
    fn get_common_mut<'a>(&'a mut self) -> &'a mut CommonData {self}
}

#[derive(RustcEncodable, RustcDecodable, Copy, Clone)]
pub struct Parent<T>(pub T);

impl Get<Entity> for CommonData {
    type Value = Parent<Entity>;

    fn get(&self, key: Entity) -> Option<Parent<Entity>> {
        self.objects.get(key).map(|o| Parent(o.parent))
    }
}

impl Set<Entity, Parent<Entity>> for CommonData {
    fn set(&mut self, key: Entity, Parent(value): Parent<Entity>) {
        self.objects.get_mut(key).map(|o| {
            o.parent = value;
        });
    }
}

#[derive(RustcEncodable, RustcDecodable, Copy, Clone)]
pub struct Scene(pub Entity);

impl ToEntity for Scene {
    fn to_entity(self) -> Entity {
        let Scene(eid) = self;
        eid
    }
}<|endoftext|>


<commit_before>

// xfail-stage0
mod test_single_attr_outer {

    #[attr = "val"]
    const int x = 10;

    #[attr = "val"]
    mod mod1 { }

    #[attr = "val"]
    native "rust" mod rustrt { }

    #[attr = "val"]
    type t = obj { };

    #[attr = "val"]
    obj o() { }
}

mod test_multi_attr_outer {

    #[attr1 = "val"]
    #[attr2 = "val"]
    const int x = 10;

    #[attr1 = "val"]
    #[attr2 = "val"]
    mod mod1 { }

    #[attr1 = "val"]
    #[attr2 = "val"]
    native "rust" mod rustrt { }

    #[attr1 = "val"]
    #[attr2 = "val"]
    type t = obj { };

    #[attr1 = "val"]
    #[attr2 = "val"]
    obj o() { }
}

fn main() { }<commit_msg>test: Add missing fn test cases to run-pass/item-attributes.rs<commit_after>// xfail-stage0

mod test_single_attr_outer {

    #[attr = "val"]
    const int x = 10;

    #[attr = "val"]
    fn f() {}

    #[attr = "val"]
    mod mod1 {
    }

    #[attr = "val"]
    native "rust" mod rustrt { }

    #[attr = "val"]
    type t = obj { };

    #[attr = "val"]
    obj o() { }
}

mod test_multi_attr_outer {

    #[attr1 = "val"]
    #[attr2 = "val"]
    const int x = 10;

    #[attr1 = "val"]
    #[attr2 = "val"]
    fn f() {}

    #[attr1 = "val"]
    #[attr2 = "val"]
    mod mod1 {
    }

    #[attr1 = "val"]
    #[attr2 = "val"]
    native "rust" mod rustrt { }

    #[attr1 = "val"]
    #[attr2 = "val"]
    type t = obj { };

    #[attr1 = "val"]
    #[attr2 = "val"]
    obj o() { }
}

fn main() { }
<|endoftext|>


<commit_before>// Figuring out the size of a vector type that depends on traits doesn't ICE

#![allow(dead_code)]

// pretty-expanded FIXME #23616

#![feature(repr_simd, platform_intrinsics, const_generics)]
#![allow(non_camel_case_types, incomplete_features)]

pub trait Simd {
    type Lane: Clone + Copy;
    const SIZE: usize;
}

pub struct i32x4;
impl Simd for i32x4 {
    type Lane = i32;
    const SIZE: usize = 4;
}

#[repr(simd)]
#[derive(Copy, Clone)]
pub struct T<S: Simd>([S::Lane; S::SIZE]); //~ ERROR constant expression depends on a generic parameter

extern "platform-intrinsic" {
    fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
    fn simd_extract<T, E>(x: T, idx: u32) -> E;
}

pub fn main() {
    let mut t = T::<i32x4>([0; 4]);
    unsafe {
        for i in 0_i32..4 {
            t = simd_insert(t, i as u32, i);
        }
        for i in 0_i32..4 {
            assert_eq!(i, simd_extract(t, i as u32));
        }
    }
}
<commit_msg>fix up tidy<commit_after>// Figuring out the size of a vector type that depends on traits doesn't ICE

#![allow(dead_code)]

// pretty-expanded FIXME #23616

#![feature(repr_simd, platform_intrinsics, const_generics)]
#![allow(non_camel_case_types, incomplete_features)]

pub trait Simd {
    type Lane: Clone + Copy;
    const SIZE: usize;
}

pub struct i32x4;
impl Simd for i32x4 {
    type Lane = i32;
    const SIZE: usize = 4;
}

#[repr(simd)]
#[derive(Copy, Clone)]
pub struct T<S: Simd>([S::Lane; S::SIZE]);
//~^ ERROR constant expression depends on a generic parameter

extern "platform-intrinsic" {
    fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
    fn simd_extract<T, E>(x: T, idx: u32) -> E;
}

pub fn main() {
    let mut t = T::<i32x4>([0; 4]);
    unsafe {
        for i in 0_i32..4 {
            t = simd_insert(t, i as u32, i);
        }
        for i in 0_i32..4 {
            assert_eq!(i, simd_extract(t, i as u32));
        }
    }
}
<|endoftext|>