<commit_before>use super::game;
use super::cards;
use super::pos;

#[derive(PartialEq)]
pub enum Target {
    Contract80,
    Contract90,
    Contract100,
    Contract110,
    Contract120,
    Contract130,
    Contract140,
    Contract150,
    Contract160,
    ContractCapot,
}

impl Target {
    pub fn score(&self) -> i32 {
        match *self {
            Target::Contract80 => 80,
            Target::Contract90 => 90,
            Target::Contract100 => 100,
            Target::Contract110 => 110,
            Target::Contract120 => 120,
            Target::Contract130 => 130,
            Target::Contract140 => 140,
            Target::Contract150 => 150,
            Target::Contract160 => 160,
            Target::ContractCapot => 250,
        }
    }

    pub fn victory(&self, score: i32, capot: bool) -> bool {
        match *self {
            Target::Contract80 => score >= 80,
            Target::Contract90 => score >= 90,
            Target::Contract100 => score >= 100,
            Target::Contract110 => score >= 110,
            Target::Contract120 => score >= 120,
            Target::Contract130 => score >= 130,
            Target::Contract140 => score >= 140,
            Target::Contract150 => score >= 150,
            Target::Contract160 => score >= 160,
            Target::ContractCapot => capot,
        }
    }
}

pub struct Contract {
    pub trump: cards::Suit,
    pub author: pos::PlayerPos,
    pub target: Target,
    pub coinche_level: i32,
}

pub struct Auction {
    history: Vec<Contract>,
    pass_count: i32,
    stopped: bool,
}

pub fn new_auction() -> Auction {
    Auction {
        history: Vec::new(),
        pass_count: 0,
        stopped: false,
    }
}

impl Auction {
    // Bid a new, higher contract.
    pub fn bid(&mut self, contract: Contract) -> Result<bool,String> {
        if self.stopped {
            return Err("auction is closed".to_string());
        }

        if !self.history.is_empty() {
            if contract.target.score() < self.history[self.history.len()-1].target.score() {
                return Err("must bid higher than current contract".to_string());
            }
        }

        self.stopped = contract.target == Target::ContractCapot;

        self.history.push(contract);
        self.pass_count = 0;

        // Only stops the bids if the guy asked for a capot
        Ok(self.stopped)
    }

    pub fn pass(&mut self) -> bool {
        self.pass_count += 1;

        // After 3 passes, we're back to the contract author, and we can start.
        self.stopped = self.pass_count == 3;

        self.stopped
    }

    pub fn coinche(&mut self) -> Result<bool,String> {
        if self.history.is_empty() {
            Err("no contract to coinche".to_string())
        } else {
            self.stopped = true;
            let i = self.history.len() - 1;
            if self.history[i].coinche_level > 1 {
                Err("constract is already sur-coinched".to_string())
            } else {
                self.history[i].coinche_level += 1;
                // Stop if we are already sur-coinching
                Ok(self.history[i].coinche_level == 2)
            }
        }
    }

    // Moves the auction to kill it
    pub fn complete(mut self, first: pos::PlayerPos) -> Result<game::GameState,String> {
        if !self.stopped {
            Err("auction is still running".to_string())
        } else if self.history.is_empty() {
            Err("no contract to start the game with".to_string())
        } else {
            Ok(game::new_game(first, self.history.pop().expect("contract history empty")))
        }
    }
}

#[test]
fn test_auction() {
    let mut auction = new_auction();

    assert!(!auction.stopped);

    assert!(!auction.pass());
    assert!(!auction.pass());
}
<commit_msg>More complete auction test<commit_after>use super::game;
use super::cards;
use super::pos;

#[derive(PartialEq)]
pub enum Target {
    Contract80,
    Contract90,
    Contract100,
    Contract110,
    Contract120,
    Contract130,
    Contract140,
    Contract150,
    Contract160,
    ContractCapot,
}

impl Target {
    pub fn score(&self) -> i32 {
        match *self {
            Target::Contract80 => 80,
            Target::Contract90 => 90,
            Target::Contract100 => 100,
            Target::Contract110 => 110,
            Target::Contract120 => 120,
            Target::Contract130 => 130,
            Target::Contract140 => 140,
            Target::Contract150 => 150,
            Target::Contract160 => 160,
            Target::ContractCapot => 250,
        }
    }

    pub fn victory(&self, score: i32, capot: bool) -> bool {
        match *self {
            Target::Contract80 => score >= 80,
            Target::Contract90 => score >= 90,
            Target::Contract100 => score >= 100,
            Target::Contract110 => score >= 110,
            Target::Contract120 => score >= 120,
            Target::Contract130 => score >= 130,
            Target::Contract140 => score >= 140,
            Target::Contract150 => score >= 150,
            Target::Contract160 => score >= 160,
            Target::ContractCapot => capot,
        }
    }
}

pub struct Contract {
    pub trump: cards::Suit,
    pub author: pos::PlayerPos,
    pub target: Target,
    pub coinche_level: i32,
}

pub struct Auction {
    history: Vec<Contract>,
    pass_count: i32,
    stopped: bool,
}

pub fn new_auction() -> Auction {
    Auction {
        history: Vec::new(),
        pass_count: 0,
        stopped: false,
    }
}

impl Auction {
    // Bid a new, higher contract.
    pub fn bid(&mut self, contract: Contract) -> Result<bool,String> {
        if self.stopped {
            return Err("auction is closed".to_string());
        }

        if !self.history.is_empty() {
            if contract.target.score() < self.history[self.history.len()-1].target.score() {
                return Err("must bid higher than current contract".to_string());
            }
        }

        self.stopped = contract.target == Target::ContractCapot;

        self.history.push(contract);
        self.pass_count = 0;

        // Only stops the bids if the guy asked for a capot
        Ok(self.stopped)
    }

    pub fn pass(&mut self) -> bool {
        self.pass_count += 1;

        // After 3 passes, we're back to the contract author, and we can start.
        let pass_limit = if !self.history.is_empty() {
            3
        } else {
            4
        };

        self.stopped = self.pass_count == pass_limit;

        self.stopped
    }

    pub fn coinche(&mut self) -> Result<bool,String> {
        if self.history.is_empty() {
            Err("no contract to coinche".to_string())
        } else {
            self.stopped = true;
            let i = self.history.len() - 1;
            if self.history[i].coinche_level > 1 {
                Err("constract is already sur-coinched".to_string())
            } else {
                self.history[i].coinche_level += 1;
                // Stop if we are already sur-coinching
                Ok(self.history[i].coinche_level == 2)
            }
        }
    }

    // Moves the auction to kill it
    pub fn complete(mut self, first: pos::PlayerPos) -> Result<game::GameState,String> {
        if !self.stopped {
            Err("auction is still running".to_string())
        } else if self.history.is_empty() {
            Err("no contract to start the game with".to_string())
        } else {
            Ok(game::new_game(first, self.history.pop().expect("contract history empty")))
        }
    }
}

