<commit_before>//! Determining which types has vtable

use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
use ir::context::{BindgenContext, ItemId};
use ir::traversal::EdgeKind;
use ir::ty::TypeKind;
use std::cmp;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ops;

/// The result of the `HasVtableAnalysis` for an individual item.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord)]
pub enum HasVtableResult {
    /// The item has a vtable, but the actual vtable pointer is in a base
    /// member.
    BaseHasVtable,

    /// The item has a vtable and the actual vtable pointer is within this item.
    SelfHasVtable,

    /// The item does not have a vtable pointer.
    No
}

impl Default for HasVtableResult {
    fn default() -> Self {
        HasVtableResult::No
    }
}

impl cmp::PartialOrd for HasVtableResult {
    fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
        use self::HasVtableResult::*;

        match (*self, *rhs) {
            (x, y) if x == y => Some(cmp::Ordering::Equal),
            (BaseHasVtable, _) => Some(cmp::Ordering::Greater),
            (_, BaseHasVtable) => Some(cmp::Ordering::Less),
            (SelfHasVtable, _) => Some(cmp::Ordering::Greater),
            (_, SelfHasVtable) => Some(cmp::Ordering::Less),
            _ => unreachable!(),
        }
    }
}

impl HasVtableResult {
    /// Take the least upper bound of `self` and `rhs`.
    pub fn join(self, rhs: Self) -> Self {
        cmp::max(self, rhs)
    }
}

impl ops::BitOr for HasVtableResult {
    type Output = Self;

    fn bitor(self, rhs: HasVtableResult) -> Self::Output {
        self.join(rhs)
    }
}

impl ops::BitOrAssign for HasVtableResult {
    fn bitor_assign(&mut self, rhs: HasVtableResult) {
        *self = self.join(rhs)
    }
}

/// An analysis that finds for each IR item whether it has vtable or not
///
/// We use the monotone function `has vtable`, defined as follows:
///
/// * If T is a type alias, a templated alias, an indirection to another type,
///   or a reference of a type, T has vtable if the type T refers to has vtable.
/// * If T is a compound type, T has vtable if we saw a virtual function when
///   parsing it or any of its base member has vtable.
/// * If T is an instantiation of an abstract template definition, T has
///   vtable if template definition has vtable
#[derive(Debug, Clone)]
pub struct HasVtableAnalysis<'ctx> {
    ctx: &'ctx BindgenContext,

    // The incremental result of this analysis's computation. Everything in this
    // set definitely has a vtable.
    have_vtable: HashMap<ItemId, HasVtableResult>,

    // Dependencies saying that if a key ItemId has been inserted into the
    // `have_vtable` set, then each of the ids in Vec<ItemId> need to be
    // considered again.
    //
    // This is a subset of the natural IR graph with reversed edges, where we
    // only include the edges from the IR graph that can affect whether a type
    // has a vtable or not.
    dependencies: HashMap<ItemId, Vec<ItemId>>,
}

impl<'ctx> HasVtableAnalysis<'ctx> {
    fn consider_edge(kind: EdgeKind) -> bool {
        match kind {
            // These are the only edges that can affect whether a type has a
            // vtable or not.
            EdgeKind::TypeReference |
            EdgeKind::BaseMember |
            EdgeKind::TemplateDeclaration => true,
            _ => false,
        }
    }

    fn insert<Id: Into<ItemId>>(&mut self, id: Id, result: HasVtableResult) -> ConstrainResult {
        if let HasVtableResult::No = result {
            return ConstrainResult::Same;
        }

        let id = id.into();
        match self.have_vtable.entry(id) {
            Entry::Occupied(mut entry) => {
                if *entry.get() < result {
                    entry.insert(result);
                    ConstrainResult::Changed
                } else {
                    ConstrainResult::Same
                }
            }
            Entry::Vacant(entry) => {
                entry.insert(result);
                ConstrainResult::Changed
            }
        }
    }

    fn forward<Id1, Id2>(&mut self, from: Id1, to: Id2) -> ConstrainResult
    where
        Id1: Into<ItemId>,
        Id2: Into<ItemId>,
    {
        let from = from.into();
        let to = to.into();

        match self.have_vtable.get(&from).cloned() {
            None => ConstrainResult::Same,
            Some(r) => self.insert(to, r),
        }
    }
}

impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
    type Node = ItemId;
    type Extra = &'ctx BindgenContext;
    type Output = HashMap<ItemId, HasVtableResult>;

    fn new(ctx: &'ctx BindgenContext) -> HasVtableAnalysis<'ctx> {
        let have_vtable = HashMap::new();
        let dependencies = generate_dependencies(ctx, Self::consider_edge);

        HasVtableAnalysis {
            ctx,
            have_vtable,
            dependencies,
        }
    }

    fn initial_worklist(&self) -> Vec<ItemId> {
        self.ctx.whitelisted_items().iter().cloned().collect()
    }

    fn constrain(&mut self, id: ItemId) -> ConstrainResult {

        let item = self.ctx.resolve_item(id);
        let ty = match item.as_type() {
            None => return ConstrainResult::Same,
            Some(ty) => ty,
        };

        // TODO #851: figure out a way to handle deriving from template type parameters.
        match *ty.kind() {
            TypeKind::TemplateAlias(t, _) |
            TypeKind::Alias(t) |
            TypeKind::ResolvedTypeRef(t) |
            TypeKind::Reference(t) => {
                self.forward(t, id)
            }

            TypeKind::Comp(ref info) => {
                let mut result = HasVtableResult::No;

                if info.has_own_virtual_method() {
                    result |= HasVtableResult::SelfHasVtable;
                }

                let bases_has_vtable = info.base_members().iter().any(|base| {
                    self.have_vtable.contains_key(&base.ty.into())
                });
                if bases_has_vtable {
                    result |= HasVtableResult::BaseHasVtable;
                }

                self.insert(id, result)
            }

            TypeKind::TemplateInstantiation(ref inst) => {
                self.forward(inst.template_definition(), id)
            }

            _ => ConstrainResult::Same,
        }
    }

    fn each_depending_on<F>(&self, id: ItemId, mut f: F)
    where
        F: FnMut(ItemId),
    {
        if let Some(edges) = self.dependencies.get(&id) {
            for item in edges {
                trace!("enqueue {:?} into worklist", item);
                f(*item);
            }
        }
    }
}

impl<'ctx> From<HasVtableAnalysis<'ctx>> for HashMap<ItemId, HasVtableResult> {
    fn from(analysis: HasVtableAnalysis<'ctx>) -> Self {
        // We let the lack of an entry mean "No" to save space.
        extra_assert!(analysis.have_vtable.values().all(|v| {
            *v != HasVtableResult::No
        }));

        analysis.have_vtable
    }
}

/// A convenience trait for the things for which we might wonder if they have a
/// vtable during codegen.
///
/// This is not for _computing_ whether the thing has a vtable, it is for
/// looking up the results of the HasVtableAnalysis's computations for a
/// specific thing.
pub trait HasVtable {
    /// Return `true` if this thing has vtable, `false` otherwise.
    fn has_vtable(&self, ctx: &BindgenContext) -> bool;
}
<commit_msg>Add `trace!` logging for the `HasVtableAnalysis`<commit_after>//! Determining which types has vtable

use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
use ir::context::{BindgenContext, ItemId};
use ir::traversal::EdgeKind;
use ir::ty::TypeKind;
use std::cmp;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ops;

/// The result of the `HasVtableAnalysis` for an individual item.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord)]
pub enum HasVtableResult {
    /// The item has a vtable, but the actual vtable pointer is in a base
    /// member.
    BaseHasVtable,

    /// The item has a vtable and the actual vtable pointer is within this item.
    SelfHasVtable,

    /// The item does not have a vtable pointer.
    No
}

impl Default for HasVtableResult {
    fn default() -> Self {
        HasVtableResult::No
    }
}

impl cmp::PartialOrd for HasVtableResult {
    fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
        use self::HasVtableResult::*;

        match (*self, *rhs) {
            (x, y) if x == y => Some(cmp::Ordering::Equal),
            (BaseHasVtable, _) => Some(cmp::Ordering::Greater),
            (_, BaseHasVtable) => Some(cmp::Ordering::Less),
            (SelfHasVtable, _) => Some(cmp::Ordering::Greater),
            (_, SelfHasVtable) => Some(cmp::Ordering::Less),
            _ => unreachable!(),
        }
    }
}

impl HasVtableResult {
    /// Take the least upper bound of `self` and `rhs`.
    pub fn join(self, rhs: Self) -> Self {
        cmp::max(self, rhs)
    }
}

impl ops::BitOr for HasVtableResult {
    type Output = Self;

    fn bitor(self, rhs: HasVtableResult) -> Self::Output {
        self.join(rhs)
    }
}

impl ops::BitOrAssign for HasVtableResult {
    fn bitor_assign(&mut self, rhs: HasVtableResult) {
        *self = self.join(rhs)
    }
}

/// An analysis that finds for each IR item whether it has vtable or not
///
/// We use the monotone function `has vtable`, defined as follows:
///
/// * If T is a type alias, a templated alias, an indirection to another type,
///   or a reference of a type, T has vtable if the type T refers to has vtable.
/// * If T is a compound type, T has vtable if we saw a virtual function when
///   parsing it or any of its base member has vtable.
/// * If T is an instantiation of an abstract template definition, T has
///   vtable if template definition has vtable
#[derive(Debug, Clone)]
pub struct HasVtableAnalysis<'ctx> {
    ctx: &'ctx BindgenContext,

    // The incremental result of this analysis's computation. Everything in this
    // set definitely has a vtable.
    have_vtable: HashMap<ItemId, HasVtableResult>,

    // Dependencies saying that if a key ItemId has been inserted into the
    // `have_vtable` set, then each of the ids in Vec<ItemId> need to be
    // considered again.
    //
    // This is a subset of the natural IR graph with reversed edges, where we
    // only include the edges from the IR graph that can affect whether a type
    // has a vtable or not.
    dependencies: HashMap<ItemId, Vec<ItemId>>,
}