#[test]
fn test_auction() {
    let mut auction = new_auction();

    assert!(!auction.stopped);

    // First three people pass.
    assert!(!auction.pass());
    assert!(!auction.pass());
    assert!(!auction.pass());

    // Someone bids.
    assert_eq!(auction.bid(Contract{
        author: pos::PlayerPos(0),
        trump: cards::HEART,
        target: Target::Contract80,
        coinche_level: 0,
    }), Ok(false));
    assert!(!auction.pass());
    // Partner surbids
    assert_eq!(auction.bid(Contract{
        author: pos::PlayerPos(0),
        trump: cards::HEART,
        target: Target::Contract100,
        coinche_level: 0,
    }), Ok(false));
    assert!(!auction.pass());
    assert!(!auction.pass());
    assert!(auction.pass());

    assert!(auction.stopped);

    match auction.complete(pos::PlayerPos(0)) {
        Err(_) => assert!(false),
        _=> {},
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Dynamic arenas.

// Arenas are used to quickly allocate objects that share a
// lifetime. The arena uses ~[u8] vectors as a backing store to
// allocate objects from. For each allocated object, the arena stores
// a pointer to the type descriptor followed by the
// object. (Potentially with alignment padding after each of them.)
// When the arena is destroyed, it iterates through all of its chunks,
// and uses the tydesc information to trace through the objects,
// calling the destructors on them.
// One subtle point that needs to be addressed is how to handle
// failures while running the user provided initializer function. It
// is important to not run the destructor on uninitialized objects, but
// how to detect them is somewhat subtle. Since alloc() can be invoked
// recursively, it is not sufficient to simply exclude the most recent
// object. To solve this without requiring extra space, we use the low
// order bit of the tydesc pointer to encode whether the object it
// describes has been fully initialized.

// As an optimization, objects with destructors are stored in
// different chunks than objects without destructors. This reduces
// overhead when initializing plain-old-data and means we don't need
// to waste time running the destructors of POD.

#[allow(missing_doc)];

use core::prelude::*;

use list::{MutList, MutCons, MutNil};

use core::at_vec;
use core::cast::{transmute, transmute_mut_region};
use core::cast;
use core::libc::size_t;
use core::ptr;
use core::sys::TypeDesc;
use core::sys;
use core::uint;
use core::vec;
use core::unstable::intrinsics;

pub mod rustrt {
    use core::libc::size_t;
    use core::sys::TypeDesc;

    pub extern {
        #[rust_stack]
        unsafe fn rust_call_tydesc_glue(root: *u8,
                                        tydesc: *TypeDesc,
                                        field: size_t);
    }
}

// This probably belongs somewhere else. Needs to be kept in sync with
// changes to glue...
static tydesc_drop_glue_index: size_t = 3 as size_t;

// The way arena uses arrays is really deeply awful. The arrays are
// allocated, and have capacities reserved, but the fill for the array
// will always stay at 0.
struct Chunk {
    data: @[u8],
    fill: uint,
    is_pod: bool,
}

pub struct Arena {
    // The head is separated out from the list as a unbenchmarked
    // microoptimization, to avoid needing to case on the list to
    // access the head.
    priv head: Chunk,
    priv pod_head: Chunk,
    priv chunks: @mut MutList<Chunk>,
}

#[unsafe_destructor]
impl Drop for Arena {
    fn finalize(&self) {
        unsafe {
            destroy_chunk(&self.head);
            for self.chunks.each |chunk| {
                if !chunk.is_pod {
                    destroy_chunk(chunk);
                }
            }
        }
    }
}

fn chunk(size: uint, is_pod: bool) -> Chunk {
    let mut v: @[u8] = @[];
    unsafe { at_vec::raw::reserve(&mut v, size); }
    Chunk {
        data: unsafe { cast::transmute(v) },
        fill: 0u,
        is_pod: is_pod,
    }
}

pub fn arena_with_size(initial_size: uint) -> Arena {
    Arena {
        head: chunk(initial_size, false),
        pod_head: chunk(initial_size, true),
        chunks: @mut MutNil,
    }
}

pub fn Arena() -> Arena {
    arena_with_size(32u)
}

#[inline]
fn round_up_to(base: uint, align: uint) -> uint {
    (base + (align - 1)) & !(align - 1)
}

// Walk down a chunk, running the destructors for any objects stored
// in it.
unsafe fn destroy_chunk(chunk: &Chunk) {
    let mut idx = 0;
    let buf = vec::raw::to_ptr(chunk.data);
    let fill = chunk.fill;

    while idx < fill {
        let tydesc_data: *uint = transmute(ptr::offset(buf, idx));
        let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
        let (size, align) = ((*tydesc).size, (*tydesc).align);

        let after_tydesc = idx + sys::size_of::<*TypeDesc>();

        let start = round_up_to(after_tydesc, align);

        //debug!("freeing object: idx = %u, size = %u, align = %u, done = %b",
        //       start, size, align, is_done);
        if is_done {
            rustrt::rust_call_tydesc_glue(
                ptr::offset(buf, start), tydesc, tydesc_drop_glue_index);
        }

        // Find where the next tydesc lives
        idx = round_up_to(start + size, sys::pref_align_of::<*TypeDesc>());
    }
}

// We encode whether the object a tydesc describes has been
// initialized in the arena in the low bit of the tydesc pointer. This
// is necessary in order to properly do cleanup if a failure occurs
// during an initializer.
#[inline]
unsafe fn bitpack_tydesc_ptr(p: *TypeDesc, is_done: bool) -> uint {
    let p_bits: uint = transmute(p);
    p_bits | (is_done as uint)
}
#[inline]
unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) {
    (transmute(p & !1), p & 1 == 1)
}

impl Arena {
    // Functions for the POD part of the arena
    fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 {
        // Allocate a new chunk.
        let chunk_size = at_vec::capacity(self.pod_head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @mut MutCons(copy self.pod_head, self.chunks);
        self.pod_head =
            chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true);

        return self.alloc_pod_inner(n_bytes, align);
    }

    #[inline]
    fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 {
        unsafe {
            // XXX: Borrow check
            let head = transmute_mut_region(&mut self.pod_head);

            let start = round_up_to(head.fill, align);
            let end = start + n_bytes;
            if end > at_vec::capacity(head.data) {
                return self.alloc_pod_grow(n_bytes, align);
            }
            head.fill = end;

            //debug!("idx = %u, size = %u, align = %u, fill = %u",
            //       start, n_bytes, align, head.fill);

            ptr::offset(vec::raw::to_ptr(head.data), start)
        }
    }

    #[inline]
    fn alloc_pod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
            let ptr: *mut T = transmute(ptr);
            intrinsics::move_val_init(&mut (*ptr), op());
            return transmute(ptr);
        }
    }

    // Functions for the non-POD part of the arena
    fn alloc_nonpod_grow(&mut self, n_bytes: uint, align: uint)
                         -> (*u8, *u8) {
        // Allocate a new chunk.
        let chunk_size = at_vec::capacity(self.head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @mut MutCons(copy self.head, self.chunks);
        self.head =
            chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false);

        return self.alloc_nonpod_inner(n_bytes, align);
    }

    #[inline]
    fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint)
                          -> (*u8, *u8) {
        unsafe {
            let head = transmute_mut_region(&mut self.head);

            let tydesc_start = head.fill;
            let after_tydesc = head.fill + sys::size_of::<*TypeDesc>();
            let start = round_up_to(after_tydesc, align);
            let end = start + n_bytes;
            if end > at_vec::capacity(head.data) {
                return self.alloc_nonpod_grow(n_bytes, align);
            }
            head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>());

            //debug!("idx = %u, size = %u, align = %u, fill = %u",
            //       start, n_bytes, align, head.fill);

            let buf = vec::raw::to_ptr(head.data);
            return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start));
        }
    }

    #[inline]
    fn alloc_nonpod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let (ty_ptr, ptr) =
                self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
            let ty_ptr: *mut uint = transmute(ty_ptr);
            let ptr: *mut T = transmute(ptr);
            // Write in our tydesc along with a bit indicating that it
            // has *not* been initialized yet.
            *ty_ptr = transmute(tydesc);
            // Actually initialize it
            intrinsics::move_val_init(&mut(*ptr), op());
            // Now that we are done, update the tydesc to indicate that
            // the object is there.
            *ty_ptr = bitpack_tydesc_ptr(tydesc, true);

            return transmute(ptr);
        }
    }

    // The external interface
    #[inline]
    pub fn alloc<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T {
        unsafe {
            // XXX: Borrow check
            let this = transmute_mut_region(self);
            if !intrinsics::needs_drop::<T>() {
                return this.alloc_pod(op);
            }
            // XXX: Borrow check
            let this = transmute_mut_region(self);
            this.alloc_nonpod(op)
        }
    }
}

#[test]
fn test_arena_destructors() {
    let mut arena = Arena();
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8] };
    }
}

#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_arena_destructors_fail() {
    let mut arena = Arena();
    // Put some stuff in the arena.
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8] };
    }
    // Now, fail while allocating
    do arena.alloc::<@int> {
        // Now fail.
        fail!();
    };
}
<commit_msg>Changed Arena API to make it usable once more.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Dynamic arenas.

// Arenas are used to quickly allocate objects that share a
// lifetime. The arena uses ~[u8] vectors as a backing store to
// allocate objects from. For each allocated object, the arena stores
// a pointer to the type descriptor followed by the
// object. (Potentially with alignment padding after each of them.)
// When the arena is destroyed, it iterates through all of its chunks,
// and uses the tydesc information to trace through the objects,
// calling the destructors on them.
// One subtle point that needs to be addressed is how to handle
// failures while running the user provided initializer function. It
// is important to not run the destructor on uninitialized objects, but
// how to detect them is somewhat subtle. Since alloc() can be invoked
// recursively, it is not sufficient to simply exclude the most recent
// object. To solve this without requiring extra space, we use the low
// order bit of the tydesc pointer to encode whether the object it
// describes has been fully initialized.