impl<'ctx> HasVtableAnalysis<'ctx> {
    fn consider_edge(kind: EdgeKind) -> bool {
        match kind {
            // These are the only edges that can affect whether a type has a
            // vtable or not.
            EdgeKind::TypeReference |
            EdgeKind::BaseMember |
            EdgeKind::TemplateDeclaration => true,
            _ => false,
        }
    }

    fn insert<Id: Into<ItemId>>(&mut self, id: Id, result: HasVtableResult) -> ConstrainResult {
        if let HasVtableResult::No = result {
            return ConstrainResult::Same;
        }

        let id = id.into();
        match self.have_vtable.entry(id) {
            Entry::Occupied(mut entry) => {
                if *entry.get() < result {
                    entry.insert(result);
                    ConstrainResult::Changed
                } else {
                    ConstrainResult::Same
                }
            }
            Entry::Vacant(entry) => {
                entry.insert(result);
                ConstrainResult::Changed
            }
        }
    }

    fn forward<Id1, Id2>(&mut self, from: Id1, to: Id2) -> ConstrainResult
    where
        Id1: Into<ItemId>,
        Id2: Into<ItemId>,
    {
        let from = from.into();
        let to = to.into();

        match self.have_vtable.get(&from).cloned() {
            None => ConstrainResult::Same,
            Some(r) => self.insert(to, r),
        }
    }
}

impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
    type Node = ItemId;
    type Extra = &'ctx BindgenContext;
    type Output = HashMap<ItemId, HasVtableResult>;

    fn new(ctx: &'ctx BindgenContext) -> HasVtableAnalysis<'ctx> {
        let have_vtable = HashMap::new();
        let dependencies = generate_dependencies(ctx, Self::consider_edge);

        HasVtableAnalysis {
            ctx,
            have_vtable,
            dependencies,
        }
    }

    fn initial_worklist(&self) -> Vec<ItemId> {
        self.ctx.whitelisted_items().iter().cloned().collect()
    }

    fn constrain(&mut self, id: ItemId) -> ConstrainResult {
        trace!("constrain {:?}", id);

        let item = self.ctx.resolve_item(id);
        let ty = match item.as_type() {
            None => return ConstrainResult::Same,
            Some(ty) => ty,
        };

        // TODO #851: figure out a way to handle deriving from template type parameters.
        match *ty.kind() {
            TypeKind::TemplateAlias(t, _) |
            TypeKind::Alias(t) |
            TypeKind::ResolvedTypeRef(t) |
            TypeKind::Reference(t) => {
                trace!("    aliases and references forward to their inner type");
                self.forward(t, id)
            }

            TypeKind::Comp(ref info) => {
                trace!("    comp considers its own methods and bases");
                let mut result = HasVtableResult::No;

                if info.has_own_virtual_method() {
                    trace!("    comp has its own virtual method");
                    result |= HasVtableResult::SelfHasVtable;
                }

                let bases_has_vtable = info.base_members().iter().any(|base| {
                    trace!("    comp has a base with a vtable: {:?}", base);
                    self.have_vtable.contains_key(&base.ty.into())
                });
                if bases_has_vtable {
                    result |= HasVtableResult::BaseHasVtable;
                }

                self.insert(id, result)
            }

            TypeKind::TemplateInstantiation(ref inst) => {
                self.forward(inst.template_definition(), id)
            }

            _ => ConstrainResult::Same,
        }
    }

    fn each_depending_on<F>(&self, id: ItemId, mut f: F)
    where
        F: FnMut(ItemId),
    {
        if let Some(edges) = self.dependencies.get(&id) {
            for item in edges {
                trace!("enqueue {:?} into worklist", item);
                f(*item);
            }
        }
    }
}

impl<'ctx> From<HasVtableAnalysis<'ctx>> for HashMap<ItemId, HasVtableResult> {
    fn from(analysis: HasVtableAnalysis<'ctx>) -> Self {
        // We let the lack of an entry mean "No" to save space.
        extra_assert!(analysis.have_vtable.values().all(|v| {
            *v != HasVtableResult::No
        }));

        analysis.have_vtable
    }
}

/// A convenience trait for the things for which we might wonder if they have a
/// vtable during codegen.
///
/// This is not for _computing_ whether the thing has a vtable, it is for
/// looking up the results of the HasVtableAnalysis's computations for a
/// specific thing.
pub trait HasVtable {
    /// Return `true` if this thing has vtable, `false` otherwise.
    fn has_vtable(&self, ctx: &BindgenContext) -> bool;
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// 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 cgmath::{EuclideanSpace, InnerSpace, Point3, Quaternion, Rotation, Vector2, Vector3};
use collision::{Aabb, Aabb3};

#[derive(Debug, Clone)]
pub struct Cube {
    min: Point3<f64>,
    edge_length: f64,
}

impl Cube {
    pub fn bounding(aabb: &Aabb3<f64>) -> Self {
        let edge_length = (aabb.max().x - aabb.min().x)
            .max(aabb.max().y - aabb.min().y)
            .max(aabb.max().z - aabb.min().z);
        Cube {
            min: aabb.min,
            edge_length,
        }
    }

    pub fn to_aabb3(&self) -> Aabb3<f64> {
        Aabb3::new(self.min(), self.max())
    }

    pub fn new(min: Point3<f64>, edge_length: f64) -> Self {
        Cube { min, edge_length }
    }

    pub fn edge_length(&self) -> f64 {
        self.edge_length
    }

    pub fn min(&self) -> Point3<f64> {
        self.min
    }

    pub fn max(&self) -> Point3<f64> {
        Point3::new(
            self.min.x + self.edge_length,
            self.min.y + self.edge_length,
            self.min.z + self.edge_length,
        )
    }

    /// The center of the box.
    pub fn center(&self) -> Vector3<f64> {
        let min = self.min();
        let max = self.max();
        Vector3::new(
            (min.x + max.x) / 2.,
            (min.y + max.y) / 2.,
            (min.z + max.z) / 2.,
        )
    }
}

#[derive(Debug, Clone)]
pub struct OrientedBeam {
    // The members here are an implementation detail and differ from the
    // minimal representation in the gRPC message to speed up operations.
    // Rotation_inv and translation_inv together form the transform from world
    // coordinates into "beam coordinates".
    rotation_inv: Quaternion<f64>,
    translation_inv: Vector3<f64>,
    half_extent: Vector2<f64>,
    corners: [Point3<f64>; 4],
    separating_axes: [Vector3<f64>; 5],
}

impl OrientedBeam {
    pub fn new(
        rotation: Quaternion<f64>,
        translation: Vector3<f64>,
        half_extent: Vector2<f64>,
    ) -> Self {
        OrientedBeam {
            rotation_inv: rotation.conjugate(),
            translation_inv: -rotation.conjugate().rotate_vector(translation),
            half_extent,
            corners: OrientedBeam::precompute_corners(&rotation, &translation, &half_extent),
            separating_axes: OrientedBeam::precompute_separating_axes(&rotation),
        }
    }
    pub fn intersects(&self, aabb: &Aabb3<f64>) -> bool {
        // SAT algorithm
        // https://gamedev.stackexchange.com/questions/44500/how-many-and-which-axes-to-use-for-3d-obb-collision-with-sat
        for sep_axis in self.separating_axes.iter() {
            if !sep_axis.x.is_finite() || !sep_axis.y.is_finite() || !sep_axis.z.is_finite() {
                // This guards against the separating axes being NaN, which may happen when the orientation aligns with the unit axes.
                continue;
            }
            // Project the cube and the beam onto that axis
            let mut cube_min_proj = std::f64::MAX;
            let mut cube_max_proj = std::f64::MIN;
            for corner in aabb.to_corners().iter() {
                let corner_proj = corner.dot(*sep_axis);
                cube_min_proj = cube_min_proj.min(corner_proj);
                cube_max_proj = cube_max_proj.max(corner_proj);
            }
            // Project four "vertices" of the beam onto that axis
            let mut beam_min_proj = std::f64::MAX;
            let mut beam_max_proj = std::f64::MIN;
            for corner in self.corners.iter() {
                let corner_proj = corner.dot(*sep_axis);
                beam_min_proj = beam_min_proj.min(corner_proj);
                beam_max_proj = beam_max_proj.max(corner_proj);
            }
            if beam_min_proj > cube_max_proj || beam_max_proj < cube_min_proj {
                return false;
            }
        }
        true
    }

    pub fn contains(&self, p: &Point3<f64>) -> bool {
        // What is the point in beam coordinates?
        let Point3 { x, y, .. } = self.rotation_inv.rotate_point(*p) + self.translation_inv;
        x.abs() <= self.half_extent.x && y.abs() <= self.half_extent.y
    }

    fn precompute_corners(
        rotation: &Quaternion<f64>,
        translation: &Vector3<f64>,
        half_extent: &Vector2<f64>,
    ) -> [Point3<f64>; 4] {
        let transform =
            |x: f64, y: f64| rotation.rotate_point(Point3::new(x, y, 0.0)) + translation;
        [
            transform(half_extent.x, half_extent.y),
            transform(half_extent.x, -half_extent.y),
            transform(-half_extent.x, half_extent.y),
            transform(-half_extent.x, -half_extent.y),
        ]
    }