// As an optimization, objects with destructors are stored in
// different chunks than objects without destructors. This reduces
// overhead when initializing plain-old-data and means we don't need
// to waste time running the destructors of POD.

#[allow(missing_doc)];

use core::prelude::*;

use list::{MutList, MutCons, MutNil};

use core::at_vec;
use core::cast::{transmute, transmute_mut, transmute_mut_region};
use core::cast;
use core::libc::size_t;
use core::ptr;
use core::sys::TypeDesc;
use core::sys;
use core::uint;
use core::vec;
use core::unstable::intrinsics;

pub mod rustrt {
    use core::libc::size_t;
    use core::sys::TypeDesc;

    pub extern {
        #[rust_stack]
        unsafe fn rust_call_tydesc_glue(root: *u8,
                                        tydesc: *TypeDesc,
                                        field: size_t);
    }
}

// This probably belongs somewhere else. Needs to be kept in sync with
// changes to glue...
static tydesc_drop_glue_index: size_t = 3 as size_t;

// The way arena uses arrays is really deeply awful. The arrays are
// allocated, and have capacities reserved, but the fill for the array
// will always stay at 0.
struct Chunk {
    data: @[u8],
    fill: uint,
    is_pod: bool,
}

#[mutable]
pub struct Arena {
    // The head is separated out from the list as a unbenchmarked
    // microoptimization, to avoid needing to case on the list to
    // access the head.
    priv head: Chunk,
    priv pod_head: Chunk,
    priv chunks: @mut MutList<Chunk>,
}

#[unsafe_destructor]
impl Drop for Arena {
    fn finalize(&self) {
        unsafe {
            destroy_chunk(&self.head);
            for self.chunks.each |chunk| {
                if !chunk.is_pod {
                    destroy_chunk(chunk);
                }
            }
        }
    }
}

fn chunk(size: uint, is_pod: bool) -> Chunk {
    let mut v: @[u8] = @[];
    unsafe { at_vec::raw::reserve(&mut v, size); }
    Chunk {
        data: unsafe { cast::transmute(v) },
        fill: 0u,
        is_pod: is_pod,
    }
}

pub fn arena_with_size(initial_size: uint) -> Arena {
    Arena {
        head: chunk(initial_size, false),
        pod_head: chunk(initial_size, true),
        chunks: @mut MutNil,
    }
}

pub fn Arena() -> Arena {
    arena_with_size(32u)
}

#[inline]
fn round_up_to(base: uint, align: uint) -> uint {
    (base + (align - 1)) & !(align - 1)
}

// Walk down a chunk, running the destructors for any objects stored
// in it.
unsafe fn destroy_chunk(chunk: &Chunk) {
    let mut idx = 0;
    let buf = vec::raw::to_ptr(chunk.data);
    let fill = chunk.fill;

    while idx < fill {
        let tydesc_data: *uint = transmute(ptr::offset(buf, idx));
        let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
        let (size, align) = ((*tydesc).size, (*tydesc).align);

        let after_tydesc = idx + sys::size_of::<*TypeDesc>();

        let start = round_up_to(after_tydesc, align);

        //debug!("freeing object: idx = %u, size = %u, align = %u, done = %b",
        //       start, size, align, is_done);
        if is_done {
            rustrt::rust_call_tydesc_glue(
                ptr::offset(buf, start), tydesc, tydesc_drop_glue_index);
        }

        // Find where the next tydesc lives
        idx = round_up_to(start + size, sys::pref_align_of::<*TypeDesc>());
    }
}

// We encode whether the object a tydesc describes has been
// initialized in the arena in the low bit of the tydesc pointer. This
// is necessary in order to properly do cleanup if a failure occurs
// during an initializer.
#[inline]
unsafe fn bitpack_tydesc_ptr(p: *TypeDesc, is_done: bool) -> uint {
    let p_bits: uint = transmute(p);
    p_bits | (is_done as uint)
}
#[inline]
unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) {
    (transmute(p & !1), p & 1 == 1)
}

impl Arena {
    // Functions for the POD part of the arena
    fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 {
        // Allocate a new chunk.
        let chunk_size = at_vec::capacity(self.pod_head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @mut MutCons(copy self.pod_head, self.chunks);
        self.pod_head =
            chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true);

        return self.alloc_pod_inner(n_bytes, align);
    }

    #[inline]
    fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 {
        unsafe {
            // XXX: Borrow check
            let head = transmute_mut_region(&mut self.pod_head);

            let start = round_up_to(head.fill, align);
            let end = start + n_bytes;
            if end > at_vec::capacity(head.data) {
                return self.alloc_pod_grow(n_bytes, align);
            }
            head.fill = end;

            //debug!("idx = %u, size = %u, align = %u, fill = %u",
            //       start, n_bytes, align, head.fill);

            ptr::offset(vec::raw::to_ptr(head.data), start)
        }
    }

    #[inline]
    fn alloc_pod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
            let ptr: *mut T = transmute(ptr);
            intrinsics::move_val_init(&mut (*ptr), op());
            return transmute(ptr);
        }
    }

    // Functions for the non-POD part of the arena
    fn alloc_nonpod_grow(&mut self, n_bytes: uint, align: uint)
                         -> (*u8, *u8) {
        // Allocate a new chunk.
        let chunk_size = at_vec::capacity(self.head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @mut MutCons(copy self.head, self.chunks);
        self.head =
            chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false);

        return self.alloc_nonpod_inner(n_bytes, align);
    }

    #[inline]
    fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint)
                          -> (*u8, *u8) {
        unsafe {
            let head = transmute_mut_region(&mut self.head);

            let tydesc_start = head.fill;
            let after_tydesc = head.fill + sys::size_of::<*TypeDesc>();
            let start = round_up_to(after_tydesc, align);
            let end = start + n_bytes;
            if end > at_vec::capacity(head.data) {
                return self.alloc_nonpod_grow(n_bytes, align);
            }
            head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>());

            //debug!("idx = %u, size = %u, align = %u, fill = %u",
            //       start, n_bytes, align, head.fill);

            let buf = vec::raw::to_ptr(head.data);
            return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start));
        }
    }

    #[inline]
    fn alloc_nonpod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let (ty_ptr, ptr) =
                self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
            let ty_ptr: *mut uint = transmute(ty_ptr);
            let ptr: *mut T = transmute(ptr);
            // Write in our tydesc along with a bit indicating that it
            // has *not* been initialized yet.
            *ty_ptr = transmute(tydesc);
            // Actually initialize it
            intrinsics::move_val_init(&mut(*ptr), op());
            // Now that we are done, update the tydesc to indicate that
            // the object is there.
            *ty_ptr = bitpack_tydesc_ptr(tydesc, true);

            return transmute(ptr);
        }
    }

    // The external interface
    #[inline]
    pub fn alloc<'a, T>(&'a self, op: &fn() -> T) -> &'a T {
        unsafe {
            // XXX: Borrow check
            let this = transmute_mut(self);
            if intrinsics::needs_drop::<T>() {
                this.alloc_nonpod(op)
            } else {
                this.alloc_pod(op)
            }
        }
    }
}

#[test]
fn test_arena_destructors() {
    let arena = Arena();
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8] };
    }
}

#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_arena_destructors_fail() {
    let arena = Arena();
    // Put some stuff in the arena.
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8] };
    }
    // Now, fail while allocating
    do arena.alloc::<@int> {
        // Now fail.
        fail!();
    };
}
<|endoftext|>


<commit_before><commit_msg>Define initial versions of the `Producer` and `Consumer` traits, and the glue code that connects them.<commit_after><|endoftext|>


<commit_before><commit_msg>Added comment parser<commit_after><|endoftext|>


<commit_before>#[derive(Debug)]
struct ImportantExcerpt<'a> {
    part: &'a str   // if hold ref, need lifetime anno
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }

    // one of the param is self, so all return
    // lifetime is same to self
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

fn main() {
    // --- lifetime prevent dangling ref
    /*
    let r;

    {   // x not live long enough
        let x = 5;
        r = &x;
    }

    println!("r: {}", r);
    */

    // ---
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("Then longest string is {}", result);

    // --- how borrow checker helps after adding lifetime
    // annotations
    /*
    let s1 = String::from("long string is long");
    let result;

    {
        let s2 = String::from("xyz");
        result = longest(s1.as_str(), s2.as_str());
    }
    println!("Then longest string is {}", result);
    */

    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.')
        .next()
        .expect("Could not find a '.'");
    let i = ImportantExcerpt {part: first_sentence};
}

// compiler don't know if the result is ref to str1 or str2,
// so the borrow checker don't know enough info to check
// anything here. We programmers need to express our intentions
// mannually, to let borrow checker help us
// fn longest(str1: &str, str2: &str) -> &str {
// since scope is always nested, will be the shortest of str1 and str2
// need to make the lifetime of result relative to at least
// one of the args
fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
    if str1.len() > str2.len() {
        str1
    } else {
        str2
    }
}
<commit_msg>On lifetime: static.<commit_after>#[derive(Debug)]
struct ImportantExcerpt<'a> {
    part: &'a str   // if hold ref, need lifetime anno
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }

    // one of the param is self, so all return
    // lifetime is same to self
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

fn main() {
    // --- lifetime prevent dangling ref
    /*
    let r;

    {   // x not live long enough
        let x = 5;
        r = &x;
    }

    println!("r: {}", r);
    */

    // ---
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("Then longest string is {}", result);

    // --- how borrow checker helps after adding lifetime
    // annotations
    /*
    let s1 = String::from("long string is long");
    let result;

    {
        let s2 = String::from("xyz");
        result = longest(s1.as_str(), s2.as_str());
    }
    println!("Then longest string is {}", result);
    */

    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.')
        .next()
        .expect("Could not find a '.'");
    let i = ImportantExcerpt {part: first_sentence};

    // entire duration of the program
    let s: &'static str = "I have a static lifetime.";
}

// compiler don't know if the result is ref to str1 or str2,
// so the borrow checker don't know enough info to check
// anything here. We programmers need to express our intentions
// mannually, to let borrow checker help us
// fn longest(str1: &str, str2: &str) -> &str {
// since scope is always nested, will be the shortest of str1 and str2
// need to make the lifetime of result relative to at least
// one of the args
fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
    if str1.len() > str2.len() {
        str1
    } else {
        str2
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, AtomicU64, Ordering};

use num::Zero;

use {clamp, Normal3f, Point2f, Point3f, Point3i, Vector3f};
use bounds::Bounds3f;
use interaction::Interaction;
use sampler::lowdiscrepancy::radical_inverse;
use sampling::Distribution1D;
use scene::Scene;

stat_counter!("SpatialLightDistribution/Distributions created", n_created);
stat_ratio!(
    "SpatialLightDistribution/Lookups per distribution",
    n_lookups_per_distribution
);
stat_int_distribution!(
    "SpatialLightDistribution/Hash probes per lookup",
    n_probes_per_lookup
);
pub fn init_stats() {
    n_created::init();
    n_lookups_per_distribution::init();
    n_probes_per_lookup::init();
}

pub trait LightDistribution: Send + Sync {
    fn lookup<'a>(&'a self, p: &Point3f) -> &'a Distribution1D;
}

pub struct UniformLightDistribution {
    distrib: Box<Distribution1D>,
}

impl UniformLightDistribution {
    pub fn new(scene: &Scene) -> UniformLightDistribution {
        let prob = vec![1.0; scene.lights.len()];
        UniformLightDistribution {
            distrib: Box::new(Distribution1D::new(&prob[..])),
        }
    }
}

impl LightDistribution for UniformLightDistribution {
    fn lookup<'a>(&'a self, _p: &Point3f) -> &'a Distribution1D {
        &self.distrib
    }
}

// SpatialLightDistribution
const INVALID_PACKED_POS: u64 = 0xffffffffffffffff;

pub struct SpatialLightDistribution {
    scene: Arc<Scene>,
    n_voxels: [u32; 3],
    hash_table: Box<[HashEntry]>,
    hash_table_size: usize,
}

impl SpatialLightDistribution {
    pub fn new(scene: Arc<Scene>, max_voxels: u32) -> SpatialLightDistribution {
        // Compute the number of voxels so that the widest scene bounding box
        // dimension has maxVoxels voxels and the other dimensions have a number
        // of voxels so that voxels are roughly cube shaped.

        let b = scene.world_bounds();
        let diag = b.diagonal();
        let b_max = diag[b.maximum_extent()];
        let mut n_voxels = [0; 3];
        for i in 0..3 {
            n_voxels[i] = u32::max(1, f32::round(diag[i] / b_max * max_voxels as f32) as u32);
        }
        let hash_table_size = (4 * n_voxels[0] * n_voxels[1] * n_voxels[2]) as usize;
        let mut hash_table: Vec<HashEntry> = Vec::with_capacity(hash_table_size);
        for _ in 0..hash_table_size {
            hash_table.push(HashEntry {
                packed_pos: AtomicU64::new(INVALID_PACKED_POS),
                distribution: AtomicPtr::default(),
            });
        }

        info!(
            "SpatialLightDistribution: scene bounds {}, voxel res {:?}",
            b, n_voxels
        );

        SpatialLightDistribution {
            scene,
            n_voxels,
            hash_table: hash_table.into_boxed_slice(),
            hash_table_size,
        }
    }

    pub fn compute_distribution(&self, pi: &Point3i) -> Distribution1D {
        n_created::inc();
        n_lookups_per_distribution::inc_total();
        // Compute the world-space bounding box of the voxel corresponding to
        // |pi|.
        let p0 = Point3f::new(
            pi[0] as f32 / self.n_voxels[0] as f32,
            pi[1] as f32 / self.n_voxels[1] as f32,
            pi[2] as f32 / self.n_voxels[2] as f32,
        );
        let p1 = Point3f::new(
            (pi[0] as f32 + 1.0) / self.n_voxels[0] as f32,
            (pi[1] as f32 + 1.0) / self.n_voxels[1] as f32,
            (pi[2] as f32 + 1.0) / self.n_voxels[2] as f32,
        );
        let voxel_bounds = Bounds3f::from_points(
            &self.scene.world_bounds().lerp(&p0),
            &self.scene.world_bounds().lerp(&p1),
        );

        // Compute the sampling distribution. Sample a number of points inside
        // voxelBounds using a 3D Halton sequence; at each one, sample each
        // light source and compute a weight based on Li/pdf for the light's
        // sample (ignoring visibility between the point in the voxel and the
        // point on the light source) as an approximation to how much the light
        // is likely to contribute to illumination in the voxel.
        let n_samples = 128;
        let mut light_contrib: Vec<f32> = vec![0.0; self.scene.lights.len()];
        for i in 0..n_samples {
            let po = voxel_bounds.lerp(&Point3f::new(
                radical_inverse(0, i),
                radical_inverse(1, i),
                radical_inverse(2, i),
            ));
            let intr = Interaction::new(
                po,
                Vector3f::zero(),
                Vector3f::new(1.0, 0.0, 0.0),
                Normal3f::zero(),
            );

            // Use the next two Halton dimensions to sample a point on the
            // light source.
            let u = Point2f::new(radical_inverse(3, i), radical_inverse(4, i));
            for j in 0..self.scene.lights.len() {
                let (li, _wi, pdf, _vis) = self.scene.lights[j].sample_li(&intr, &u);
                if pdf > 0.0 {
                    // TODO: look at tracing shadow rays / computing beam
                    // transmittance.  Probably shouldn't give those full weight
                    // but instead e.g. have an occluded shadow ray scale down
                    // the contribution by 10 or something.
                    light_contrib[j] += li.y() / pdf;
                }
            }
        }

        // We don't want to leave any lights with a zero probability; it's
        // possible that a light contributes to points in the voxel even though
        // we didn't find such a point when sampling above.  Therefore, compute
        // a minimum (small) weight and ensure that all lights are given at
        // least the corresponding probability.
        let sum_contrib: f32 = light_contrib.iter().sum();
        let avg_contrib = sum_contrib / (n_samples * light_contrib.len() as u64) as f32;
        let min_contrib = if avg_contrib > 0.0 {
            0.001 * avg_contrib
        } else {
            1.0
        };
        for i in 0..light_contrib.len() {
            light_contrib[i] = f32::max(light_contrib[i], min_contrib);
        }

        info!(
            "Initialized light distribution in voxel pi={}, avg_contrib={}",
            pi, avg_contrib
        );
        // Compute a sampling distribution from the accumulated contributions.
        Distribution1D::new(&light_contrib[..])
    }
}