    fn precompute_separating_axes(rotation: &Quaternion<f64>) -> [Vector3<f64>; 5] {
        // The separating axis needs to be perpendicular to the beam's main
        // axis, i.e. the possible axes are the cross product of the three unit
        // vectors with the beam's main axis and the beam's face normals.
        let main_axis = rotation.rotate_vector(Vector3::unit_z());
        [
            rotation.rotate_vector(Vector3::unit_x()),
            rotation.rotate_vector(Vector3::unit_y()),
            main_axis.cross(Vector3::unit_x()).normalize(),
            main_axis.cross(Vector3::unit_y()).normalize(),
            main_axis.cross(Vector3::unit_z()).normalize(),
        ]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cgmath::Zero;
    // These tests were created in Blender by creating two cubes, naming one
    // "Beam" and scaling it up in its local z direction. The corresponding
    // object in Rust was defined by querying Blender's Python API with
    // bpy.data.objects['Beam'].rotation_euler.to_quaternion() and
    // bpy.data.objects['Beam'].location.

    fn some_beam() -> OrientedBeam {
        let quater = Quaternion::new(
            0.9292423725128174,
            -0.2677415907382965,
            -0.20863021910190582,
            -0.14593297243118286,
        );
        let translation = Vector3::new(1.0, 2.0, 0.0);
        let half_extent = Vector2::new(1.0, 1.0);
        OrientedBeam::new(quater, translation, half_extent)
    }

    #[test]
    fn test_beam_contains() {
        let point1 = Point3::new(-29.96, 57.85, 76.96); // (0, 0, 100) in local coordinates
        let point2 = Point3::new(-29.50, 58.83, 76.43); // (0, 1.2, 100) in local coordinates

        assert_eq!(some_beam().contains(&point1), true);
        assert_eq!(some_beam().contains(&point2), false);
    }

    #[test]
    fn test_beam_intersects() {
        let bbox1 = Aabb3::new(Point3::new(0.0, 0.0, 0.0), Point3::new(2.0, 2.0, 2.0));
        let bbox2 = Aabb3::new(Point3::new(0.0, 0.0, 3.0), Point3::new(2.0, 2.0, 5.0));
        // bbox3 is completely inside the beam, none of its faces intersect it
        let bbox3 = Aabb3::new(Point3::new(0.25, 1.8, 0.0), Point3::new(1.25, 2.8, 1.0));
        // bbox4 intersects the beam, but has no vertices inside it
        let bbox4 = Aabb3::new(Point3::new(-3.0, -2.0, -3.5), Point3::new(5.0, 6.0, 4.5));
        let bbox5 = Aabb3::new(Point3::new(2.1, -0.55, 0.0), Point3::new(4.1, 1.45, 2.0));
        let bbox6 = Aabb3::new(Point3::new(0.9, -1.67, 0.0), Point3::new(2.9, 0.33, 2.0));
        let bbox7 = Aabb3::new(Point3::new(0.9, -1.57, 0.0), Point3::new(2.9, 0.43, 2.0));
        assert_eq!(some_beam().intersects(&bbox1), true);
        assert_eq!(some_beam().intersects(&bbox2), false);
        assert_eq!(some_beam().intersects(&bbox3), true);
        assert_eq!(some_beam().intersects(&bbox4), true);
        assert_eq!(some_beam().intersects(&bbox5), false);
        assert_eq!(some_beam().intersects(&bbox6), false);
        assert_eq!(some_beam().intersects(&bbox7), true);
        let vertical_beam =
            OrientedBeam::new(Quaternion::zero(), Vector3::zero(), Vector2::new(1.0, 1.0));
        assert_eq!(vertical_beam.intersects(&bbox1), true);
    }
}
<commit_msg>Add OBB. (#263)<commit_after>// Copyright 2016 Google Inc.
//
// 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 cgmath::{
    BaseFloat, EuclideanSpace, InnerSpace, Point3, Quaternion, Rotation, Vector2, Vector3,
};
use collision::{Aabb, Aabb3};
use num_traits::Float;

#[derive(Debug, Clone)]
pub struct Cube {
    min: Point3<f64>,
    edge_length: f64,
}

impl Cube {
    pub fn bounding(aabb: &Aabb3<f64>) -> Self {
        let edge_length = (aabb.max().x - aabb.min().x)
            .max(aabb.max().y - aabb.min().y)
            .max(aabb.max().z - aabb.min().z);
        Cube {
            min: aabb.min,
            edge_length,
        }
    }

    pub fn to_aabb3(&self) -> Aabb3<f64> {
        Aabb3::new(self.min(), self.max())
    }

    pub fn new(min: Point3<f64>, edge_length: f64) -> Self {
        Cube { min, edge_length }
    }

    pub fn edge_length(&self) -> f64 {
        self.edge_length
    }

    pub fn min(&self) -> Point3<f64> {
        self.min
    }

    pub fn max(&self) -> Point3<f64> {
        Point3::new(
            self.min.x + self.edge_length,
            self.min.y + self.edge_length,
            self.min.z + self.edge_length,
        )
    }

    /// The center of the box.
    pub fn center(&self) -> Vector3<f64> {
        let min = self.min();
        let max = self.max();
        Vector3::new(
            (min.x + max.x) / 2.,
            (min.y + max.y) / 2.,
            (min.z + max.z) / 2.,
        )
    }
}

// This guards against the separating axes being NaN, which may happen when the orientation aligns with the unit axes.
fn is_finite<S: BaseFloat>(vec: &Vector3<S>) -> bool {
    vec.x.is_finite() && vec.y.is_finite() && vec.z.is_finite()
}

fn intersects<S: BaseFloat>(
    corners: &[Point3<S>],
    separating_axes: &[Vector3<S>],
    aabb: &Aabb3<S>,
) -> bool {
    // SAT algorithm
    // https://gamedev.stackexchange.com/questions/44500/how-many-and-which-axes-to-use-for-3d-obb-collision-with-sat
    for sep_axis in separating_axes.iter() {
        // Project the cube and the box/beam onto that axis
        let mut cube_min_proj: S = Float::max_value();
        let mut cube_max_proj: S = Float::min_value();
        for corner in aabb.to_corners().iter() {
            let corner_proj = corner.dot(*sep_axis);
            cube_min_proj = cube_min_proj.min(corner_proj);
            cube_max_proj = cube_max_proj.max(corner_proj);
        }
        // Project corners of the box/beam onto that axis
        let mut beam_min_proj: S = Float::max_value();
        let mut beam_max_proj: S = Float::min_value();
        for corner in corners.iter() {
            let corner_proj = corner.dot(*sep_axis);
            beam_min_proj = beam_min_proj.min(corner_proj);
            beam_max_proj = beam_max_proj.max(corner_proj);
        }
        if beam_min_proj > cube_max_proj || beam_max_proj < cube_min_proj {
            return false;
        }
    }
    true
}

pub struct Obb<S> {
    rotation_inv: Quaternion<S>,
    translation_inv: Vector3<S>,
    half_extent: Vector3<S>,
    corners: [Point3<S>; 8],
    separating_axes: Vec<Vector3<S>>,
}

impl<S: BaseFloat> Obb<S> {
    pub fn new(rotation: Quaternion<S>, translation: Vector3<S>, half_extent: Vector3<S>) -> Self {
        Obb {
            rotation_inv: rotation.conjugate(),
            translation_inv: -rotation.conjugate().rotate_vector(translation),
            half_extent,
            corners: Obb::precompute_corners(&rotation, &translation, &half_extent),
            separating_axes: Obb::precompute_separating_axes(&rotation),
        }
    }

    pub fn intersects(&self, aabb: &Aabb3<S>) -> bool {
        intersects(&self.corners, &self.separating_axes, aabb)
    }

    pub fn contains(&self, p: &Point3<S>) -> bool {
        let Point3 { x, y, z } = self.rotation_inv.rotate_point(*p) + self.translation_inv;
        x.abs() <= self.half_extent.x
            && y.abs() <= self.half_extent.y
            && z.abs() <= self.half_extent.z
    }

    fn precompute_corners(
        rotation: &Quaternion<S>,
        translation: &Vector3<S>,
        half_extent: &Vector3<S>,
    ) -> [Point3<S>; 8] {
        let transform =
            |x: S, y: S, z: S| rotation.rotate_point(Point3::new(x, y, z)) + translation;
        [
            transform(-half_extent.x, -half_extent.y, -half_extent.z),
            transform(half_extent.x, -half_extent.y, -half_extent.z),
            transform(-half_extent.x, half_extent.y, -half_extent.z),
            transform(half_extent.x, half_extent.y, -half_extent.z),
            transform(-half_extent.x, -half_extent.y, half_extent.z),
            transform(half_extent.x, -half_extent.y, half_extent.z),
            transform(-half_extent.x, half_extent.y, half_extent.z),
            transform(half_extent.x, half_extent.y, half_extent.z),
        ]
    }