impl LightDistribution for SpatialLightDistribution {
    fn lookup<'a>(&'a self, p: &Point3f) -> &'a Distribution1D {
        n_lookups_per_distribution::inc();
        // First compute integer voxel coordinates for the given point |p|
        // with respect to the overall voxel grid.
        let offset = self.scene.world_bounds().offset(p);
        let mut pi = Point3i::zero();
        for i in 0..3 {
            // The clamp should almost never be necessary, but is there to be
            // robust to computed intersection points being slightly outside
            // the scene bounds due to floating-point roundoff error.
            pi[i] = clamp(
                (offset[i] * self.n_voxels[i] as f32) as i32,
                0,
                self.n_voxels[i] as i32 - 1,
            );
        }

        // Pack the 3D integer voxel coordinates into a single 64-bit value.
        let packed_pos: u64 = (pi[0] as u64) << 40 | (pi[1] as u64) << 20 | (pi[2] as u64);
        assert_ne!(packed_pos, INVALID_PACKED_POS);

        // Compute a hash value from the packed voxel coordinates.  We could
        // just take packedPos mod the hash table size, but since packedPos
        // isn't necessarily well distributed on its own, it's worthwhile to do
        // a little work to make sure that its bits values are individually
        // fairly random. For details of and motivation for the following, see:
        // http://zimbry.blogspot.ch/2011/09/better-bit-mixing-improving-on.html
        let mut hash = packed_pos;
        hash ^= hash >> 31;
        hash *= 0x7fb5d329728ea185;
        hash ^= hash >> 27;
        hash *= 0x81dadef4bc2dd44d;
        hash ^= hash >> 33;
        hash %= self.hash_table_size as u64;

        // Now, see if the hash table already has an entry for the voxel. We'll
        // use quadratic probing when the hash table entry is already used for
        // another value; step stores the square root of the probe step.
        let mut step = 1;
        let mut n_probes: u64 = 0;
        loop {
            n_probes += 1;
            let entry = &self.hash_table[hash as usize];
            // Does the hash table entry at offset |hash| match the current point?
            let entry_packed_pos = entry.packed_pos.load(Ordering::Acquire);
            if entry_packed_pos == packed_pos {
                // Yes! Most of the time, there should already by a light
                // sampling distribution available.
                let mut dist = entry.distribution.load(Ordering::Acquire);
                if dist.is_null() {
                    // Rarely, another thread will have already done a lookup
                    // at this point, found that there isn't a sampling
                    // distribution, and will already be computing the
                    // distribution for the point.  In this case, we spin until
                    // the sampling distribution is ready.  We assume that this
                    // is a rare case, so don't do anything more sophisticated
                    // than spinning.
                    loop {
                        dist = entry.distribution.load(Ordering::Acquire);
                        if !dist.is_null() {
                            break;
                        }
                        // spin :-(. If we were fancy, we'd have any threads
                        // that hit this instead help out with computing the
                        // distribution for the voxel...
                    }
                }
                unsafe {
                    // We have a valid sampling distribution.
                    n_probes_per_lookup::report_value(n_probes);
                    return dist.as_ref().unwrap();
                }
            } else if entry_packed_pos != INVALID_PACKED_POS {
                // The hash table entry we're checking has already been
                // allocated for another voxel. Advance to the next entry with
                // quadratic probing.
                hash += step * step;
                if hash >= self.hash_table_size as u64 {
                    hash %= self.hash_table_size as u64;
                }
                step += 1;
            } else {
                // We have found an invalid entry. (Though this may have
                // changed since the load into entryPackedPos above.)  Use an
                // atomic compare/exchange to try to claim this entry for the
                // current position.
                if entry
                    .packed_pos
                    .compare_exchange_weak(
                        INVALID_PACKED_POS,
                        packed_pos,
                        Ordering::SeqCst,
                        Ordering::SeqCst,
                    )
                    .is_ok()
                {
                    // Success; we've claimed this position for this voxel's
                    // distribution. Now compute the sampling distribution and
                    // add it to the hash table. As long as packedPos has been
                    // set but the entry's distribution pointer is nullptr, any
                    // other threads looking up the distribution for this voxel
                    // will spin wait until the distribution pointer is
                    // written.
                    let distrib = Box::new(self.compute_distribution(&pi));
                    let distrib_ptr = Box::into_raw(distrib);
                    entry.distribution.store(distrib_ptr, Ordering::Release);
                    unsafe {
                        n_probes_per_lookup::report_value(n_probes);
                        return distrib_ptr.as_ref().unwrap();
                    }
                }
            }
        }
    }
}

// TODO implement Drop?

struct HashEntry {
    pub packed_pos: AtomicU64,
    pub distribution: AtomicPtr<Distribution1D>,
}
<commit_msg>Avoid overflow panics in debug mode.<commit_after>use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, AtomicU64, Ordering};
use std::num::Wrapping;

use num::Zero;

use {clamp, Normal3f, Point2f, Point3f, Point3i, Vector3f};
use bounds::Bounds3f;
use interaction::Interaction;
use sampler::lowdiscrepancy::radical_inverse;
use sampling::Distribution1D;
use scene::Scene;

stat_counter!("SpatialLightDistribution/Distributions created", n_created);
stat_ratio!(
    "SpatialLightDistribution/Lookups per distribution",
    n_lookups_per_distribution
);
stat_int_distribution!(
    "SpatialLightDistribution/Hash probes per lookup",
    n_probes_per_lookup
);
pub fn init_stats() {
    n_created::init();
    n_lookups_per_distribution::init();
    n_probes_per_lookup::init();
}

pub trait LightDistribution: Send + Sync {
    fn lookup<'a>(&'a self, p: &Point3f) -> &'a Distribution1D;
}

pub struct UniformLightDistribution {
    distrib: Box<Distribution1D>,
}

impl UniformLightDistribution {
    pub fn new(scene: &Scene) -> UniformLightDistribution {
        let prob = vec![1.0; scene.lights.len()];
        UniformLightDistribution {
            distrib: Box::new(Distribution1D::new(&prob[..])),
        }
    }
}

impl LightDistribution for UniformLightDistribution {
    fn lookup<'a>(&'a self, _p: &Point3f) -> &'a Distribution1D {
        &self.distrib
    }
}

// SpatialLightDistribution
const INVALID_PACKED_POS: u64 = 0xffffffffffffffff;

pub struct SpatialLightDistribution {
    scene: Arc<Scene>,
    n_voxels: [u32; 3],
    hash_table: Box<[HashEntry]>,
    hash_table_size: usize,
}

impl SpatialLightDistribution {
    pub fn new(scene: Arc<Scene>, max_voxels: u32) -> SpatialLightDistribution {
        // Compute the number of voxels so that the widest scene bounding box
        // dimension has maxVoxels voxels and the other dimensions have a number
        // of voxels so that voxels are roughly cube shaped.

        let b = scene.world_bounds();
        let diag = b.diagonal();
        let b_max = diag[b.maximum_extent()];
        let mut n_voxels = [0; 3];
        for i in 0..3 {
            n_voxels[i] = u32::max(1, f32::round(diag[i] / b_max * max_voxels as f32) as u32);
        }
        let hash_table_size = (4 * n_voxels[0] * n_voxels[1] * n_voxels[2]) as usize;
        let mut hash_table: Vec<HashEntry> = Vec::with_capacity(hash_table_size);
        for _ in 0..hash_table_size {
            hash_table.push(HashEntry {
                packed_pos: AtomicU64::new(INVALID_PACKED_POS),
                distribution: AtomicPtr::default(),
            });
        }

        info!(
            "SpatialLightDistribution: scene bounds {}, voxel res {:?}",
            b, n_voxels
        );

        SpatialLightDistribution {
            scene,
            n_voxels,
            hash_table: hash_table.into_boxed_slice(),
            hash_table_size,
        }
    }