    fn precompute_separating_axes(rotation: &Quaternion<S>) -> Vec<Vector3<S>> {
        let unit_x = Vector3::unit_x();
        let unit_y = Vector3::unit_y();
        let unit_z = Vector3::unit_z();
        let rot_x = rotation.rotate_vector(unit_x);
        let rot_y = rotation.rotate_vector(unit_y);
        let rot_z = rotation.rotate_vector(unit_z);
        let mut separating_axes = vec![unit_x, unit_y, unit_z];
        for axis in &[
            rot_x,
            rot_y,
            rot_z,
            unit_x.cross(rot_x).normalize(),
            unit_x.cross(rot_y).normalize(),
            unit_x.cross(rot_z).normalize(),
            unit_y.cross(rot_x).normalize(),
            unit_y.cross(rot_y).normalize(),
            unit_y.cross(rot_z).normalize(),
            unit_z.cross(rot_x).normalize(),
            unit_z.cross(rot_y).normalize(),
            unit_z.cross(rot_z).normalize(),
        ] {
            let is_finite_and_non_parallel = is_finite(&axis)
                && separating_axes.iter().all(|elem| {
                    (elem - axis).magnitude() > S::default_epsilon()
                        && (elem + axis).magnitude() > S::default_epsilon()
                });
            if is_finite_and_non_parallel {
                separating_axes.push(*axis);
            }
        }
        separating_axes
    }
}

#[derive(Debug, Clone)]
pub struct OrientedBeam {
    // The members here are an implementation detail and differ from the
    // minimal representation in the gRPC message to speed up operations.
    // Rotation_inv and translation_inv together form the transform from world
    // coordinates into "beam coordinates".
    rotation_inv: Quaternion<f64>,
    translation_inv: Vector3<f64>,
    half_extent: Vector2<f64>,
    corners: [Point3<f64>; 4],
    separating_axes: Vec<Vector3<f64>>,
}

impl OrientedBeam {
    pub fn new(
        rotation: Quaternion<f64>,
        translation: Vector3<f64>,
        half_extent: Vector2<f64>,
    ) -> Self {
        OrientedBeam {
            rotation_inv: rotation.conjugate(),
            translation_inv: -rotation.conjugate().rotate_vector(translation),
            half_extent,
            corners: OrientedBeam::precompute_corners(&rotation, &translation, &half_extent),
            separating_axes: OrientedBeam::precompute_separating_axes(&rotation),
        }
    }

    pub fn intersects(&self, aabb: &Aabb3<f64>) -> bool {
        intersects(&self.corners, &self.separating_axes, aabb)
    }

    pub fn contains(&self, p: &Point3<f64>) -> bool {
        // What is the point in beam coordinates?
        let Point3 { x, y, .. } = self.rotation_inv.rotate_point(*p) + self.translation_inv;
        x.abs() <= self.half_extent.x && y.abs() <= self.half_extent.y
    }

    fn precompute_corners(
        rotation: &Quaternion<f64>,
        translation: &Vector3<f64>,
        half_extent: &Vector2<f64>,
    ) -> [Point3<f64>; 4] {
        let transform =
            |x: f64, y: f64| rotation.rotate_point(Point3::new(x, y, 0.0)) + translation;
        [
            transform(half_extent.x, half_extent.y),
            transform(half_extent.x, -half_extent.y),
            transform(-half_extent.x, half_extent.y),
            transform(-half_extent.x, -half_extent.y),
        ]
    }

    // TODO(nnmm): Change the axes to describe a beam, which is finitie in one direction.
    // Currently we have a beam which is infinite in both directions.
    // If we defined a beam on one side of the earth pointing towards the sky,
    // it will also collect points on the other side of the earth, which is undesired.
    fn precompute_separating_axes(rotation: &Quaternion<f64>) -> Vec<Vector3<f64>> {
        // The separating axis needs to be perpendicular to the beam's main
        // axis, i.e. the possible axes are the cross product of the three unit
        // vectors with the beam's main axis and the beam's face normals.
        let main_axis = rotation.rotate_vector(Vector3::unit_z());
        vec![
            rotation.rotate_vector(Vector3::unit_x()),
            rotation.rotate_vector(Vector3::unit_y()),
            main_axis.cross(Vector3::unit_x()).normalize(),
            main_axis.cross(Vector3::unit_y()).normalize(),
            main_axis.cross(Vector3::unit_z()).normalize(),
        ]
        .into_iter()
        .filter(is_finite)
        .collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cgmath::{Rad, Rotation3, Zero};
    // These tests were created in Blender by creating two cubes, naming one
    // "Beam" and scaling it up in its local z direction. The corresponding
    // object in Rust was defined by querying Blender's Python API with
    // bpy.data.objects['Beam'].rotation_euler.to_quaternion() and
    // bpy.data.objects['Beam'].location.

    fn some_beam() -> OrientedBeam {
        let quater = Quaternion::new(
            0.9292423725128174,
            -0.2677415907382965,
            -0.20863021910190582,
            -0.14593297243118286,
        );
        let translation = Vector3::new(1.0, 2.0, 0.0);
        let half_extent = Vector2::new(1.0, 1.0);
        OrientedBeam::new(quater, translation, half_extent)
    }

    #[test]
    fn test_beam_contains() {
        let point1 = Point3::new(-29.96, 57.85, 76.96); // (0, 0, 100) in local coordinates
        let point2 = Point3::new(-29.50, 58.83, 76.43); // (0, 1.2, 100) in local coordinates

        assert_eq!(some_beam().contains(&point1), true);
        assert_eq!(some_beam().contains(&point2), false);
    }

    #[test]
    fn test_beam_intersects() {
        let bbox1 = Aabb3::new(Point3::new(0.0, 0.0, 0.0), Point3::new(2.0, 2.0, 2.0));
        let bbox2 = Aabb3::new(Point3::new(0.0, 0.0, 3.0), Point3::new(2.0, 2.0, 5.0));
        // bbox3 is completely inside the beam, none of its faces intersect it
        let bbox3 = Aabb3::new(Point3::new(0.25, 1.8, 0.0), Point3::new(1.25, 2.8, 1.0));
        // bbox4 intersects the beam, but has no vertices inside it
        let bbox4 = Aabb3::new(Point3::new(-3.0, -2.0, -3.5), Point3::new(5.0, 6.0, 4.5));
        let bbox5 = Aabb3::new(Point3::new(2.1, -0.55, 0.0), Point3::new(4.1, 1.45, 2.0));
        let bbox6 = Aabb3::new(Point3::new(0.9, -1.67, 0.0), Point3::new(2.9, 0.33, 2.0));
        let bbox7 = Aabb3::new(Point3::new(0.9, -1.57, 0.0), Point3::new(2.9, 0.43, 2.0));
        assert_eq!(some_beam().intersects(&bbox1), true);
        assert_eq!(some_beam().intersects(&bbox2), false);
        assert_eq!(some_beam().intersects(&bbox3), true);
        assert_eq!(some_beam().intersects(&bbox4), true);
        assert_eq!(some_beam().intersects(&bbox5), false);
        assert_eq!(some_beam().intersects(&bbox6), false);
        assert_eq!(some_beam().intersects(&bbox7), true);
        let vertical_beam =
            OrientedBeam::new(Quaternion::zero(), Vector3::zero(), Vector2::new(1.0, 1.0));
        assert_eq!(vertical_beam.intersects(&bbox1), true);
    }

    #[test]
    fn test_obb_intersects() {
        let zero_rot: Quaternion<f64> = Rotation3::from_angle_z(Rad(0.0));
        let fourty_five_deg_rot: Quaternion<f64> =
            Rotation3::from_angle_z(Rad(std::f64::consts::PI / 4.0));
        let arbitrary_rot: Quaternion<f64> =
            Rotation3::from_axis_angle(Vector3::new(0.2, 0.5, -0.7), Rad(0.123));
        let translation = Vector3::new(0.0, 0.0, 0.0);
        let half_extent = Vector3::new(1.0, 2.0, 3.0);
        let zero_obb = Obb::new(zero_rot, translation, half_extent);
        let fourty_five_deg_obb = Obb::new(fourty_five_deg_rot, translation, half_extent);
        let arbitrary_obb = Obb::new(arbitrary_rot, translation, half_extent);
        let bbox = Aabb3::new(Point3::new(0.5, 1.0, -3.0), Point3::new(1.5, 3.0, 3.0));
        assert_eq!(zero_obb.separating_axes.len(), 3);
        assert_eq!(zero_obb.intersects(&bbox), true);
        assert_eq!(fourty_five_deg_obb.separating_axes.len(), 5);
        assert_eq!(fourty_five_deg_obb.intersects(&bbox), false);
        assert_eq!(arbitrary_obb.separating_axes.len(), 15);
    }
}
<|endoftext|>


<commit_before>use alga::general::{Real, SupersetOf};
use nalgebra::{self, Matrix4, Point2, Point3, Scalar, Unit, Vector3, Vector4};
use num::{Float, Integer};
use std::cmp;
use std::ops;

pub type UScalar = u32;
pub type FScalar = f32;

pub type UPoint2 = Point2<UScalar>;
pub type UPoint3 = Point3<UScalar>;
pub type UVector3 = Vector3<UScalar>;

pub type FPoint2 = Point2<FScalar>;
pub type FPoint3 = Point3<FScalar>;
pub type FVector3 = Vector3<FScalar>;
pub type FVector4 = Vector4<FScalar>;
pub type FMatrix4 = Matrix4<FScalar>;

pub type FRay3 = Ray3<FScalar>;

pub struct Ray3<T>
where
    T: Scalar,
{
    pub origin: Point3<T>,
    pub direction: Unit<Vector3<T>>,
}

impl<T> Ray3<T>
where
    T: Real + Scalar,
{
    pub fn new(origin: Point3<T>, direction: Vector3<T>) -> Self {
        Ray3 {
            origin: origin,
            direction: Unit::new_normalize(direction),
        }
    }

    pub fn x() -> Self {
        Ray3::new(Point3::origin(), Vector3::x())
    }

    pub fn y() -> Self {
        Ray3::new(Point3::origin(), Vector3::y())
    }

    pub fn z() -> Self {
        Ray3::new(Point3::origin(), Vector3::z())
    }
}

pub trait Matrix4Ext<T>
where
    T: Scalar,
{
    fn to_array(&self) -> [[T; 4]; 4];
}

impl<T> Matrix4Ext<T> for Matrix4<T>
where
    T: Scalar,
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn to_array(&self) -> [[T; 4]; 4] {
        [
            [self[0],  self[1],  self[2],  self[3]],
            [self[4],  self[5],  self[6],  self[7]],
            [self[8],  self[9],  self[10], self[11]],
            [self[12], self[13], self[14], self[15]]
        ]
    }
}

// TODO: The `FromSpace` and `IntoSpace` traits may not be useful. Instead, the
//       `nalgebra::convert` function can be used directly.
pub trait FromSpace<T> {
    fn from_space(value: T) -> Self;
}

impl<T, U> FromSpace<Point2<U>> for Point2<T>
where
    T: SupersetOf<U> + Scalar,
    U: Scalar,
{
    fn from_space(point: Point2<U>) -> Self {
        nalgebra::convert(point)
    }
}

impl<T, U> FromSpace<Point3<U>> for Point3<T>
where
    T: SupersetOf<U> + Scalar,
    U: Scalar,
{
    fn from_space(point: Point3<U>) -> Self {
        nalgebra::convert(point)
    }
}

impl<T, U> FromSpace<Vector3<U>> for Vector3<T>
where
    T: SupersetOf<U> + Scalar,
    U: Scalar,
{
    fn from_space(vector: Vector3<U>) -> Self {
        nalgebra::convert(vector)
    }
}

pub trait IntoSpace<T> {
    fn into_space(self) -> T;
}

impl<T, U> IntoSpace<U> for T
where
    U: FromSpace<T>,
{
    fn into_space(self) -> U {
        U::from_space(self)
    }
}

pub trait Clamp<T>
where
    T: PartialOrd,
{
    fn clamp(&self, min: T, max: T) -> Self;
}

impl<T> Clamp<T> for Point3<T>
where
    T: PartialOrd + Scalar,
{
    fn clamp(&self, min: T, max: T) -> Self {
        use nalgebra::clamp;

        Point3::new(
            clamp(self.x, min, max),
            clamp(self.y, min, max),
            clamp(self.z, min, max),
        )
    }
}

pub trait Mask<T>
where
    T: ops::BitAnd<Output = T>,
{
    fn mask(&self, value: T) -> Self;
}

impl<T> Mask<T> for Point3<T>
where
    T: ops::BitAnd<Output = T> + Scalar,
{
    fn mask(&self, value: T) -> Self {
        Point3::new(self.x & value, self.y & value, self.z & value)
    }
}

pub trait UpperBound {
    fn upper_bound(&self, other: &Self) -> Self;
}

impl<T> UpperBound for Point3<T>
where
    T: Ord + Scalar,
{
    fn upper_bound(&self, other: &Self) -> Self {
        Point3::new(
            cmp::max(self.x, other.x),
            cmp::max(self.y, other.y),
            cmp::max(self.y, other.y),
        )
    }
}

pub trait LowerBound {
    fn lower_bound(&self, other: &Self) -> Self;
}

impl<T> LowerBound for Point3<T>
where
    T: Ord + Scalar,
{
    fn lower_bound(&self, other: &Self) -> Self {
        Point3::new(
            cmp::min(self.x, other.x),
            cmp::min(self.y, other.y),
            cmp::min(self.y, other.y),
        )
    }
}

pub trait Interpolate<F>: Sized
where
    F: Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self;