    pub fn compute_distribution(&self, pi: &Point3i) -> Distribution1D {
        n_created::inc();
        n_lookups_per_distribution::inc_total();
        // Compute the world-space bounding box of the voxel corresponding to
        // |pi|.
        let p0 = Point3f::new(
            pi[0] as f32 / self.n_voxels[0] as f32,
            pi[1] as f32 / self.n_voxels[1] as f32,
            pi[2] as f32 / self.n_voxels[2] as f32,
        );
        let p1 = Point3f::new(
            (pi[0] as f32 + 1.0) / self.n_voxels[0] as f32,
            (pi[1] as f32 + 1.0) / self.n_voxels[1] as f32,
            (pi[2] as f32 + 1.0) / self.n_voxels[2] as f32,
        );
        let voxel_bounds = Bounds3f::from_points(
            &self.scene.world_bounds().lerp(&p0),
            &self.scene.world_bounds().lerp(&p1),
        );

        // Compute the sampling distribution. Sample a number of points inside
        // voxelBounds using a 3D Halton sequence; at each one, sample each
        // light source and compute a weight based on Li/pdf for the light's
        // sample (ignoring visibility between the point in the voxel and the
        // point on the light source) as an approximation to how much the light
        // is likely to contribute to illumination in the voxel.
        let n_samples = 128;
        let mut light_contrib: Vec<f32> = vec![0.0; self.scene.lights.len()];
        for i in 0..n_samples {
            let po = voxel_bounds.lerp(&Point3f::new(
                radical_inverse(0, i),
                radical_inverse(1, i),
                radical_inverse(2, i),
            ));
            let intr = Interaction::new(
                po,
                Vector3f::zero(),
                Vector3f::new(1.0, 0.0, 0.0),
                Normal3f::zero(),
            );

            // Use the next two Halton dimensions to sample a point on the
            // light source.
            let u = Point2f::new(radical_inverse(3, i), radical_inverse(4, i));
            for j in 0..self.scene.lights.len() {
                let (li, _wi, pdf, _vis) = self.scene.lights[j].sample_li(&intr, &u);
                if pdf > 0.0 {
                    // TODO: look at tracing shadow rays / computing beam
                    // transmittance.  Probably shouldn't give those full weight
                    // but instead e.g. have an occluded shadow ray scale down
                    // the contribution by 10 or something.
                    light_contrib[j] += li.y() / pdf;
                }
            }
        }

        // We don't want to leave any lights with a zero probability; it's
        // possible that a light contributes to points in the voxel even though
        // we didn't find such a point when sampling above.  Therefore, compute
        // a minimum (small) weight and ensure that all lights are given at
        // least the corresponding probability.
        let sum_contrib: f32 = light_contrib.iter().sum();
        let avg_contrib = sum_contrib / (n_samples * light_contrib.len() as u64) as f32;
        let min_contrib = if avg_contrib > 0.0 {
            0.001 * avg_contrib
        } else {
            1.0
        };
        for i in 0..light_contrib.len() {
            light_contrib[i] = f32::max(light_contrib[i], min_contrib);
        }

        info!(
            "Initialized light distribution in voxel pi={}, avg_contrib={}",
            pi, avg_contrib
        );
        // Compute a sampling distribution from the accumulated contributions.
        Distribution1D::new(&light_contrib[..])
    }
}

impl LightDistribution for SpatialLightDistribution {
    fn lookup<'a>(&'a self, p: &Point3f) -> &'a Distribution1D {
        n_lookups_per_distribution::inc();
        // First compute integer voxel coordinates for the given point |p|
        // with respect to the overall voxel grid.
        let offset = self.scene.world_bounds().offset(p);
        let mut pi = Point3i::zero();
        for i in 0..3 {
            // The clamp should almost never be necessary, but is there to be
            // robust to computed intersection points being slightly outside
            // the scene bounds due to floating-point roundoff error.
            pi[i] = clamp(
                (offset[i] * self.n_voxels[i] as f32) as i32,
                0,
                self.n_voxels[i] as i32 - 1,
            );
        }

        // Pack the 3D integer voxel coordinates into a single 64-bit value.
        let packed_pos: u64 = (pi[0] as u64) << 40 | (pi[1] as u64) << 20 | (pi[2] as u64);
        assert_ne!(packed_pos, INVALID_PACKED_POS);

        // Compute a hash value from the packed voxel coordinates.  We could
        // just take packedPos mod the hash table size, but since packedPos
        // isn't necessarily well distributed on its own, it's worthwhile to do
        // a little work to make sure that its bits values are individually
        // fairly random. For details of and motivation for the following, see:
        // http://zimbry.blogspot.ch/2011/09/better-bit-mixing-improving-on.html
        let mut hash = Wrapping(packed_pos);
        hash ^= hash >> 31;
        hash *= Wrapping(0x7fb5d329728ea185);
        hash ^= hash >> 27;
        hash *= Wrapping(0x81dadef4bc2dd44d);
        hash ^= hash >> 33;
        hash %= Wrapping(self.hash_table_size as u64);

        // Now, see if the hash table already has an entry for the voxel. We'll
        // use quadratic probing when the hash table entry is already used for
        // another value; step stores the square root of the probe step.
        let mut step = 1;
        let mut n_probes: u64 = 0;
        loop {
            n_probes += 1;
            let entry = &self.hash_table[hash.0 as usize];
            // Does the hash table entry at offset |hash| match the current point?
            let entry_packed_pos = entry.packed_pos.load(Ordering::Acquire);
            if entry_packed_pos == packed_pos {
                // Yes! Most of the time, there should already by a light
                // sampling distribution available.
                let mut dist = entry.distribution.load(Ordering::Acquire);
                if dist.is_null() {
                    // Rarely, another thread will have already done a lookup
                    // at this point, found that there isn't a sampling
                    // distribution, and will already be computing the
                    // distribution for the point.  In this case, we spin until
                    // the sampling distribution is ready.  We assume that this
                    // is a rare case, so don't do anything more sophisticated
                    // than spinning.
                    loop {
                        dist = entry.distribution.load(Ordering::Acquire);
                        if !dist.is_null() {
                            break;
                        }
                        // spin :-(. If we were fancy, we'd have any threads
                        // that hit this instead help out with computing the
                        // distribution for the voxel...
                    }
                }
                unsafe {
                    // We have a valid sampling distribution.
                    n_probes_per_lookup::report_value(n_probes);
                    return dist.as_ref().unwrap();
                }
            } else if entry_packed_pos != INVALID_PACKED_POS {
                // The hash table entry we're checking has already been
                // allocated for another voxel. Advance to the next entry with
                // quadratic probing.
                hash += Wrapping(step * step);
                if hash.0 >= self.hash_table_size as u64 {
                    hash %= Wrapping(self.hash_table_size as u64);
                }
                step += 1;
            } else {
                // We have found an invalid entry. (Though this may have
                // changed since the load into entryPackedPos above.)  Use an
                // atomic compare/exchange to try to claim this entry for the
                // current position.
                if entry
                    .packed_pos
                    .compare_exchange_weak(
                        INVALID_PACKED_POS,
                        packed_pos,
                        Ordering::SeqCst,
                        Ordering::SeqCst,
                    )
                    .is_ok()
                {
                    // Success; we've claimed this position for this voxel's
                    // distribution. Now compute the sampling distribution and
                    // add it to the hash table. As long as packedPos has been
                    // set but the entry's distribution pointer is nullptr, any
                    // other threads looking up the distribution for this voxel
                    // will spin wait until the distribution pointer is
                    // written.
                    let distrib = Box::new(self.compute_distribution(&pi));
                    let distrib_ptr = Box::into_raw(distrib);
                    entry.distribution.store(distrib_ptr, Ordering::Release);
                    unsafe {
                        n_probes_per_lookup::report_value(n_probes);
                        return distrib_ptr.as_ref().unwrap();
                    }
                }
            }
        }
    }
}

// TODO implement Drop?

struct HashEntry {
    pub packed_pos: AtomicU64,
    pub distribution: AtomicPtr<Distribution1D>,
}
<|endoftext|>


<commit_before>//! Compares the decoding results with reference renderings.

extern crate crc32fast;
extern crate glob;
extern crate image;

use std::fs;
use std::io;
use std::path::PathBuf;
use std::u32;

use crc32fast::Hasher as Crc32;

const BASE_PATH: [&str; 2] = [".", "tests"];
const IMAGE_DIR: &str = "images";
const OUTPUT_DIR: &str = "output";
const REFERENCE_DIR: &str = "reference";