    fn midpoint(&self, other: &Self) -> Self {
        self.lerp(other, F::one() / (F::one() + F::one()))
    }
}

impl<T, F> Interpolate<F> for (T, T)
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        (lerp(self.0, other.0, f), lerp(self.1, other.1, f))
    }
}

impl<T, F> Interpolate<F> for (T, T, T)
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        (
            lerp(self.0, other.0, f),
            lerp(self.1, other.1, f),
            lerp(self.2, other.2, f),
        )
    }
}

impl<T, F> Interpolate<F> for Point2<T>
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        Point2::new(lerp(self.x, other.x, f), lerp(self.y, other.y, f))
    }
}

impl<T, F> Interpolate<F> for Point3<T>
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        Point3::new(
            lerp(self.x, other.x, f),
            lerp(self.y, other.y, f),
            lerp(self.z, other.z, f),
        )
    }
}

pub fn lerp<T, F>(a: T, b: T, f: F) -> T
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    use nalgebra::{convert, clamp};

    let f = clamp(f, F::zero(), F::one());
    let af = convert::<T, F>(a) * (F::one() - f);
    let bf = convert::<T, F>(b) * f;
    convert::<F, T>(af + bf)
}

pub fn ordered_pair<T>(a: T, b: T) -> (T, T)
where
    T: PartialOrd,
{
    if a <= b {
        (a, b)
    }
    else {
        (b, a)
    }
}

pub fn partial_min<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a <= b {
        a
    }
    else {
        b
    }
}

pub fn partial_max<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a > b {
        a
    }
    else {
        b
    }
}

pub fn umod<T>(n: T, m: T) -> T
where
    T: Copy + Integer,
{
    ((n % m) + m) % m
}

#[cfg(test)]
mod tests {
    use super::*;
}
<commit_msg>Fix `UpperBound` and `LowerBound` implementation.<commit_after>use alga::general::{Real, SupersetOf};
use nalgebra::{self, Matrix4, Point2, Point3, Scalar, Unit, Vector3, Vector4};
use num::{Float, Integer};
use std::cmp;
use std::ops;

pub type UScalar = u32;
pub type FScalar = f32;

pub type UPoint2 = Point2<UScalar>;
pub type UPoint3 = Point3<UScalar>;
pub type UVector3 = Vector3<UScalar>;

pub type FPoint2 = Point2<FScalar>;
pub type FPoint3 = Point3<FScalar>;
pub type FVector3 = Vector3<FScalar>;
pub type FVector4 = Vector4<FScalar>;
pub type FMatrix4 = Matrix4<FScalar>;

pub type FRay3 = Ray3<FScalar>;

pub struct Ray3<T>
where
    T: Scalar,
{
    pub origin: Point3<T>,
    pub direction: Unit<Vector3<T>>,
}

impl<T> Ray3<T>
where
    T: Real + Scalar,
{
    pub fn new(origin: Point3<T>, direction: Vector3<T>) -> Self {
        Ray3 {
            origin: origin,
            direction: Unit::new_normalize(direction),
        }
    }

    pub fn x() -> Self {
        Ray3::new(Point3::origin(), Vector3::x())
    }

    pub fn y() -> Self {
        Ray3::new(Point3::origin(), Vector3::y())
    }

    pub fn z() -> Self {
        Ray3::new(Point3::origin(), Vector3::z())
    }
}

pub trait Matrix4Ext<T>
where
    T: Scalar,
{
    fn to_array(&self) -> [[T; 4]; 4];
}

impl<T> Matrix4Ext<T> for Matrix4<T>
where
    T: Scalar,
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn to_array(&self) -> [[T; 4]; 4] {
        [
            [self[0],  self[1],  self[2],  self[3]],
            [self[4],  self[5],  self[6],  self[7]],
            [self[8],  self[9],  self[10], self[11]],
            [self[12], self[13], self[14], self[15]]
        ]
    }
}

// TODO: The `FromSpace` and `IntoSpace` traits may not be useful. Instead, the
//       `nalgebra::convert` function can be used directly.
pub trait FromSpace<T> {
    fn from_space(value: T) -> Self;
}

impl<T, U> FromSpace<Point2<U>> for Point2<T>
where
    T: SupersetOf<U> + Scalar,
    U: Scalar,
{
    fn from_space(point: Point2<U>) -> Self {
        nalgebra::convert(point)
    }
}

impl<T, U> FromSpace<Point3<U>> for Point3<T>
where
    T: SupersetOf<U> + Scalar,
    U: Scalar,
{
    fn from_space(point: Point3<U>) -> Self {
        nalgebra::convert(point)
    }
}

impl<T, U> FromSpace<Vector3<U>> for Vector3<T>
where
    T: SupersetOf<U> + Scalar,
    U: Scalar,
{
    fn from_space(vector: Vector3<U>) -> Self {
        nalgebra::convert(vector)
    }
}

pub trait IntoSpace<T> {
    fn into_space(self) -> T;
}

impl<T, U> IntoSpace<U> for T
where
    U: FromSpace<T>,
{
    fn into_space(self) -> U {
        U::from_space(self)
    }
}

pub trait Clamp<T>
where
    T: PartialOrd,
{
    fn clamp(&self, min: T, max: T) -> Self;
}

impl<T> Clamp<T> for Point3<T>
where
    T: PartialOrd + Scalar,
{
    fn clamp(&self, min: T, max: T) -> Self {
        use nalgebra::clamp;

        Point3::new(
            clamp(self.x, min, max),
            clamp(self.y, min, max),
            clamp(self.z, min, max),
        )
    }
}

pub trait Mask<T>
where
    T: ops::BitAnd<Output = T>,
{
    fn mask(&self, value: T) -> Self;
}

impl<T> Mask<T> for Point3<T>
where
    T: ops::BitAnd<Output = T> + Scalar,
{
    fn mask(&self, value: T) -> Self {
        Point3::new(self.x & value, self.y & value, self.z & value)
    }
}

pub trait UpperBound {
    fn upper_bound(&self, other: &Self) -> Self;
}

impl<T> UpperBound for Point3<T>
where
    T: Ord + Scalar,
{
    fn upper_bound(&self, other: &Self) -> Self {
        Point3::new(
            cmp::max(self.x, other.x),
            cmp::max(self.y, other.y),
            cmp::max(self.z, other.z),
        )
    }
}

pub trait LowerBound {
    fn lower_bound(&self, other: &Self) -> Self;
}

impl<T> LowerBound for Point3<T>
where
    T: Ord + Scalar,
{
    fn lower_bound(&self, other: &Self) -> Self {
        Point3::new(
            cmp::min(self.x, other.x),
            cmp::min(self.y, other.y),
            cmp::min(self.z, other.z),
        )
    }
}