fn process_images<F>(dir: &str, input_decoder: Option<&str>, func: F)
where
    F: Fn(&PathBuf, PathBuf, &str),
{
    let base: PathBuf = BASE_PATH.iter().collect();
    let decoders = &["tga", "tiff", "png", "gif", "bmp", "ico", "jpg", "hdr", "pbm", "webp"];
    for decoder in decoders {
        let mut path = base.clone();
        path.push(dir);
        path.push(decoder);
        path.push("**");
        path.push(
            "*.".to_string() + match input_decoder {
                Some(val) => val,
                None => decoder,
            },
        );
        let pattern = &*format!("{}", path.display());
        for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
            func(&base, path, decoder)
        }
    }
}

#[cfg(feature = "png")]
#[test]
fn render_images() {
    process_images(IMAGE_DIR, None, |base, path, decoder| {
        println!("render_images {}", path.display());
        let img = match image::open(&path) {
            Ok(img) => img.to_rgba(),
            // Do not fail on unsupported error
            // This might happen because the testsuite contains unsupported images
            // or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(e)) => {
                println!("UNSUPPORTED {}: {}", path.display(), e);
                return;
            }
            Err(err) => panic!(format!("decoding of {:?} failed with: {}", path, err)),
        };
        let mut crc = Crc32::new();
        crc.update(&*img);

        let (filename, testsuite) = {
            let mut path: Vec<_> = path.components().collect();
            (path.pop().unwrap(), path.pop().unwrap())
        };
        let mut out_path = base.clone();

        out_path.push(OUTPUT_DIR);
        out_path.push(decoder);
        out_path.push(testsuite.as_os_str());
        fs::create_dir_all(&out_path).unwrap();
        out_path.push(format!(
            "{}.{}.{}",
            filename.as_os_str().to_str().unwrap(),
            format!("{:x}", crc.finalize()),
            "png"
        ));
        img.save(out_path).unwrap();
    })
}

#[test]
fn check_references() {
    process_images(REFERENCE_DIR, Some("png"), |base, path, decoder| {
        println!("check_references {}", path.display());

        let ref_img = match image::open(&path) {
            Ok(img) => img.to_rgba(),
            // Do not fail on unsupported error
            // This might happen because the testsuite contains unsupported images
            // or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(_)) => return,
            Err(err) => panic!(format!("{}", err)),
        };

        let (filename, testsuite) = {
            let mut path: Vec<_> = path.components().collect();
            (path.pop().unwrap(), path.pop().unwrap())
        };

        let mut filename_parts = filename
            .as_os_str()
            .to_str()
            .unwrap()
            .split('.')
            .collect::<Vec<_>>();

        // Ignore the file extension
        filename_parts.pop().unwrap();

        // The penultimate part of `filename_parts` represents the metadata.
        let meta_str = filename_parts.pop().unwrap();
        let mut meta = meta_str.split('_').collect::<Vec<_>>();
        let ref_crc;
        let anim_frame: Option<usize>;

        if meta.len() == 1 {
            // `CRC`
            ref_crc = meta.pop().unwrap();
            anim_frame = None;
        } else if meta.len() == 3 && meta[0] == "anim" {
            // `anim_FRAME_CRC`
            ref_crc = meta.pop().unwrap();
            let frame: usize = meta.pop().unwrap().parse().unwrap();
            anim_frame = Some(frame.checked_sub(1).expect("frame number cannot be 0"));
        } else {
            panic!(
                "unrecognized reference image metadata format: {:?}",
                meta_str
            );
        }

        // The remaining part represents the original file name
        let orig_filename = filename_parts.join(".");

        // Check the reference image's CRC
        let ref_crc = u32::from_str_radix(ref_crc, 16).unwrap();

        let ref_crc_actual = {
            let mut hasher = Crc32::new();
            hasher.update(&*ref_img);
            hasher.finalize()
        };

        if ref_crc_actual != ref_crc {
            panic!(
                "Reference rendering hash check failed (expected = {:08x}, actual = {:08x}).",
                ref_crc, ref_crc_actual
            );
        }

        let mut img_path = base.clone();
        img_path.push(IMAGE_DIR);
        img_path.push(decoder);
        img_path.push(testsuite.as_os_str());
        img_path.push(orig_filename);

        // Load the test image
        let test_img;

        if let Some(anim_frame) = anim_frame {
            #[cfg(feature = "gif_codec")]
            {
                // Interpret the input file as an animation file and extract a
                // single frame
                use image::AnimationDecoder;
                let stream = io::BufReader::new(fs::File::open(&img_path).unwrap());
                let decoder = match image::gif::Decoder::new(stream) {
                    Ok(decoder) => decoder,
                    Err(image::ImageError::UnsupportedError(_)) => return,
                    Err(err) => panic!(format!("decoding of {:?} failed with: {}", img_path, err)),
                };

                let mut frames = match decoder.into_frames().collect_frames() {
                    Ok(frames) => frames,
                    Err(image::ImageError::UnsupportedError(_)) => return,
                    Err(err) => panic!(format!(
                        "collecting frames of {:?} failed with: {}",
                        img_path, err
                    )),
                };

                let frame = frames.drain(anim_frame..).nth(0).unwrap();

                // Convert the frame to a`RgbaImage`
                test_img = frame.into_buffer();
            }

            #[cfg(not(feature = "gif_codec"))]
            {
                println!("Skipping - GIF codec is not enabled");
                return;
            }
        } else {
            // Read the input file as a single image
            match image::open(&img_path) {
                Ok(img) => test_img = img.to_rgba(),
                // Do not fail on unsupported error
                // This might happen because the testsuite contains unsupported images
                // or because a specific decoder included via a feature.
                Err(image::ImageError::UnsupportedError(_)) => return,
                Err(err) => panic!(format!("decoding of {:?} failed with: {}", img_path, err)),
            };
        }

        let ref_img = coalesce_transparent_pixels(ref_img);
        let test_img = coalesce_transparent_pixels(test_img);

        if *ref_img != *test_img {
            panic!("Reference rendering does not match.");
        }
    })
}

/// Replace transparent pixel values with a single value. This is useful for
/// disregarding differences in the RGB values of completely transparent pixels.
fn coalesce_transparent_pixels(mut img: image::RgbaImage) -> image::RgbaImage {
    for p in img.pixels_mut() {
        if p[3] == 0 {
            *p = image::Rgba([0, 0, 0, 0]);
        }
    }
    img
}

#[cfg(feature = "hdr")]
#[test]
fn check_hdr_references() {
    let mut ref_path: PathBuf = BASE_PATH.iter().collect();
    ref_path.push(REFERENCE_DIR);
    ref_path.push("hdr");
    let mut path: PathBuf = BASE_PATH.iter().collect();
    path.push(IMAGE_DIR);
    path.push("hdr");
    path.push("*");
    path.push("*.hdr");
    let pattern = &*format!("{}", path.display());
    for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
        use std::path::Component::Normal;
        let mut ref_path = ref_path.clone();
        // append 2 last components of image path to reference path
        for c in path.components()
            .rev()
            .take(2)
            .collect::<Vec<_>>()
            .iter()
            .rev()
        {
            match *c {
                Normal(name) => ref_path.push(name),
                _ => panic!(),
            }
        }
        ref_path.set_extension("raw");
        println!("{}", ref_path.display());
        println!("{}", path.display());
        let decoder = image::hdr::HDRDecoder::new(io::BufReader::new(
            fs::File::open(&path).unwrap(),
        )).unwrap();
        let decoded = decoder.read_image_hdr().unwrap();
        let reference = image::hdr::read_raw_file(&ref_path).unwrap();
        assert_eq!(decoded, reference);
    }
}

/// Check that BMP files with large values could cause OOM issues are rejected.
///
/// The images are postfixed with `bad_bmp` to not be loaded by the other test.
#[test]
fn bad_bmps() {
    let path: PathBuf = BASE_PATH
        .iter()
        .collect::<PathBuf>()
        .join(IMAGE_DIR)
        .join("bmp/images")
        .join("*.bad_bmp");

    let pattern = &*format!("{}", path.display());
    for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
        let im = image::open(path);
        assert!(im.is_err());
    }
}
<commit_msg>Compare RGB values of transparent pixels (again)<commit_after>//! Compares the decoding results with reference renderings.

extern crate crc32fast;
extern crate glob;
extern crate image;

use std::fs;
use std::io;
use std::path::PathBuf;
use std::u32;

use crc32fast::Hasher as Crc32;

const BASE_PATH: [&str; 2] = [".", "tests"];
const IMAGE_DIR: &str = "images";
const OUTPUT_DIR: &str = "output";
const REFERENCE_DIR: &str = "reference";

fn process_images<F>(dir: &str, input_decoder: Option<&str>, func: F)
where
    F: Fn(&PathBuf, PathBuf, &str),
{
    let base: PathBuf = BASE_PATH.iter().collect();
    let decoders = &["tga", "tiff", "png", "gif", "bmp", "ico", "jpg", "hdr", "pbm", "webp"];
    for decoder in decoders {
        let mut path = base.clone();
        path.push(dir);
        path.push(decoder);
        path.push("**");
        path.push(
            "*.".to_string() + match input_decoder {
                Some(val) => val,
                None => decoder,
            },
        );
        let pattern = &*format!("{}", path.display());
        for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
            func(&base, path, decoder)
        }
    }
}

#[cfg(feature = "png")]
#[test]
fn render_images() {
    process_images(IMAGE_DIR, None, |base, path, decoder| {
        println!("render_images {}", path.display());
        let img = match image::open(&path) {
            Ok(img) => img.to_rgba(),
            // Do not fail on unsupported error
            // This might happen because the testsuite contains unsupported images
            // or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(e)) => {
                println!("UNSUPPORTED {}: {}", path.display(), e);
                return;
            }
            Err(err) => panic!(format!("decoding of {:?} failed with: {}", path, err)),
        };
        let mut crc = Crc32::new();
        crc.update(&*img);

        let (filename, testsuite) = {
            let mut path: Vec<_> = path.components().collect();
            (path.pop().unwrap(), path.pop().unwrap())
        };
        let mut out_path = base.clone();

        out_path.push(OUTPUT_DIR);
        out_path.push(decoder);
        out_path.push(testsuite.as_os_str());
        fs::create_dir_all(&out_path).unwrap();
        out_path.push(format!(
            "{}.{}.{}",
            filename.as_os_str().to_str().unwrap(),
            format!("{:x}", crc.finalize()),
            "png"
        ));
        img.save(out_path).unwrap();
    })
}

#[test]
fn check_references() {
    process_images(REFERENCE_DIR, Some("png"), |base, path, decoder| {
        println!("check_references {}", path.display());

        let ref_img = match image::open(&path) {
            Ok(img) => img.to_rgba(),
            // Do not fail on unsupported error
            // This might happen because the testsuite contains unsupported images
            // or because a specific decoder included via a feature.
            Err(image::ImageError::UnsupportedError(_)) => return,
            Err(err) => panic!(format!("{}", err)),
        };

        let (filename, testsuite) = {
            let mut path: Vec<_> = path.components().collect();
            (path.pop().unwrap(), path.pop().unwrap())
        };

        let mut filename_parts = filename
            .as_os_str()
            .to_str()
            .unwrap()
            .split('.')
            .collect::<Vec<_>>();

        // Ignore the file extension
        filename_parts.pop().unwrap();

        // The penultimate part of `filename_parts` represents the metadata.
        let meta_str = filename_parts.pop().unwrap();
        let mut meta = meta_str.split('_').collect::<Vec<_>>();
        let ref_crc;
        let anim_frame: Option<usize>;

        if meta.len() == 1 {
            // `CRC`
            ref_crc = meta.pop().unwrap();
            anim_frame = None;
        } else if meta.len() == 3 && meta[0] == "anim" {
            // `anim_FRAME_CRC`
            ref_crc = meta.pop().unwrap();
            let frame: usize = meta.pop().unwrap().parse().unwrap();
            anim_frame = Some(frame.checked_sub(1).expect("frame number cannot be 0"));
        } else {
            panic!(
                "unrecognized reference image metadata format: {:?}",
                meta_str
            );
        }

        // The remaining part represents the original file name
        let orig_filename = filename_parts.join(".");

        // Check the reference image's CRC
        let ref_crc = u32::from_str_radix(ref_crc, 16).unwrap();

        let ref_crc_actual = {
            let mut hasher = Crc32::new();
            hasher.update(&*ref_img);
            hasher.finalize()
        };

        if ref_crc_actual != ref_crc {
            panic!(
                "Reference rendering hash check failed (expected = {:08x}, actual = {:08x}).",
                ref_crc, ref_crc_actual
            );
        }

        let mut img_path = base.clone();
        img_path.push(IMAGE_DIR);
        img_path.push(decoder);
        img_path.push(testsuite.as_os_str());
        img_path.push(orig_filename);

        // Load the test image
        let test_img;

        if let Some(anim_frame) = anim_frame {
            #[cfg(feature = "gif_codec")]
            {
                // Interpret the input file as an animation file and extract a
                // single frame
                use image::AnimationDecoder;
                let stream = io::BufReader::new(fs::File::open(&img_path).unwrap());
                let decoder = match image::gif::Decoder::new(stream) {
                    Ok(decoder) => decoder,
                    Err(image::ImageError::UnsupportedError(_)) => return,
                    Err(err) => panic!(format!("decoding of {:?} failed with: {}", img_path, err)),
                };

                let mut frames = match decoder.into_frames().collect_frames() {
                    Ok(frames) => frames,
                    Err(image::ImageError::UnsupportedError(_)) => return,
                    Err(err) => panic!(format!(
                        "collecting frames of {:?} failed with: {}",
                        img_path, err
                    )),
                };

                let frame = frames.drain(anim_frame..).nth(0).unwrap();

                // Convert the frame to a`RgbaImage`
                test_img = frame.into_buffer();
            }

            #[cfg(not(feature = "gif_codec"))]
            {
                println!("Skipping - GIF codec is not enabled");
                return;
            }
        } else {
            // Read the input file as a single image
            match image::open(&img_path) {
                Ok(img) => test_img = img.to_rgba(),
                // Do not fail on unsupported error
                // This might happen because the testsuite contains unsupported images
                // or because a specific decoder included via a feature.
                Err(image::ImageError::UnsupportedError(_)) => return,
                Err(err) => panic!(format!("decoding of {:?} failed with: {}", img_path, err)),
            };
        }

        if *ref_img != *test_img {
            panic!("Reference rendering does not match.");
        }
    })
}

#[cfg(feature = "hdr")]
#[test]
fn check_hdr_references() {
    let mut ref_path: PathBuf = BASE_PATH.iter().collect();
    ref_path.push(REFERENCE_DIR);
    ref_path.push("hdr");
    let mut path: PathBuf = BASE_PATH.iter().collect();
    path.push(IMAGE_DIR);
    path.push("hdr");
    path.push("*");
    path.push("*.hdr");
    let pattern = &*format!("{}", path.display());
    for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
        use std::path::Component::Normal;
        let mut ref_path = ref_path.clone();
        // append 2 last components of image path to reference path
        for c in path.components()
            .rev()
            .take(2)
            .collect::<Vec<_>>()
            .iter()
            .rev()
        {
            match *c {
                Normal(name) => ref_path.push(name),
                _ => panic!(),
            }
        }
        ref_path.set_extension("raw");
        println!("{}", ref_path.display());
        println!("{}", path.display());
        let decoder = image::hdr::HDRDecoder::new(io::BufReader::new(
            fs::File::open(&path).unwrap(),
        )).unwrap();
        let decoded = decoder.read_image_hdr().unwrap();
        let reference = image::hdr::read_raw_file(&ref_path).unwrap();
        assert_eq!(decoded, reference);
    }
}

/// Check that BMP files with large values could cause OOM issues are rejected.
///
/// The images are postfixed with `bad_bmp` to not be loaded by the other test.
#[test]
fn bad_bmps() {
    let path: PathBuf = BASE_PATH
        .iter()
        .collect::<PathBuf>()
        .join(IMAGE_DIR)
        .join("bmp/images")
        .join("*.bad_bmp");

    let pattern = &*format!("{}", path.display());
    for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
        let im = image::open(path);
        assert!(im.is_err());
    }
}
<|endoftext|>


<commit_before><commit_msg>Clear up `iter_ok` docs<commit_after><|endoftext|>


<commit_before><commit_msg>Tapa: make generator more configurable<commit_after><|endoftext|>