pub trait Interpolate<F>: Sized
where
    F: Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self;

    fn midpoint(&self, other: &Self) -> Self {
        self.lerp(other, F::one() / (F::one() + F::one()))
    }
}

impl<T, F> Interpolate<F> for (T, T)
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        (lerp(self.0, other.0, f), lerp(self.1, other.1, f))
    }
}

impl<T, F> Interpolate<F> for (T, T, T)
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        (
            lerp(self.0, other.0, f),
            lerp(self.1, other.1, f),
            lerp(self.2, other.2, f),
        )
    }
}

impl<T, F> Interpolate<F> for Point2<T>
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        Point2::new(lerp(self.x, other.x, f), lerp(self.y, other.y, f))
    }
}

impl<T, F> Interpolate<F> for Point3<T>
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    fn lerp(&self, other: &Self, f: F) -> Self {
        Point3::new(
            lerp(self.x, other.x, f),
            lerp(self.y, other.y, f),
            lerp(self.z, other.z, f),
        )
    }
}

pub fn lerp<T, F>(a: T, b: T, f: F) -> T
where
    T: SupersetOf<F> + Scalar,
    F: SupersetOf<T> + Float,
{
    use nalgebra::{convert, clamp};

    let f = clamp(f, F::zero(), F::one());
    let af = convert::<T, F>(a) * (F::one() - f);
    let bf = convert::<T, F>(b) * f;
    convert::<F, T>(af + bf)
}

pub fn ordered_pair<T>(a: T, b: T) -> (T, T)
where
    T: PartialOrd,
{
    if a <= b {
        (a, b)
    }
    else {
        (b, a)
    }
}

pub fn partial_min<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a <= b {
        a
    }
    else {
        b
    }
}

pub fn partial_max<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a > b {
        a
    }
    else {
        b
    }
}

pub fn umod<T>(n: T, m: T) -> T
where
    T: Copy + Integer,
{
    ((n % m) + m) % m
}

#[cfg(test)]
mod tests {
    use super::*;
}
<|endoftext|>


<commit_before>use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use syntax::visit::{FnKind};
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr};
use syntax::codemap::Span;

use types::span_note_and_lint;

/// Handles uncategorized lints
/// Currently handles linting of if-let-able matches
#[allow(missing_copy_implementations)]
pub struct MiscPass;

declare_lint!(pub SINGLE_MATCH, Warn,
              "Warn on usage of matches with a single nontrivial arm");

impl LintPass for MiscPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node {
            if arms.len() == 2 {
                if arms[0].guard.is_none() && arms[1].pats.len() == 1 {
                    match arms[1].body.node {
                        ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (),
                        ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (),
                         _ => return
                    }
                    // In some cases, an exhaustive match is preferred to catch situations when
                    // an enum is extended. So we only consider cases where a `_` wildcard is used
                    if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 {
                        let map = cx.sess().codemap();
                        span_note_and_lint(cx, SINGLE_MATCH, expr.span,
                              "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?",
                              format!("Try if let {} = {} {{ ... }}",
                                      map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()),
                                      map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice()
                        );
                    }
                }
            }
        }
    }
}

declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()");

#[allow(missing_copy_implementations)]
pub struct StrToStringPass;

impl LintPass for StrToStringPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(STR_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        match expr.node {
            ast::ExprMethodCall(ref method, _, ref args)
                if method.node.as_str() == "to_string"
                && is_str(cx, &*args[0]) => {
                cx.span_lint(STR_TO_STRING, expr.span, "str.into_string() is faster");
            },
            _ => ()
        }

        fn is_str(cx: &Context, expr: &ast::Expr) -> bool {
            fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
                //println!("{}: -> {}", depth, ty);
                match ty.sty {
                    ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty),
                    _ => ty
                }
            }
            match walk_ty(expr_ty(cx.tcx, expr)).sty {
                ty_str => true,
                _ => false
            }
        }
    }
}

declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOPLEVEL_REF_ARG)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        for ref arg in decl.inputs.iter() {
            if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
                cx.span_lint(
                    TOPLEVEL_REF_ARG,
                    arg.pat.span,
                    "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
                );
            }
        }
    }
}
<commit_msg>into_string() -> to_owned() (fix #27)<commit_after>use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use syntax::visit::{FnKind};
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr};
use syntax::codemap::Span;

use types::span_note_and_lint;

/// Handles uncategorized lints
/// Currently handles linting of if-let-able matches
#[allow(missing_copy_implementations)]
pub struct MiscPass;

declare_lint!(pub SINGLE_MATCH, Warn,
              "Warn on usage of matches with a single nontrivial arm");

impl LintPass for MiscPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node {
            if arms.len() == 2 {
                if arms[0].guard.is_none() && arms[1].pats.len() == 1 {
                    match arms[1].body.node {
                        ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (),
                        ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (),
                         _ => return
                    }
                    // In some cases, an exhaustive match is preferred to catch situations when
                    // an enum is extended. So we only consider cases where a `_` wildcard is used
                    if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 {
                        let map = cx.sess().codemap();
                        span_note_and_lint(cx, SINGLE_MATCH, expr.span,
                              "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?",
                              format!("Try if let {} = {} {{ ... }}",
                                      map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()),
                                      map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice()
                        );
                    }
                }
            }
        }
    }
}

declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use to_owned() instead of to_string()");

#[allow(missing_copy_implementations)]
pub struct StrToStringPass;

impl LintPass for StrToStringPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(STR_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        match expr.node {
            ast::ExprMethodCall(ref method, _, ref args)
                if method.node.as_str() == "to_string"
                && is_str(cx, &*args[0]) => {
                cx.span_lint(STR_TO_STRING, expr.span, "str.to_owned() is faster");
            },
            _ => ()
        }

        fn is_str(cx: &Context, expr: &ast::Expr) -> bool {
            fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
                //println!("{}: -> {}", depth, ty);
                match ty.sty {
                    ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty),
                    _ => ty
                }
            }
            match walk_ty(expr_ty(cx.tcx, expr)).sty {
                ty_str => true,
                _ => false
            }
        }
    }
}

declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOPLEVEL_REF_ARG)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        for ref arg in decl.inputs.iter() {
            if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
                cx.span_lint(
                    TOPLEVEL_REF_ARG,
                    arg.pat.span,
                    "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>/// MPI-based method for summing many arrays

// Argument parsing
// logging
#[macro_use] extern crate log;
#[macro_use] extern crate clap;
extern crate ndarray;
extern crate env_logger;
// lastly, this library
extern crate cabarrus;
use cabarrus::errors::*;

pub fn main() {
    // Main can't return a Result, and the ? operator needs the enclosing function to return Result
    inner_main().expect("Could not recover. Exiting.");
}
pub fn inner_main() -> Result<()> {
    env_logger::init().unwrap();
    let args = app_from_crate!()
        .arg_from_usage("<size> 'how many workers there are'")
        .arg_from_usage("<rank> 'which worker am I, starting from 0'")
        .arg_from_usage("<addends>.. 'files containin matrices to add'")
        .arg_from_usage("<output> 'file in which to store the resulting matrix'")
        .get_matches();

    let mut mats : Vec<&str> = args.values_of("addends").unwrap().collect();
    mats.sort();

    let size = value_t!(args, "size", usize).unwrap_or_else(|e| e.exit());
    let rank = value_t!(args, "rank", usize).unwrap_or_else(|e| e.exit());
    let chunksize = (mats.len() + size - 1) / size;
    info!("{} files, {} workers, chunks of {}", mats.len(), size, chunksize);

    let mut accum = None;
    for matname in mats.into_iter().skip(rank*chunksize).take(chunksize) {
        info!("Reading {}..", matname);
        let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)?;
        let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)?;
        accum = Some(match accum {
            Some(mut acc) => {acc += mat; acc}
            None => mat.to_owned()
        });
    }
    if let Some(ref acc) = accum {
        cabarrus::numpy::write_matrix(args.value_of("output").unwrap(), acc)?;
    } else {
        info!("No matrices processed so nothing saved.");
    }
    Ok(())
}
<commit_msg>A little more debug info still<commit_after>/// MPI-based method for summing many arrays

// Argument parsing
// logging
#[macro_use] extern crate log;
#[macro_use] extern crate clap;
extern crate ndarray;
extern crate env_logger;
// lastly, this library
extern crate cabarrus;
use cabarrus::errors::*;

pub fn main() {
    // Main can't return a Result, and the ? operator needs the enclosing function to return Result
    inner_main().expect("Could not recover. Exiting.");
}
pub fn inner_main() -> Result<()> {
    env_logger::init().unwrap();
    let args = app_from_crate!()
        .arg_from_usage("<size> 'how many workers there are'")
        .arg_from_usage("<rank> 'which worker am I, starting from 0'")
        .arg_from_usage("<addends>.. 'files containing matrices to add'")
        .arg_from_usage("<output> 'file in which to store the resulting matrix'")
        .get_matches();

    let mut mats : Vec<&str> = args.values_of("addends").unwrap().collect();
    mats.sort();

    let size = value_t!(args, "size", usize).unwrap_or_else(|e| e.exit());
    let rank = value_t!(args, "rank", usize).unwrap_or_else(|e| e.exit());
    let chunksize = (mats.len() + size - 1) / size;
    info!("{} files, {} workers (I'm #{}), chunks of {}", mats.len(), size, rank, chunksize);

    let mut accum = None;
    for matname in mats.into_iter().skip(rank*chunksize).take(chunksize) {
        let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)?;
        let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)?;

        info!("Reading {} ({} GB) ..", matname, matname.len() >> 27);
        accum = Some(match accum {
            Some(mut acc) => {acc += mat; acc}
            None => mat.to_owned()
        });
    }
    if let Some(ref acc) = accum {
        cabarrus::numpy::write_matrix(args.value_of("output").unwrap(), acc)?;
    } else {
        info!("No matrices processed so nothing saved.");
    }
    Ok(())
}
<|endoftext|>


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

#![deny(warnings)]

extern crate build_helper;
extern crate cc;

use std::env;
use std::path::PathBuf;
use std::process::Command;
use build_helper::{run, native_lib_boilerplate};

fn main() {
    // FIXME: This is a hack to support building targets that don't
    // support jemalloc alongside hosts that do. The jemalloc build is
    // controlled by a feature of the std crate, and if that feature
    // changes between targets, it invalidates the fingerprint of
    // std's build script (this is a cargo bug); so we must ensure
    // that the feature set used by std is the same across all
    // targets, which means we have to build the alloc_jemalloc crate
    // for targets like emscripten, even if we don't use it.
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if target.contains("bitrig") || target.contains("emscripten") || target.contains("fuchsia") ||
       target.contains("msvc") || target.contains("openbsd") || target.contains("redox") ||
       target.contains("rumprun") || target.contains("wasm32") {
        println!("cargo:rustc-cfg=dummy_jemalloc");
        return;
    }

    // CloudABI ships with a copy of jemalloc that has been patched to
    // work well with sandboxing. Don't attempt to build our own copy,
    // as it won't build.
    if target.contains("cloudabi") {
        return;
    }

    if target.contains("android") {
        println!("cargo:rustc-link-lib=gcc");
    } else if !target.contains("windows") && !target.contains("musl") {
        println!("cargo:rustc-link-lib=pthread");
    }

    if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
        let jemalloc = PathBuf::from(jemalloc);
        println!("cargo:rustc-link-search=native={}",
                 jemalloc.parent().unwrap().display());
        let stem = jemalloc.file_stem().unwrap().to_str().unwrap();
        let name = jemalloc.file_name().unwrap().to_str().unwrap();
        let kind = if name.ends_with(".a") {
            "static"
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]);
        return;
    }

    let link_name = if target.contains("windows") { "jemalloc" } else { "jemalloc_pic" };
    let native = match native_lib_boilerplate("jemalloc", "jemalloc", link_name, "lib") {
        Ok(native) => native,
        _ => return,
    };

    let mut cmd = Command::new("sh");
    cmd.arg(native.src_dir.join("configure")
                          .to_str()
                          .unwrap()
                          .replace("C:\\", "/c/")
                          .replace("\\", "/"))
       .current_dir(&native.out_dir)
       // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
       // that GCC will run the preprocessor, and only the preprocessor, over
       // jemalloc's source files. If we don't specify CPPFLAGS, then at least
       // on ARM that step fails with a "Missing implementation for 32-bit
       // atomic operations" error. This is because no "-march" flag will be
       // passed to GCC, and then GCC won't define the
       // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
       // select an atomic operation implementation.
       .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default());

    if target.contains("ios") {
        cmd.arg("--disable-tls");
    } else if target.contains("android") {
        // We force android to have prefixed symbols because apparently
        // replacement of the libc allocator doesn't quite work. When this was
        // tested (unprefixed symbols), it was found that the `realpath`
        // function in libc would allocate with libc malloc (not jemalloc
        // malloc), and then the standard library would free with jemalloc free,
        // causing a segfault.
        //
        // If the test suite passes, however, without symbol prefixes then we
        // should be good to go!
        cmd.arg("--with-jemalloc-prefix=je_");
        cmd.arg("--disable-tls");
    } else if target.contains("dragonfly") || target.contains("musl") {
        cmd.arg("--with-jemalloc-prefix=je_");
    }

    // FIXME: building with jemalloc assertions is currently broken.
    // See <https://github.com/rust-lang/rust/issues/44152>.
    //if cfg!(feature = "debug") {
    //    cmd.arg("--enable-debug");
    //}

    cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
    cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));

    // for some reason, jemalloc configure doesn't detect this value
    // automatically for this target
    if target == "sparc64-unknown-linux-gnu" {
        cmd.arg("--with-lg-quantum=4");
    }

    run(&mut cmd);

    let mut make = Command::new(build_helper::make(&host));
    make.current_dir(&native.out_dir)
        .arg("build_lib_static");

    // These are intended for mingw32-make which we don't use
    if cfg!(windows) {
        make.env_remove("MAKEFLAGS").env_remove("MFLAGS");
    }

    // mingw make seems... buggy? unclear...
    if !host.contains("windows") {
        make.arg("-j")
            .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"));
    }

    run(&mut make);

    // The pthread_atfork symbols is used by jemalloc on android but the really
    // old android we're building on doesn't have them defined, so just make
    // sure the symbols are available.
    if target.contains("androideabi") {
        println!("cargo:rerun-if-changed=pthread_atfork_dummy.c");
        cc::Build::new()
            .flag("-fvisibility=hidden")
            .file("pthread_atfork_dummy.c")
            .compile("pthread_atfork_dummy");
    }
}
<commit_msg>Auto merge of #52906 - RalfJung:jemalloc, r=alexcrichton<commit_after>// Copyright 2015 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.

#![deny(warnings)]

extern crate build_helper;
extern crate cc;

use std::env;
use std::path::PathBuf;
use std::process::Command;
use build_helper::{run, native_lib_boilerplate};

fn main() {
    // FIXME: This is a hack to support building targets that don't
    // support jemalloc alongside hosts that do. The jemalloc build is
    // controlled by a feature of the std crate, and if that feature
    // changes between targets, it invalidates the fingerprint of
    // std's build script (this is a cargo bug); so we must ensure
    // that the feature set used by std is the same across all
    // targets, which means we have to build the alloc_jemalloc crate
    // for targets like emscripten, even if we don't use it.
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if target.contains("bitrig") || target.contains("emscripten") || target.contains("fuchsia") ||
       target.contains("msvc") || target.contains("openbsd") || target.contains("redox") ||
       target.contains("rumprun") || target.contains("wasm32") {
        println!("cargo:rustc-cfg=dummy_jemalloc");
        return;
    }

    // CloudABI ships with a copy of jemalloc that has been patched to
    // work well with sandboxing. Don't attempt to build our own copy,
    // as it won't build.
    if target.contains("cloudabi") {
        return;
    }

    if target.contains("android") {
        println!("cargo:rustc-link-lib=gcc");
    } else if !target.contains("windows") && !target.contains("musl") {
        println!("cargo:rustc-link-lib=pthread");
    }

    if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
        let jemalloc = PathBuf::from(jemalloc);
        println!("cargo:rustc-link-search=native={}",
                 jemalloc.parent().unwrap().display());
        let stem = jemalloc.file_stem().unwrap().to_str().unwrap();
        let name = jemalloc.file_name().unwrap().to_str().unwrap();
        let kind = if name.ends_with(".a") {
            "static"
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]);
        return;
    }

    let link_name = if target.contains("windows") { "jemalloc" } else { "jemalloc_pic" };
    let native = match native_lib_boilerplate("jemalloc", "jemalloc", link_name, "lib") {
        Ok(native) => native,
        _ => return,
    };

    let mut cmd = Command::new("sh");
    cmd.arg(native.src_dir.join("configure")
                          .to_str()
                          .unwrap()
                          .replace("C:\\", "/c/")
                          .replace("\\", "/"))
       .current_dir(&native.out_dir)
       // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
       // that GCC will run the preprocessor, and only the preprocessor, over
       // jemalloc's source files. If we don't specify CPPFLAGS, then at least
       // on ARM that step fails with a "Missing implementation for 32-bit
       // atomic operations" error. This is because no "-march" flag will be
       // passed to GCC, and then GCC won't define the
       // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
       // select an atomic operation implementation.
       .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default());

    if target.contains("ios") {
        cmd.arg("--disable-tls");
    } else if target.contains("android") {
        // We force android to have prefixed symbols because apparently
        // replacement of the libc allocator doesn't quite work. When this was
        // tested (unprefixed symbols), it was found that the `realpath`
        // function in libc would allocate with libc malloc (not jemalloc
        // malloc), and then the standard library would free with jemalloc free,
        // causing a segfault.
        //
        // If the test suite passes, however, without symbol prefixes then we
        // should be good to go!
        cmd.arg("--with-jemalloc-prefix=je_");
        cmd.arg("--disable-tls");
    } else if target.contains("dragonfly") || target.contains("musl") {
        cmd.arg("--with-jemalloc-prefix=je_");
    }

    if cfg!(feature = "debug") {
        // Enable jemalloc assertions.
        cmd.arg("--enable-debug");
    }

    cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
    cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));

    // for some reason, jemalloc configure doesn't detect this value
    // automatically for this target
    if target == "sparc64-unknown-linux-gnu" {
        cmd.arg("--with-lg-quantum=4");
    }

    run(&mut cmd);

    let mut make = Command::new(build_helper::make(&host));
    make.current_dir(&native.out_dir)
        .arg("build_lib_static");

    // These are intended for mingw32-make which we don't use
    if cfg!(windows) {
        make.env_remove("MAKEFLAGS").env_remove("MFLAGS");
    }

    // mingw make seems... buggy? unclear...
    if !host.contains("windows") {
        make.arg("-j")
            .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"));
    }

    run(&mut make);

    // The pthread_atfork symbols is used by jemalloc on android but the really
    // old android we're building on doesn't have them defined, so just make
    // sure the symbols are available.
    if target.contains("androideabi") {
        println!("cargo:rerun-if-changed=pthread_atfork_dummy.c");
        cc::Build::new()
            .flag("-fvisibility=hidden")
            .file("pthread_atfork_dummy.c")
            .compile("pthread_atfork_dummy");
    }
}
<|endoftext|>


<commit_before>use neb::ram::schema::Field;
use neb::ram::types::TypeId;

lazy_static! {
    pub static ref VERTEX_TEMPLATE: Vec<Field> = vec![
            Field::new(&String::from("_inbound"), TypeId::Id as u32, true, false, None),
            Field::new(&String::from("_outbound"), TypeId::Id as u32, true, false, None),
            Field::new(&String::from("_indirected"), TypeId::Id as u32, true, false, None)
        ];
}<commit_msg>factory mode?<commit_after>use neb::ram::schema::Field;
use neb::ram::types::TypeId;
use neb::ram::cell::Cell;
use neb::client::{Client as NebClient};
use server::schema::{MorpheusSchema, SchemaType, SchemaContainer};
use std::sync::Arc;

lazy_static! {
    pub static ref VERTEX_TEMPLATE: Vec<Field> = vec![
            Field::new(&String::from("_inbound"), TypeId::Id as u32, true, false, None),
            Field::new(&String::from("_outbound"), TypeId::Id as u32, true, false, None),
            Field::new(&String::from("_indirected"), TypeId::Id as u32, true, false, None)
        ];
}

pub struct VertexFactory {
    schema: Arc<SchemaContainer>,
    neb_client: Arc<NebClient>
}<|endoftext|>


<commit_before>//! Safe-interface corresponding to out-place transform

use super::aligned_vec::*;
use super::error::*;
use super::plan::*;

use ndarray::*;
use ndarray_linalg::Scalar;

/// Safe-interface corresponding to out-place transform
///
/// FFTW interface modifies an array in `fftw_execute` function
/// which does not takes the array as its arguments.
/// It is not compatible to the programing model of safe Rust.
/// `Pair` interface composes the array and plan to manage
/// mutability in the safe Rust way.
pub struct Pair<A, B, D: Dimension>
where
    A: Scalar,
    B: Scalar<Real = A::Real>,
{
    pub a: AlignedArray<A, D>,
    pub b: AlignedArray<B, D>,
    pub(crate) forward: Plan<B>,
    pub(crate) backward: Plan<A>,
}

impl<A, B, D: Dimension> Pair<A, B, D>
where
    A: Scalar,
    B: Scalar<Real = A::Real>,
{
    // /// Execute `Pair::forward` with `ndarray::ArrayView`
    // pub fn forward_array<'a, 'b>(&'a mut self, input: ArrayView<'b, A, D>) -> ArrayViewMut<'a, B, D> {
    //     let sl = self.forward(input.as_slice().unwrap());
    //     ArrayViewMut::from(sl).into_shape(dim).unwrap()
    // }
    //
    // /// Execute `Pair::backward` with `ndarray::ArrayView`
    // pub fn backward_array<'a, 'b>(&'a mut self, input: ArrayView<'b, B, D>) -> ArrayViewMut<'a, A, D> {
    //     let dim = self.a_dim();
    //     let sl = self.backward(input.as_slice().unwrap());
    //     ArrayViewMut::from(sl).into_shape(dim).unwrap()
    // }

    /// Executes copy the input to `a`, forward transform,
    /// and returns the result `b` as a reference
    pub fn forward(&mut self, input: &[A]) -> &mut [B] {
        self.a.copy_from_slice(input);
        self.exec_forward();
        self.b.as_slice_mut()
    }

    /// Execute copy to pair, forward transform,
    /// and returns a reference of the result.
    pub fn backward(&mut self, input: &[B]) -> &mut [A]
    where
        A: Scalar,
        B: Scalar,
    {
        self.b.copy_from_slice(input);
        self.exec_backward();
        self.a.as_slice_mut()
    }

    /// Execute a forward transform (`a` to `b`)
    pub fn exec_forward(&mut self) {
        unsafe { self.forward.execute() }
        self.forward.normalize(self.b.as_slice_mut());
    }

    /// Execute a backward transform (`b` to `a`)
    pub fn exec_backward(&mut self) {
        unsafe { self.backward.execute() }
        self.backward.normalize(self.a.as_slice_mut());
    }

    pub(crate) fn null_checked(self) -> Result<Self> {
        self.forward.check_null()?;
        self.backward.check_null()?;
        Ok(self)
    }
}

/// Create a `Pair` from a setting struct e.g. `R2C1D`.
pub trait ToPair<A, B>
where
    A: Scalar,
    B: Scalar<Real = A::Real>,
{
    type Dim: Dimension;
    /// Generate `Pair` from a setting struct
    fn to_pair(&self) -> Result<Pair<A, B, Self::Dim>>;
}
<commit_msg>Re-enable {forward,backward}_array<commit_after>//! Safe-interface corresponding to out-place transform

use super::aligned_vec::*;
use super::error::*;
use super::plan::*;

use ndarray::*;
use ndarray_linalg::Scalar;

/// Safe-interface corresponding to out-place transform
///
/// FFTW interface modifies an array in `fftw_execute` function
/// which does not takes the array as its arguments.
/// It is not compatible to the programing model of safe Rust.
/// `Pair` interface composes the array and plan to manage
/// mutability in the safe Rust way.
pub struct Pair<A, B, D: Dimension>
where
    A: Scalar,
    B: Scalar<Real = A::Real>,
{
    pub a: AlignedArray<A, D>,
    pub b: AlignedArray<B, D>,
    pub(crate) forward: Plan<B>,
    pub(crate) backward: Plan<A>,
}

impl<A, B, D: Dimension> Pair<A, B, D>
where
    A: Scalar,
    B: Scalar<Real = A::Real>,
{
    /// Execute `Pair::forward` with `ndarray::ArrayView`
    pub fn forward_array<'a, 'b>(&'a mut self, input: ArrayView<'b, A, D>) -> ArrayViewMut<'a, B, D> {
        self.a.as_view_mut().assign(&input);
        self.exec_forward();
        self.b.as_view_mut()
    }

    /// Execute `Pair::backward` with `ndarray::ArrayView`
    pub fn backward_array<'a, 'b>(&'a mut self, input: ArrayView<'b, B, D>) -> ArrayViewMut<'a, A, D> {
        self.b.as_view_mut().assign(&input);
        self.exec_backward();
        self.a.as_view_mut()
    }

    /// Executes copy the input to `a`, forward transform,
    /// and returns the result `b` as a reference
    pub fn forward(&mut self, input: &[A]) -> &mut [B] {
        self.a.copy_from_slice(input);
        self.exec_forward();
        self.b.as_slice_mut()
    }

    /// Execute copy to pair, forward transform,
    /// and returns a reference of the result.
    pub fn backward(&mut self, input: &[B]) -> &mut [A] {
        self.b.copy_from_slice(input);
        self.exec_backward();
        self.a.as_slice_mut()
    }

    /// Execute a forward transform (`a` to `b`)
    pub fn exec_forward(&mut self) {
        unsafe { self.forward.execute() }
        self.forward.normalize(self.b.as_slice_mut());
    }

    /// Execute a backward transform (`b` to `a`)
    pub fn exec_backward(&mut self) {
        unsafe { self.backward.execute() }
        self.backward.normalize(self.a.as_slice_mut());
    }

    pub(crate) fn null_checked(self) -> Result<Self> {
        self.forward.check_null()?;
        self.backward.check_null()?;
        Ok(self)
    }
}

/// Create a `Pair` from a setting struct e.g. `R2C1D`.
pub trait ToPair<A, B>
where
    A: Scalar,
    B: Scalar<Real = A::Real>,
{
    type Dim: Dimension;
    /// Generate `Pair` from a setting struct
    fn to_pair(&self) -> Result<Pair<A, B, Self::Dim>>;
}
<|endoftext|>


<commit_before>//! Creating paths and manipulating path data

use std;

///  A data structure for holding a path. This data structure serves as the return value for cairo_copy_path() and cairo_copy_path_flat() as well the input value for cairo_append_path().
///
/// See cairo_path_data_t for hints on how to iterate over the actual data within the path.
///
/// The num_data member gives the number of elements in the data array. This number is larger than the number of independent path portions (defined in cairo_path_data_type_t), since the data includes both headers and coordinates for each portion.
///
/// cairo_status_t status; the current error status
///
/// cairo_path_data_t *data; the elements in the path
///
/// int num_data; the number of elements in the data array
///
/// Since 1.0
pub struct Path {
  /// Wraps Cairo pointer for path.
  opaque: *mut std::libc::c_void
}

impl std::ops::Drop for Path {
  fn drop(&mut self) {
    unsafe {
      cairo_path_destroy(self.opaque);
    }
  }
}

extern {
  fn cairo_path_destroy(self_value: *mut std::libc::c_void);
}

<commit_msg>Replaced Cairo ´_t' types with Rust-Cairo types<commit_after>//! Creating paths and manipulating path data

use std;

///  A data structure for holding a path. This data structure serves as the return value for cairo_copy_path() and cairo_copy_path_flat() as well the input value for cairo_append_path().
///
/// See cairo_path_data_t for hints on how to iterate over the actual data within the path.
///
/// The num_data member gives the number of elements in the data array. This number is larger than the number of independent path portions (defined in cairo_path_data_type_t), since the data includes both headers and coordinates for each portion.
///
/// Status status; the current error status
///
/// cairo_path_data_t *data; the elements in the path
///
/// int num_data; the number of elements in the data array
///
/// Since 1.0
pub struct Path {
  /// Wraps Cairo pointer for path.
  opaque: *mut std::libc::c_void
}

impl std::ops::Drop for Path {
  fn drop(&mut self) {
    unsafe {
      cairo_path_destroy(self.opaque);
    }
  }
}

extern {
  fn cairo_path_destroy(self_value: *mut std::libc::c_void);
}

<|endoftext|>