<commit_before>use markup5ever::LocalName;
use std::collections::HashMap;

use crate::clip_path::NodeClipPath;
use crate::filters::{
    blend::Blend,
    color_matrix::ColorMatrix,
    component_transfer::{ComponentTransfer, FuncX},
    composite::Composite,
    convolve_matrix::ConvolveMatrix,
    displacement_map::DisplacementMap,
    flood::Flood,
    gaussian_blur::GaussianBlur,
    image::Image,
    light::{light_source::LightSource, lighting::Lighting},
    merge::{Merge, MergeNode},
    morphology::Morphology,
    node::NodeFilter,
    offset::Offset,
    tile::Tile,
    turbulence::Turbulence,
};
use crate::gradient::NodeGradient;
use crate::image::NodeImage;
use crate::link::NodeLink;
use crate::marker::NodeMarker;
use crate::mask::NodeMask;
use crate::node::*;
use crate::pattern::NodePattern;
use crate::property_bag::PropertyBag;
use crate::shapes::{NodeCircle, NodeEllipse, NodeLine, NodePath, NodePoly, NodeRect};
use crate::stop::NodeStop;
use crate::structure::{NodeGroup, NodeNonRendering, NodeSvg, NodeSwitch, NodeSymbol, NodeUse};
use crate::style::NodeStyle;
use crate::text::{NodeTRef, NodeTSpan, NodeText};

macro_rules! n {
    ($name:ident, $node_type:ident, $new_fn:expr) => {
        pub fn $name(
            element_name: LocalName,
            id: Option<&str>,
            class: Option<&str>,
            parent: Option<&RsvgNode>,
        ) -> RsvgNode {
            RsvgNode::new(
                NodeData::new(
                    NodeType::$node_type,
                    element_name,
                    id,
                    class,
                    Box::new($new_fn()),
                ),
                parent,
            )
        }
    };
}

#[cfg_attr(rustfmt, rustfmt_skip)]
mod creators {
    use super::*;

    n!(create_circle,                    Circle,                     NodeCircle::new);
    n!(create_clip_path,                 ClipPath,                   NodeClipPath::new);
    n!(create_blend,                     FeBlend,                    Blend::new);
    n!(create_color_matrix,              FeColorMatrix,              ColorMatrix::new);
    n!(create_component_transfer,        FeComponentTransfer,        ComponentTransfer::new);
    n!(create_component_transfer_func_a, ComponentTransferFunctionA, FuncX::new_a);
    n!(create_component_transfer_func_b, ComponentTransferFunctionB, FuncX::new_b);
    n!(create_component_transfer_func_g, ComponentTransferFunctionG, FuncX::new_g);
    n!(create_component_transfer_func_r, ComponentTransferFunctionR, FuncX::new_r);
    n!(create_composite,                 FeComposite,                Composite::new);
    n!(create_convolve_matrix,           FeConvolveMatrix,           ConvolveMatrix::new);
    n!(create_defs,                      Defs,                       NodeNonRendering::new);
    n!(create_diffuse_lighting,          FeDiffuseLighting,          Lighting::new_diffuse);
    n!(create_distant_light,             DistantLight,               LightSource::new_distant_light);
    n!(create_displacement_map,          FeDisplacementMap,          DisplacementMap::new);
    n!(create_ellipse,                   Ellipse,                    NodeEllipse::new);
    n!(create_filter,                    Filter,                     NodeFilter::new);
    n!(create_flood,                     FeFlood,                    Flood::new);
    n!(create_gaussian_blur,             FeGaussianBlur,             GaussianBlur::new);
    n!(create_group,                     Group,                      NodeGroup::new);
    n!(create_image,                     Image,                      NodeImage::new);
    n!(create_fe_image,                  FeImage,                    Image::new);
    n!(create_linear_gradient,           LinearGradient,             NodeGradient::new_linear);
    n!(create_line,                      Line,                       NodeLine::new);
    n!(create_link,                      Link,                       NodeLink::new);
    n!(create_marker,                    Marker,                     NodeMarker::new);
    n!(create_mask,                      Mask,                       NodeMask::new);
    n!(create_merge,                     FeMerge,                    Merge::new);
    n!(create_merge_node,                FeMergeNode,                MergeNode::new);
    n!(create_morphology,                FeMorphology,               Morphology::new);
    n!(create_non_rendering,             NonRendering,               NodeNonRendering::new);
    n!(create_offset,                    FeOffset,                   Offset::new);
    n!(create_path,                      Path,                       NodePath::new);
    n!(create_pattern,                   Pattern,                    NodePattern::new);
    n!(create_point_light,               PointLight,                 LightSource::new_point_light);
    n!(create_polygon,                   Polygon,                    NodePoly::new_closed);
    n!(create_polyline,                  Polyline,                   NodePoly::new_open);
    n!(create_radial_gradient,           RadialGradient,             NodeGradient::new_radial);
    n!(create_rect,                      Rect,                       NodeRect::new);
    n!(create_specular_lighting,         FeSpecularLighting,         Lighting::new_specular);
    n!(create_spot_light,                SpotLight,                  LightSource::new_spot_light);
    n!(create_stop,                      Stop,                       NodeStop::new);
    n!(create_style,                     Style,                      NodeStyle::new);
    n!(create_svg,                       Svg,                        NodeSvg::new);
    n!(create_switch,                    Switch,                     NodeSwitch::new);
    n!(create_symbol,                    Symbol,                     NodeSymbol::new);
    n!(create_text,                      Text,                       NodeText::new);
    n!(create_tref,                      TRef,                       NodeTRef::new);
    n!(create_tspan,                     TSpan,                      NodeTSpan::new);
    n!(create_tile,                      FeTile,                     Tile::new);
    n!(create_turbulence,                FeTurbulence,               Turbulence::new);
    n!(create_use,                       Use,                        NodeUse::new);

    // hack to partially support conical gradient
    n!(create_conical_gradient,          RadialGradient,             NodeGradient::new_radial);

    // hack to make multiImage sort-of work
    n!(create_multi_image,               Switch,                     NodeSwitch::new);
    n!(create_sub_image,                 Group,                      NodeGroup::new);
    n!(create_sub_image_ref,             Image,                      NodeImage::new);
}

use creators::*;

type NodeCreateFn = fn(
    element_name: LocalName,
    id: Option<&str>,
    class: Option<&str>,
    parent: Option<&RsvgNode>,
) -> RsvgNode;

lazy_static! {
    // Lines in comments are elements that we don't support.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    static ref NODE_CREATORS: HashMap<&'static str, (bool, NodeCreateFn)> = {
        let mut h = HashMap::new();
        h.insert("a",                   (true,  create_link as NodeCreateFn));
        /* h.insert("altGlyph",         (true,  as NodeCreateFn)); */
        /* h.insert("altGlyphDef",      (false, as NodeCreateFn)); */
        /* h.insert("altGlyphItem",     (false, as NodeCreateFn)); */
        /* h.insert("animate",          (false, as NodeCreateFn)); */
        /* h.insert("animateColor",     (false, as NodeCreateFn)); */
        /* h.insert("animateMotion",    (false, as NodeCreateFn)); */
        /* h.insert("animateTransform", (false, as NodeCreateFn)); */
        h.insert("circle",              (true,  create_circle as NodeCreateFn));
        h.insert("clipPath",            (true,  create_clip_path as NodeCreateFn));
        /* h.insert("color-profile",    (false, as NodeCreateFn)); */
        h.insert("conicalGradient",     (true,  create_conical_gradient as NodeCreateFn));
        /* h.insert("cursor",           (false, as NodeCreateFn)); */
        h.insert("defs",                (true,  create_defs as NodeCreateFn));
        /* h.insert("desc",             (true,  as NodeCreateFn)); */
        h.insert("ellipse",             (true,  create_ellipse as NodeCreateFn));
        h.insert("feBlend",             (true,  create_blend as NodeCreateFn));
        h.insert("feColorMatrix",       (true,  create_color_matrix as NodeCreateFn));
        h.insert("feComponentTransfer", (true,  create_component_transfer as NodeCreateFn));
        h.insert("feComposite",         (true,  create_composite as NodeCreateFn));
        h.insert("feConvolveMatrix",    (true,  create_convolve_matrix as NodeCreateFn));
        h.insert("feDiffuseLighting",   (true,  create_diffuse_lighting as NodeCreateFn));
        h.insert("feDisplacementMap",   (true,  create_displacement_map as NodeCreateFn));
        h.insert("feDistantLight",      (false, create_distant_light as NodeCreateFn));
        h.insert("feFuncA",             (false, create_component_transfer_func_a as NodeCreateFn));
        h.insert("feFuncB",             (false, create_component_transfer_func_b as NodeCreateFn));
        h.insert("feFuncG",             (false, create_component_transfer_func_g as NodeCreateFn));
        h.insert("feFuncR",             (false, create_component_transfer_func_r as NodeCreateFn));
        h.insert("feFlood",             (true,  create_flood as NodeCreateFn));
        h.insert("feGaussianBlur",      (true,  create_gaussian_blur as NodeCreateFn));
        h.insert("feImage",             (true,  create_fe_image as NodeCreateFn));
        h.insert("feMerge",             (true,  create_merge as NodeCreateFn));
        h.insert("feMergeNode",         (false, create_merge_node as NodeCreateFn));
        h.insert("feMorphology",        (true,  create_morphology as NodeCreateFn));
        h.insert("feOffset",            (true,  create_offset as NodeCreateFn));
        h.insert("fePointLight",        (false, create_point_light as NodeCreateFn));
        h.insert("feSpecularLighting",  (true,  create_specular_lighting as NodeCreateFn));
        h.insert("feSpotLight",         (false, create_spot_light as NodeCreateFn));
        h.insert("feTile",              (true,  create_tile as NodeCreateFn));
        h.insert("feTurbulence",        (true,  create_turbulence as NodeCreateFn));
        h.insert("filter",              (true,  create_filter as NodeCreateFn));
        /* h.insert("font",             (true,  as NodeCreateFn)); */
        /* h.insert("font-face",        (false, as NodeCreateFn)); */
        /* h.insert("font-face-format", (false, as NodeCreateFn)); */
        /* h.insert("font-face-name",   (false, as NodeCreateFn)); */
        /* h.insert("font-face-src",    (false, as NodeCreateFn)); */
        /* h.insert("font-face-uri",    (false, as NodeCreateFn)); */
        /* h.insert("foreignObject",    (true,  as NodeCreateFn)); */
        h.insert("g",                   (true,  create_group as NodeCreateFn));
        /* h.insert("glyph",            (true,  as NodeCreateFn)); */
        /* h.insert("glyphRef",         (true,  as NodeCreateFn)); */
        /* h.insert("hkern",            (false, as NodeCreateFn)); */
        h.insert("image",               (true,  create_image as NodeCreateFn));
        h.insert("line",                (true,  create_line as NodeCreateFn));
        h.insert("linearGradient",      (true,  create_linear_gradient as NodeCreateFn));
        h.insert("marker",              (true,  create_marker as NodeCreateFn));
        h.insert("mask",                (true,  create_mask as NodeCreateFn));
        /* h.insert("metadata",         (false, as NodeCreateFn)); */
        /* h.insert("missing-glyph",    (true,  as NodeCreateFn)); */
        /* h.insert("mpath",            (false, as NodeCreateFn)); */
        h.insert("multiImage",          (false, create_multi_image as NodeCreateFn));
        h.insert("path",                (true,  create_path as NodeCreateFn));
        h.insert("pattern",             (true,  create_pattern as NodeCreateFn));
        h.insert("polygon",             (true,  create_polygon as NodeCreateFn));
        h.insert("polyline",            (true,  create_polyline as NodeCreateFn));
        h.insert("radialGradient",      (true,  create_radial_gradient as NodeCreateFn));
        h.insert("rect",                (true,  create_rect as NodeCreateFn));
        /* h.insert("script",           (false, as NodeCreateFn)); */
        /* h.insert("set",              (false, as NodeCreateFn)); */
        h.insert("stop",                (true,  create_stop as NodeCreateFn));
        h.insert("style",               (false, create_style as NodeCreateFn));
        h.insert("subImage",            (false, create_sub_image as NodeCreateFn));
        h.insert("subImageRef",         (false, create_sub_image_ref as NodeCreateFn));
        h.insert("svg",                 (true,  create_svg as NodeCreateFn));
        h.insert("switch",              (true,  create_switch as NodeCreateFn));
        h.insert("symbol",              (true,  create_symbol as NodeCreateFn));
        h.insert("text",                (true,  create_text as NodeCreateFn));
        /* h.insert("textPath",         (true,  as NodeCreateFn)); */
        /* h.insert("title",            (true,  as NodeCreateFn)); */
        h.insert("tref",                (true,  create_tref as NodeCreateFn));
        h.insert("tspan",               (true,  create_tspan as NodeCreateFn));
        h.insert("use",                 (true,  create_use as NodeCreateFn));
        /* h.insert("view",             (false, as NodeCreateFn)); */
        /* h.insert("vkern",            (false, as NodeCreateFn)); */
        h
    };
}

pub fn create_node_and_register_id(
    name: &str,
    parent: Option<&RsvgNode>,
    pbag: &PropertyBag,
    ids: &mut HashMap<String, RsvgNode>,
) -> RsvgNode {
    let mut id = None;
    let mut class = None;

    for (attr, value) in pbag.iter() {
        match attr {
            local_name!("id") => id = Some(value),
            local_name!("class") => class = Some(value),
            _ => (),
        }
    }

    let &(supports_class, create_fn) = match NODE_CREATORS.get(name) {
        Some(c) => c,

        // Whenever we encounter a node we don't understand, represent it as a
        // non-rendering node.  This is like a group, but it doesn't do any rendering of
        // children.  The effect is that we will ignore all children of unknown elements.
        None => &(true, create_non_rendering as NodeCreateFn),
    };

    let element_name = LocalName::from(name);

    if !supports_class {
        class = None;
    };

    let node = create_fn(element_name, id, class, parent);

    if let Some(id) = id {
        // This is so we don't overwrite an existing id
        ids.entry(id.to_string()).or_insert(node.clone());
    }

    node
}
<commit_msg>Make the NODE_CREATORS table more legible with a macro<commit_after>use markup5ever::LocalName;
use std::collections::HashMap;

use crate::clip_path::NodeClipPath;
use crate::filters::{
    blend::Blend,
    color_matrix::ColorMatrix,
    component_transfer::{ComponentTransfer, FuncX},
    composite::Composite,
    convolve_matrix::ConvolveMatrix,
    displacement_map::DisplacementMap,
    flood::Flood,
    gaussian_blur::GaussianBlur,
    image::Image,
    light::{light_source::LightSource, lighting::Lighting},
    merge::{Merge, MergeNode},
    morphology::Morphology,
    node::NodeFilter,
    offset::Offset,
    tile::Tile,
    turbulence::Turbulence,
};
use crate::gradient::NodeGradient;
use crate::image::NodeImage;
use crate::link::NodeLink;
use crate::marker::NodeMarker;
use crate::mask::NodeMask;
use crate::node::*;
use crate::pattern::NodePattern;
use crate::property_bag::PropertyBag;
use crate::shapes::{NodeCircle, NodeEllipse, NodeLine, NodePath, NodePoly, NodeRect};
use crate::stop::NodeStop;
use crate::structure::{NodeGroup, NodeNonRendering, NodeSvg, NodeSwitch, NodeSymbol, NodeUse};
use crate::style::NodeStyle;
use crate::text::{NodeTRef, NodeTSpan, NodeText};

macro_rules! n {
    ($name:ident, $node_type:ident, $new_fn:expr) => {
        pub fn $name(
            element_name: LocalName,
            id: Option<&str>,
            class: Option<&str>,
            parent: Option<&RsvgNode>,
        ) -> RsvgNode {
            RsvgNode::new(
                NodeData::new(
                    NodeType::$node_type,
                    element_name,
                    id,
                    class,
                    Box::new($new_fn()),
                ),
                parent,
            )
        }
    };
}

#[cfg_attr(rustfmt, rustfmt_skip)]
mod creators {
    use super::*;

    n!(create_circle,                    Circle,                     NodeCircle::new);
    n!(create_clip_path,                 ClipPath,                   NodeClipPath::new);
    n!(create_blend,                     FeBlend,                    Blend::new);
    n!(create_color_matrix,              FeColorMatrix,              ColorMatrix::new);
    n!(create_component_transfer,        FeComponentTransfer,        ComponentTransfer::new);
    n!(create_component_transfer_func_a, ComponentTransferFunctionA, FuncX::new_a);
    n!(create_component_transfer_func_b, ComponentTransferFunctionB, FuncX::new_b);
    n!(create_component_transfer_func_g, ComponentTransferFunctionG, FuncX::new_g);
    n!(create_component_transfer_func_r, ComponentTransferFunctionR, FuncX::new_r);
    n!(create_composite,                 FeComposite,                Composite::new);
    n!(create_convolve_matrix,           FeConvolveMatrix,           ConvolveMatrix::new);
    n!(create_defs,                      Defs,                       NodeNonRendering::new);
    n!(create_diffuse_lighting,          FeDiffuseLighting,          Lighting::new_diffuse);
    n!(create_distant_light,             DistantLight,               LightSource::new_distant_light);
    n!(create_displacement_map,          FeDisplacementMap,          DisplacementMap::new);
    n!(create_ellipse,                   Ellipse,                    NodeEllipse::new);
    n!(create_filter,                    Filter,                     NodeFilter::new);
    n!(create_flood,                     FeFlood,                    Flood::new);
    n!(create_gaussian_blur,             FeGaussianBlur,             GaussianBlur::new);
    n!(create_group,                     Group,                      NodeGroup::new);
    n!(create_image,                     Image,                      NodeImage::new);
    n!(create_fe_image,                  FeImage,                    Image::new);
    n!(create_linear_gradient,           LinearGradient,             NodeGradient::new_linear);
    n!(create_line,                      Line,                       NodeLine::new);
    n!(create_link,                      Link,                       NodeLink::new);
    n!(create_marker,                    Marker,                     NodeMarker::new);
    n!(create_mask,                      Mask,                       NodeMask::new);
    n!(create_merge,                     FeMerge,                    Merge::new);
    n!(create_merge_node,                FeMergeNode,                MergeNode::new);
    n!(create_morphology,                FeMorphology,               Morphology::new);
    n!(create_non_rendering,             NonRendering,               NodeNonRendering::new);
    n!(create_offset,                    FeOffset,                   Offset::new);
    n!(create_path,                      Path,                       NodePath::new);
    n!(create_pattern,                   Pattern,                    NodePattern::new);
    n!(create_point_light,               PointLight,                 LightSource::new_point_light);
    n!(create_polygon,                   Polygon,                    NodePoly::new_closed);
    n!(create_polyline,                  Polyline,                   NodePoly::new_open);
    n!(create_radial_gradient,           RadialGradient,             NodeGradient::new_radial);
    n!(create_rect,                      Rect,                       NodeRect::new);
    n!(create_specular_lighting,         FeSpecularLighting,         Lighting::new_specular);
    n!(create_spot_light,                SpotLight,                  LightSource::new_spot_light);
    n!(create_stop,                      Stop,                       NodeStop::new);
    n!(create_style,                     Style,                      NodeStyle::new);
    n!(create_svg,                       Svg,                        NodeSvg::new);
    n!(create_switch,                    Switch,                     NodeSwitch::new);
    n!(create_symbol,                    Symbol,                     NodeSymbol::new);
    n!(create_text,                      Text,                       NodeText::new);
    n!(create_tref,                      TRef,                       NodeTRef::new);
    n!(create_tspan,                     TSpan,                      NodeTSpan::new);
    n!(create_tile,                      FeTile,                     Tile::new);
    n!(create_turbulence,                FeTurbulence,               Turbulence::new);
    n!(create_use,                       Use,                        NodeUse::new);

    // hack to partially support conical gradient
    n!(create_conical_gradient,          RadialGradient,             NodeGradient::new_radial);

    // hack to make multiImage sort-of work
    n!(create_multi_image,               Switch,                     NodeSwitch::new);
    n!(create_sub_image,                 Group,                      NodeGroup::new);
    n!(create_sub_image_ref,             Image,                      NodeImage::new);
}

use creators::*;

type NodeCreateFn = fn(
    element_name: LocalName,
    id: Option<&str>,
    class: Option<&str>,
    parent: Option<&RsvgNode>,
) -> RsvgNode;

macro_rules! c {
    ($hashset:expr, $str_name:expr, $supports_class:expr, $fn_name:ident) => {
        $hashset.insert($str_name, ($supports_class, $fn_name as NodeCreateFn));
    }
}

lazy_static! {
    // Lines in comments are elements that we don't support.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    static ref NODE_CREATORS: HashMap<&'static str, (bool, NodeCreateFn)> = {
        let mut h = HashMap::new();
        // name, supports_class, create_fn
        c!(h, "a",                   true,  create_link);
        /* c!(h, "altGlyph",         true,  ); */
        /* c!(h, "altGlyphDef",      false, ); */
        /* c!(h, "altGlyphItem",     false, ); */
        /* c!(h, "animate",          false, ); */
        /* c!(h, "animateColor",     false, ); */
        /* c!(h, "animateMotion",    false, ); */
        /* c!(h, "animateTransform", false, ); */
        c!(h, "circle",              true,  create_circle);
        c!(h, "clipPath",            true,  create_clip_path);
        /* c!(h, "color-profile",    false, ); */
        c!(h, "conicalGradient",     true,  create_conical_gradient);
        /* c!(h, "cursor",           false, ); */
        c!(h, "defs",                true,  create_defs);
        /* c!(h, "desc",             true,  ); */
        c!(h, "ellipse",             true,  create_ellipse);
        c!(h, "feBlend",             true,  create_blend);
        c!(h, "feColorMatrix",       true,  create_color_matrix);
        c!(h, "feComponentTransfer", true,  create_component_transfer);
        c!(h, "feComposite",         true,  create_composite);
        c!(h, "feConvolveMatrix",    true,  create_convolve_matrix);
        c!(h, "feDiffuseLighting",   true,  create_diffuse_lighting);
        c!(h, "feDisplacementMap",   true,  create_displacement_map);
        c!(h, "feDistantLight",      false, create_distant_light);
        c!(h, "feFuncA",             false, create_component_transfer_func_a);
        c!(h, "feFuncB",             false, create_component_transfer_func_b);
        c!(h, "feFuncG",             false, create_component_transfer_func_g);
        c!(h, "feFuncR",             false, create_component_transfer_func_r);
        c!(h, "feFlood",             true,  create_flood);
        c!(h, "feGaussianBlur",      true,  create_gaussian_blur);
        c!(h, "feImage",             true,  create_fe_image);
        c!(h, "feMerge",             true,  create_merge);
        c!(h, "feMergeNode",         false, create_merge_node);
        c!(h, "feMorphology",        true,  create_morphology);
        c!(h, "feOffset",            true,  create_offset);
        c!(h, "fePointLight",        false, create_point_light);
        c!(h, "feSpecularLighting",  true,  create_specular_lighting);
        c!(h, "feSpotLight",         false, create_spot_light);
        c!(h, "feTile",              true,  create_tile);
        c!(h, "feTurbulence",        true,  create_turbulence);
        c!(h, "filter",              true,  create_filter);
        /* c!(h, "font",             true,  ); */
        /* c!(h, "font-face",        false, ); */
        /* c!(h, "font-face-format", false, ); */
        /* c!(h, "font-face-name",   false, ); */
        /* c!(h, "font-face-src",    false, ); */
        /* c!(h, "font-face-uri",    false, ); */
        /* c!(h, "foreignObject",    true,  ); */
        c!(h, "g",                   true,  create_group);
        /* c!(h, "glyph",            true,  ); */
        /* c!(h, "glyphRef",         true,  ); */
        /* c!(h, "hkern",            false, ); */
        c!(h, "image",               true,  create_image);
        c!(h, "line",                true,  create_line);
        c!(h, "linearGradient",      true,  create_linear_gradient);
        c!(h, "marker",              true,  create_marker);
        c!(h, "mask",                true,  create_mask);
        /* c!(h, "metadata",         false, ); */
        /* c!(h, "missing-glyph",    true,  ); */
        /* c!(h, "mpath",            false, ); */
        c!(h, "multiImage",          false, create_multi_image);
        c!(h, "path",                true,  create_path);
        c!(h, "pattern",             true,  create_pattern);
        c!(h, "polygon",             true,  create_polygon);
        c!(h, "polyline",            true,  create_polyline);
        c!(h, "radialGradient",      true,  create_radial_gradient);
        c!(h, "rect",                true,  create_rect);
        /* c!(h, "script",           false, ); */
        /* c!(h, "set",              false, ); */
        c!(h, "stop",                true,  create_stop);
        c!(h, "style",               false, create_style);
        c!(h, "subImage",            false, create_sub_image);
        c!(h, "subImageRef",         false, create_sub_image_ref);
        c!(h, "svg",                 true,  create_svg);
        c!(h, "switch",              true,  create_switch);
        c!(h, "symbol",              true,  create_symbol);
        c!(h, "text",                true,  create_text);
        /* c!(h, "textPath",         true,  ); */
        /* c!(h, "title",            true,  ); */
        c!(h, "tref",                true,  create_tref);
        c!(h, "tspan",               true,  create_tspan);
        c!(h, "use",                 true,  create_use);
        /* c!(h, "view",             false, ); */
        /* c!(h, "vkern",            false, ); */
        h
    };
}

pub fn create_node_and_register_id(
    name: &str,
    parent: Option<&RsvgNode>,
    pbag: &PropertyBag,
    ids: &mut HashMap<String, RsvgNode>,
) -> RsvgNode {
    let mut id = None;
    let mut class = None;

    for (attr, value) in pbag.iter() {
        match attr {
            local_name!("id") => id = Some(value),
            local_name!("class") => class = Some(value),
            _ => (),
        }
    }

    let &(supports_class, create_fn) = match NODE_CREATORS.get(name) {
        Some(c) => c,

        // Whenever we encounter a node we don't understand, represent it as a
        // non-rendering node.  This is like a group, but it doesn't do any rendering of
        // children.  The effect is that we will ignore all children of unknown elements.
        None => &(true, create_non_rendering as NodeCreateFn),
    };

    let element_name = LocalName::from(name);

    if !supports_class {
        class = None;
    };

    let node = create_fn(element_name, id, class, parent);

    if let Some(id) = id {
        // This is so we don't overwrite an existing id
        ids.entry(id.to_string()).or_insert(node.clone());
    }

    node
}
<|endoftext|>


<commit_before>use crate::pipeline::broad_phase::BroadPhasePairFilter;
use crate::pipeline::object::{CollisionObjectHandle, CollisionObjectRef};
use na::RealField;

const SELF_COLLISION: u32 = 1 << 31;
const ALL_GROUPS: u32 = (1 << 30) - 1;
const NO_GROUP: u32 = 0;

/// Groups of collision used to filter which object interact with which other one.
///
/// There are at most 30 groups indexed from 0 to 29 (included). This identifies collidable
/// entities by combining three attributes:
///    * A set of group this structure is member of.
///    * A collision group whitelist.
///    * A collision group blacklist.
///
/// For two entities to interact, they must be member of at least one group part of each-other's
/// whitelists, and must not be part of any blacklisted group. The blacklist always has priority on
/// the whitelist.
///
/// ### Example
/// For example if the object A is such that:
///    * It is part of the groups 1, 3, and 6.
///    * It whitelists the groups 6 and 7.
///    * It blacklists the group 1.
/// Let the object B be such that:
///    * It is part of the groups 1, 3, and 7.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
/// For example if the object C is such that:
///    * It is part of the groups 6 and 9.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
///
/// Then we have:
///    * A and C can interact because A whitelists the group 6 (which C is part of), and,
///    reciprocally, C whitelists the group 3 (which A is part of).
///    * A and B will **not** interact because B is part of the group 1 which is blacklisted by A.
///    * Finally, B and C will **not** interact either because, even if C whitelists the group 3
///    (which B is part of), B does not whitelists the groups 6 nor 9 (which B is part of).
#[derive(Clone, Debug, Copy)]
pub struct CollisionGroups {
    membership: u32,
    whitelist: u32,
    blacklist: u32,
}

impl CollisionGroups {
    /// Creates a new `CollisionGroups` that enables interactions with everything except
    /// self-interaction.
    #[inline]
    pub fn new() -> CollisionGroups {
        CollisionGroups {
            membership: ALL_GROUPS,
            whitelist: ALL_GROUPS,
            blacklist: NO_GROUP,
        }
    }

    /// Returns a copy of this object, updated with a new set of membership groups.
    ///
    /// # Examples
    ///
    /// ```.ignore
    /// const GROUP_A: usize = 0;
    /// const GROUP_B: usize = 29;
    /// let groups = CollisionGroups::new().with_membership(&[GROUP_A, GROUP_B]);
    /// assert!(groups.is_member_of(GROUP_A));
    /// assert!(groups.is_member_of(GROUP_B));
    /// ```
    #[inline]
    pub fn with_membership(mut self, groups: &[usize]) -> CollisionGroups {
        CollisionGroups::set_mask(&mut self.membership, groups);
        self
    }

    /// Returns a copy of this object, updated with a new set of whitelisted groups.
    ///
    /// # Examples
    ///
    /// ```.ignore
    /// const GROUP_A: usize = 0;
    /// const GROUP_B: usize = 29;
    /// let group_a = CollisionGroups::new().with_whitelist(&[GROUP_B]);
    /// assert!(!group_a.is_group_whitelisted(GROUP_A));
    /// assert!(group_a.is_group_whitelisted(GROUP_B));
    /// ```
    #[inline]
    pub fn with_whitelist(mut self, groups: &[usize]) -> CollisionGroups {
        CollisionGroups::set_mask(&mut self.whitelist, groups);
        self
    }

    /// Returns a copy of this object, updated with a new set of blacklisted groups.
    ///
    /// # Examples
    ///
    /// ```.ignore
    /// const GROUP_A: usize = 0;
    /// const GROUP_B: usize = 29;
    /// let group_a = CollisionGroups::new().with_blacklist(&[GROUP_B]);
    /// assert!(!group_a.is_group_blacklisted(GROUP_A));
    /// assert!(group_a.is_group_blacklisted(GROUP_B));
    /// ```
    #[inline]
    pub fn with_blacklist(mut self, groups: &[usize]) -> CollisionGroups {
        CollisionGroups::set_mask(&mut self.blacklist, groups);
        self
    }

    /// The maximum allowed group identifier.
    #[inline]
    pub fn max_group_id() -> usize {
        29
    }

    #[inline]
    fn modify_mask(mask: &mut u32, group_id: usize, add: bool) {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );

        if add {
            *mask = *mask | (1 << group_id)
        } else {
            *mask = *mask & !(1 << group_id)
        }
    }

    #[inline]
    fn set_mask(mask: &mut u32, groups: &[usize]) {
        *mask = 0;
        for g in groups.iter() {
            CollisionGroups::modify_mask(mask, *g, true);
        }
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_membership(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.membership, group_id, add);
    }

    /// Adds or removes the given group from this entity whitelist.
    #[inline]
    pub fn modify_whitelist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.whitelist, group_id, add);
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_blacklist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.blacklist, group_id, add);
    }

    /// Make this object member of the given groups only.
    #[inline]
    pub fn set_membership(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.membership, groups);
    }

    /// Whitelists the given groups only (others will be un-whitelisted).
    #[inline]
    pub fn set_whitelist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.whitelist, groups);
    }

    /// Blacklists the given groups only (others will be un-blacklisted).
    #[inline]
    pub fn set_blacklist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.blacklist, groups);
    }

    /// Copies the membership of another collision groups.
    #[inline]
    pub fn copy_membership(&mut self, other: &CollisionGroups) {
        self.membership = other.membership
    }

    /// Copies the whitelist of another collision groups.
    #[inline]
    pub fn copy_whitelist(&mut self, other: &CollisionGroups) {
        self.whitelist = other.whitelist
    }

    /// Copies the blacklist of another collision groups.
    #[inline]
    pub fn copy_blacklist(&mut self, other: &CollisionGroups) {
        self.blacklist = other.blacklist
    }

    /// Allows the object to interact with itself.
    #[inline]
    pub fn enable_self_interaction(&mut self) {
        self.whitelist = self.whitelist | SELF_COLLISION;
    }

    /// Prevents the object from interacting with itself.
    #[inline]
    pub fn disable_self_interaction(&mut self) {
        self.whitelist = self.whitelist & !SELF_COLLISION;
    }

    #[inline]
    fn is_inside_mask(mask: u32, group_id: usize) -> bool {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );
        mask & (1 << group_id) != 0
    }

    /// Tests if this entity is part of the given group.
    #[inline]
    pub fn is_member_of(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.membership, group_id)
    }

    /// Tests if the given group is whitelisted.
    #[inline]
    pub fn is_group_whitelisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests if the given group is blacklisted.
    #[inline]
    pub fn is_group_blacklisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.blacklist, group_id)
    }

    /// Tests whether interactions with a given group is possible.
    ///
    /// Collision is possible if `group_id` is whitelisted but not blacklisted.
    #[inline]
    pub fn can_interact_with(&self, group_id: usize) -> bool {
        !CollisionGroups::is_inside_mask(self.blacklist, group_id)
            && CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests whether two collision groups have at least one group in common.
    #[inline]
    pub fn can_interact_with_groups(&self, other: &CollisionGroups) -> bool {
        // FIXME: is there a more bitwise-y way of doing this?
        self.membership & other.blacklist == 0
            && other.membership & self.blacklist == 0
            && self.membership & other.whitelist != 0
            && other.membership & self.whitelist != 0
    }

    /// Tests whether self-interaction is enabled.
    #[inline]
    pub fn can_interact_with_self(&self) -> bool {
        self.whitelist & SELF_COLLISION != 0
    }
}

impl Default for CollisionGroups {
    #[inline]
    fn default() -> Self {
        CollisionGroups::new()
    }
}

/// A collision filter based collision groups.
pub struct CollisionGroupsPairFilter;

impl CollisionGroupsPairFilter {
    /// Creates a new collision filter based collision groups.
    #[inline]
    pub fn new() -> CollisionGroupsPairFilter {
        CollisionGroupsPairFilter
    }
}

impl<N: RealField, Object: CollisionObjectRef<N>, Handle: CollisionObjectHandle>
    BroadPhasePairFilter<N, Object, Handle> for CollisionGroupsPairFilter
{
    fn is_pair_valid(&self, co1: &Object, co2: &Object, h1: Handle, h2: Handle) -> bool {
        if h1 == h2 {
            co1.collision_groups().can_interact_with_self()
        } else {
            co1.collision_groups()
                .can_interact_with_groups(co2.collision_groups())
        }
    }
}
<commit_msg>Fix collision group documentation formatting, grammar<commit_after>use crate::pipeline::broad_phase::BroadPhasePairFilter;
use crate::pipeline::object::{CollisionObjectHandle, CollisionObjectRef};
use na::RealField;

const SELF_COLLISION: u32 = 1 << 31;
const ALL_GROUPS: u32 = (1 << 30) - 1;
const NO_GROUP: u32 = 0;

/// Groups of collision used to filter which object interact with which other one.
///
/// There are at most 30 groups indexed from 0 to 29 (included). This identifies collidable
/// entities by combining three attributes:
///    * A set of group this structure is member of.
///    * A collision group whitelist.
///    * A collision group blacklist.
///
/// For two entities to interact, they must be member of at least one group part of each-other's
/// whitelists, and must not be part of any blacklisted group. The blacklist always has priority on
/// the whitelist.
///
/// ### Example
/// For example if the object A is such that:
///    * It is part of the groups 1, 3, and 6.
///    * It whitelists the groups 6 and 7.
///    * It blacklists the group 1.
///
/// Let there be an object B such that:
///    * It is part of the groups 1, 3, and 7.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
///
/// and an object C such that:
///    * It is part of the groups 6 and 9.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
///
/// Then we have:
///    * A and C can interact because A whitelists the group 6 (which C is part of), and,
///    reciprocally, C whitelists the group 3 (which A is part of).
///    * A and B will **not** interact because B is part of the group 1 which is blacklisted by A.
///    * Finally, B and C will **not** interact either because, even if C whitelists the group 3
///    (which B is part of), B does not whitelists the groups 6 nor 9 (which B is part of).
#[derive(Clone, Debug, Copy)]
pub struct CollisionGroups {
    membership: u32,
    whitelist: u32,
    blacklist: u32,
}

impl CollisionGroups {
    /// Creates a new `CollisionGroups` that enables interactions with everything except
    /// self-interaction.
    #[inline]
    pub fn new() -> CollisionGroups {
        CollisionGroups {
            membership: ALL_GROUPS,
            whitelist: ALL_GROUPS,
            blacklist: NO_GROUP,
        }
    }

    /// Returns a copy of this object, updated with a new set of membership groups.
    ///
    /// # Examples
    ///
    /// ```.ignore
    /// const GROUP_A: usize = 0;
    /// const GROUP_B: usize = 29;
    /// let groups = CollisionGroups::new().with_membership(&[GROUP_A, GROUP_B]);
    /// assert!(groups.is_member_of(GROUP_A));
    /// assert!(groups.is_member_of(GROUP_B));
    /// ```
    #[inline]
    pub fn with_membership(mut self, groups: &[usize]) -> CollisionGroups {
        CollisionGroups::set_mask(&mut self.membership, groups);
        self
    }

    /// Returns a copy of this object, updated with a new set of whitelisted groups.
    ///
    /// # Examples
    ///
    /// ```.ignore
    /// const GROUP_A: usize = 0;
    /// const GROUP_B: usize = 29;
    /// let group_a = CollisionGroups::new().with_whitelist(&[GROUP_B]);
    /// assert!(!group_a.is_group_whitelisted(GROUP_A));
    /// assert!(group_a.is_group_whitelisted(GROUP_B));
    /// ```
    #[inline]
    pub fn with_whitelist(mut self, groups: &[usize]) -> CollisionGroups {
        CollisionGroups::set_mask(&mut self.whitelist, groups);
        self
    }

    /// Returns a copy of this object, updated with a new set of blacklisted groups.
    ///
    /// # Examples
    ///
    /// ```.ignore
    /// const GROUP_A: usize = 0;
    /// const GROUP_B: usize = 29;
    /// let group_a = CollisionGroups::new().with_blacklist(&[GROUP_B]);
    /// assert!(!group_a.is_group_blacklisted(GROUP_A));
    /// assert!(group_a.is_group_blacklisted(GROUP_B));
    /// ```
    #[inline]
    pub fn with_blacklist(mut self, groups: &[usize]) -> CollisionGroups {
        CollisionGroups::set_mask(&mut self.blacklist, groups);
        self
    }

    /// The maximum allowed group identifier.
    #[inline]
    pub fn max_group_id() -> usize {
        29
    }

    #[inline]
    fn modify_mask(mask: &mut u32, group_id: usize, add: bool) {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );

        if add {
            *mask = *mask | (1 << group_id)
        } else {
            *mask = *mask & !(1 << group_id)
        }
    }

    #[inline]
    fn set_mask(mask: &mut u32, groups: &[usize]) {
        *mask = 0;
        for g in groups.iter() {
            CollisionGroups::modify_mask(mask, *g, true);
        }
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_membership(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.membership, group_id, add);
    }

    /// Adds or removes the given group from this entity whitelist.
    #[inline]
    pub fn modify_whitelist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.whitelist, group_id, add);
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_blacklist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.blacklist, group_id, add);
    }

    /// Make this object member of the given groups only.
    #[inline]
    pub fn set_membership(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.membership, groups);
    }

    /// Whitelists the given groups only (others will be un-whitelisted).
    #[inline]
    pub fn set_whitelist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.whitelist, groups);
    }

    /// Blacklists the given groups only (others will be un-blacklisted).
    #[inline]
    pub fn set_blacklist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.blacklist, groups);
    }

    /// Copies the membership of another collision groups.
    #[inline]
    pub fn copy_membership(&mut self, other: &CollisionGroups) {
        self.membership = other.membership
    }

    /// Copies the whitelist of another collision groups.
    #[inline]
    pub fn copy_whitelist(&mut self, other: &CollisionGroups) {
        self.whitelist = other.whitelist
    }

    /// Copies the blacklist of another collision groups.
    #[inline]
    pub fn copy_blacklist(&mut self, other: &CollisionGroups) {
        self.blacklist = other.blacklist
    }

    /// Allows the object to interact with itself.
    #[inline]
    pub fn enable_self_interaction(&mut self) {
        self.whitelist = self.whitelist | SELF_COLLISION;
    }

    /// Prevents the object from interacting with itself.
    #[inline]
    pub fn disable_self_interaction(&mut self) {
        self.whitelist = self.whitelist & !SELF_COLLISION;
    }

    #[inline]
    fn is_inside_mask(mask: u32, group_id: usize) -> bool {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );
        mask & (1 << group_id) != 0
    }

    /// Tests if this entity is part of the given group.
    #[inline]
    pub fn is_member_of(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.membership, group_id)
    }

    /// Tests if the given group is whitelisted.
    #[inline]
    pub fn is_group_whitelisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests if the given group is blacklisted.
    #[inline]
    pub fn is_group_blacklisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.blacklist, group_id)
    }

    /// Tests whether interactions with a given group is possible.
    ///
    /// Collision is possible if `group_id` is whitelisted but not blacklisted.
    #[inline]
    pub fn can_interact_with(&self, group_id: usize) -> bool {
        !CollisionGroups::is_inside_mask(self.blacklist, group_id)
            && CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests whether two collision groups have at least one group in common.
    #[inline]
    pub fn can_interact_with_groups(&self, other: &CollisionGroups) -> bool {
        // FIXME: is there a more bitwise-y way of doing this?
        self.membership & other.blacklist == 0
            && other.membership & self.blacklist == 0
            && self.membership & other.whitelist != 0
            && other.membership & self.whitelist != 0
    }

    /// Tests whether self-interaction is enabled.
    #[inline]
    pub fn can_interact_with_self(&self) -> bool {
        self.whitelist & SELF_COLLISION != 0
    }
}

impl Default for CollisionGroups {
    #[inline]
    fn default() -> Self {
        CollisionGroups::new()
    }
}

/// A collision filter based collision groups.
pub struct CollisionGroupsPairFilter;

impl CollisionGroupsPairFilter {
    /// Creates a new collision filter based collision groups.
    #[inline]
    pub fn new() -> CollisionGroupsPairFilter {
        CollisionGroupsPairFilter
    }
}

impl<N: RealField, Object: CollisionObjectRef<N>, Handle: CollisionObjectHandle>
    BroadPhasePairFilter<N, Object, Handle> for CollisionGroupsPairFilter
{
    fn is_pair_valid(&self, co1: &Object, co2: &Object, h1: Handle, h2: Handle) -> bool {
        if h1 == h2 {
            co1.collision_groups().can_interact_with_self()
        } else {
            co1.collision_groups()
                .can_interact_with_groups(co2.collision_groups())
        }
    }
}
<|endoftext|>


<commit_before>//! Demangles rustc mangled names.
//!
//! This tool uses https://crates.io/crates/rustc-demangle to convert an input buffer of
//! newline-separated mangled names into their demangled translations.
//!
//! This tool can be leveraged by other applications that support third-party demanglers.
//! It takes a list of mangled names (one per line) on standard input, and prints a corresponding
//! list of demangled names. The tool is designed to support other programs that can leverage a
//! third-party demangler, such as `llvm-cov`, via the `-Xdemangler=<path-to-demangler>` option.
//!
//! To use `rust-demangler`, first build the tool with:
//!
//! ```shell
//! $ ./x.py build rust-demangler
//! ```
//!
//! Then, with `llvm-cov` for example, add the `-Xdemangler=...` option:
//!
//! ```shell
//! $ TARGET="${PWD}/build/x86_64-unknown-linux-gnu"
//! $ "${TARGET}"/llvm/bin/llvm-cov show --Xdemangler="${TARGET}"/stage0-tools-bin/rust-demangler \
//!   --instr-profile=main.profdata ./main --show-line-counts-or-regions
//! ```

use regex::Regex;
use rustc_demangle::demangle;
use std::io::{self, Read, Write};

const REPLACE_COLONS: &str = "::";

fn main() -> io::Result<()> {
    let mut strip_crate_disambiguators = Some(Regex::new(r"\[[a-f0-9]{16}\]::").unwrap());

    let mut args = std::env::args();
    let progname = args.next().unwrap();
    for arg in args {
        if arg == "--disambiguators" || arg == "-d" {
            strip_crate_disambiguators = None;
        } else {
            eprintln!();
            eprintln!("Usage: {} [-d|--disambiguators]", progname);
            eprintln!();
            eprintln!(
                "This tool converts a list of Rust mangled symbols (one per line) into a\n
                corresponding list of demangled symbols."
            );
            eprintln!();
            eprintln!(
                "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\
                include crate disambiguators (a 16 character hex value in square brackets).\n\
                Crate disambiguators are removed by default."
            );
            eprintln!();
            std::process::exit(1)
        }
    }

    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer)?;
    let lines = buffer.lines();
    let mut demangled_lines = Vec::new();
    for mangled in lines {
        let mut demangled = demangle(mangled).to_string();
        if let Some(re) = &strip_crate_disambiguators {
            demangled = re.replace_all(&demangled, REPLACE_COLONS).to_string();
        }
        demangled_lines.push(demangled);
    }
    demangled_lines.push("".to_string());
    io::stdout().write_all(demangled_lines.join("\n").as_bytes())?;
    Ok(())
}
<commit_msg>rust-demangler tool strips crate disambiguators with < 16 digits<commit_after>//! Demangles rustc mangled names.
//!
//! This tool uses https://crates.io/crates/rustc-demangle to convert an input buffer of
//! newline-separated mangled names into their demangled translations.
//!
//! This tool can be leveraged by other applications that support third-party demanglers.
//! It takes a list of mangled names (one per line) on standard input, and prints a corresponding
//! list of demangled names. The tool is designed to support other programs that can leverage a
//! third-party demangler, such as `llvm-cov`, via the `-Xdemangler=<path-to-demangler>` option.
//!
//! To use `rust-demangler`, first build the tool with:
//!
//! ```shell
//! $ ./x.py build rust-demangler
//! ```
//!
//! Then, with `llvm-cov` for example, add the `-Xdemangler=...` option:
//!
//! ```shell
//! $ TARGET="${PWD}/build/x86_64-unknown-linux-gnu"
//! $ "${TARGET}"/llvm/bin/llvm-cov show --Xdemangler="${TARGET}"/stage0-tools-bin/rust-demangler \
//!   --instr-profile=main.profdata ./main --show-line-counts-or-regions
//! ```
//!
//! Note regarding crate disambiguators:
//!
//! Some demangled symbol paths can include "crate disambiguator" suffixes, represented as a large
//! hexadecimal value enclosed in square braces, and appended to the name of the crate. a suffix to the
//! original crate name. For example, the `core` crate, here, includes a disambiguator:
//!
//! ```rust
//!     <generics::Firework<f64> as core[a7a74cee373f048]::ops::drop::Drop>::drop
//! ```
//!
//! These disambiguators are known to vary depending on environmental circumstances. As a result,
//! tests that compare results including demangled names can fail across development environments,
//! particularly with cross-platform testing. Also, the resulting crate paths are not syntactically
//! valid, and don't match the original source symbol paths, which can impact development tools.
//!
//! For these reasons, by default, `rust-demangler` uses a heuristic to remove crate disambiguators
//! from their original demangled representation before printing them to standard output. If crate
//! disambiguators are required, add the `-d` (or `--disambiguators`) flag, and the disambiguators
//! will not be removed.
//!
//! Also note that the disambiguators are stripped by a Regex pattern that is tolerant to some
//! variation in the number of hexadecimal digits. The disambiguators come from a hash value, which
//! typically generates a 16-digit hex representation on a 64-bit architecture; however, leading
//! zeros are not included, which can shorten the hex digit length, and a different hash algorithm
//! that might also be dependent on the architecture, might shorten the length even further. A
//! minimum length of 5 digits is assumed, which should be more than sufficient to support hex
//! representations that generate only 8-digits of precision with an extremely rare (but not
//! impossible) result with up to 3 leading zeros.
//!
//! Using a minimum number of digits less than 5 risks the possibility of stripping demangled name
//! components with a similar pattern. For example, some closures instantiated multiple times
//! include their own disambiguators, demangled as non-hashed zero-based indexes in square brackets.
//! These disambiguators seem to have more analytical value (for instance, in coverage analysis), so
//! they are not removed.

use regex::Regex;
use rustc_demangle::demangle;
use std::io::{self, Read, Write};

const REPLACE_COLONS: &str = "::";

fn main() -> io::Result<()> {
    // FIXME(richkadel): In Issue #77615 discussed updating the `rustc-demangle` library, to provide
    // an option to generate demangled names without including crate disambiguators. If that
    // happens, update this tool to use that option (if the `-d` flag is not set) instead stripping
    // them via the Regex heuristic. The update the doc comments and help.

    // Strip hashed hexadecimal crate disambiguators. Leading zeros are not enforced, and can be
    // different across different platform/architecture types, so while 16 hex digits are common,
    // they can also be shorter.
    //
    // Also note that a demangled symbol path may include the `[<digits>]` pattern, with zero-based
    // indexes (such as for closures, and possibly for types defined in anonymous scopes). Preferably
    // these should not be stripped.
    //
    // The minimum length of 5 digits supports the possibility that some target architecture (maybe
    // a 32-bit or smaller architecture) could generate a hash value with a maximum of 8 digits,
    // and more than three leading zeros should be extremely unlikely. Conversely, it should be
    // sufficient to assume the zero-based indexes for closures and anonymous scopes will never
    // exceed the value 9999.
    let mut strip_crate_disambiguators = Some(Regex::new(r"\[[a-f0-9]{5,16}\]::").unwrap());

    let mut args = std::env::args();
    let progname = args.next().unwrap();
    for arg in args {
        if arg == "--disambiguators" || arg == "-d" {
            strip_crate_disambiguators = None;
        } else {
            eprintln!();
            eprintln!("Usage: {} [-d|--disambiguators]", progname);
            eprintln!();
            eprintln!(
                "This tool converts a list of Rust mangled symbols (one per line) into a\n\
                corresponding list of demangled symbols."
            );
            eprintln!();
            eprintln!(
                "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\
                include crate disambiguators (a hexadecimal hash value, typically up to 16 digits\n\
                long, enclosed in square brackets)."
            );
            eprintln!();
            eprintln!(
                "By default, crate disambiguators are removed, using a heuristics-based regular\n\
                expression. (See the `rust-demangler` doc comments for more information.)"
            );
            eprintln!();
            std::process::exit(1)
        }
    }

    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer)?;
    let lines = buffer.lines();
    let mut demangled_lines = Vec::new();
    for mangled in lines {
        let mut demangled = demangle(mangled).to_string();
        if let Some(re) = &strip_crate_disambiguators {
            demangled = re.replace_all(&demangled, REPLACE_COLONS).to_string();
        }
        demangled_lines.push(demangled);
    }
    demangled_lines.push("".to_string());
    io::stdout().write_all(demangled_lines.join("\n").as_bytes())?;
    Ok(())
}
<|endoftext|>


<commit_before>use crate::index::btree::min_entry_key;
use crate::index::btree::test::u64_to_slice;
use crate::index::trees::*;
use crate::index::lsmtree::tree::KeyRange;
use crate::index::lsmtree::tree::LSMTree;
use itertools::Itertools;
use crate::ram::types::Id;
use rand::thread_rng;
use smallvec::SmallVec;
use std::env;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use rayon::prelude::*;
use rand::seq::SliceRandom;

fn dump_trees(lsm_tree: &LSMTree, name: &str) {
    for i in 0..lsm_tree.trees.len() {
        lsm_tree.trees[i].dump(&format!("{}_lsm_{}_dump.json", name, i));
    }
}

fn default_key_range() -> KeyRange {
    (min_entry_key(), min_entry_key())
}

#[test]
pub fn insertions() {
    env_logger::init();
    let tree = Arc::new(LSMTree::new(default_key_range(), Id::unit_id()));
    let num = env::var("LSM_TREE_TEST_ITEMS")
        // this value cannot do anything useful to the test
        // must arrange a long-term test to cover every levels
        .unwrap_or("331776".to_string())
        .parse::<u64>()
        .unwrap();

    let tree_clone = tree.clone();
    debug!("Testing LSM-tree");
    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(10));
        let tree_len = tree_clone.len();
        debug!(
            "LSM-Tree now have {}/{} elements, total {:.2}%",
            tree_len,
            num,
            tree_len as f32 / num as f32 * 100.0
        );
    });

    (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        key_with_id(&mut key, &id);
        tree.insert(key);
    });

    debug!("Start point search validations");
    tree.ensure_trees_in_order();
    (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        debug!("checking: {}", i);
        let cursor = tree.seek(&key, Ordering::Forward);
        key_with_id(&mut key, &id);
        assert_eq!(cursor.current(), Some(&key), "{}", i);
    });

    dump_trees(&*tree, "insertions_before_merge");
    for _ in 0..50 {
        tree.check_and_merge();
    }
    dump_trees(&*tree, "insertions_after_merge");
    tree.ensure_trees_in_order();

    debug!("Start point search validations");
    (0..num).collect::<Vec<_>>().iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        debug!("checking: {}", i);
        let cursor = tree.seek(&key, Ordering::Forward);
        key_with_id(&mut key, &id);
        assert_eq!(cursor.current(), Some(&key), "{}, looking for {:?}", i, key);
    });
}

#[test]
pub fn hybrid() {
    env_logger::init();
    let tree = Arc::new(LSMTree::new(default_key_range(), Id::unit_id()));
    let num = env::var("LSM_TREE_TEST_ITEMS")
        // this value cannot do anything useful to the test
        // must arrange a long-term test to cover every levels
        .unwrap_or("663552".to_string())
        .parse::<u64>()
        .unwrap();

    LSMTree::start_sentinel(&tree);
    let tree_clone = tree.clone();
    debug!("Testing LSM-tree");
    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(10));
        let tree_len = tree_clone.len();
        debug!(
            "LSM-Tree now have {}/{} elements, total {:.2}%",
            tree_len,
            num,
            tree_len as f32 / num as f32 * 100.0
        );
    });

    let mut test_data = (0..num).collect_vec();
    let mut rng = thread_rng();
    test_data.as_mut_slice().shuffle(&mut rng);
    test_data.par_iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        key_with_id(&mut key, &id);
        tree.insert(key);
    });

    tree.ensure_trees_in_order();
    dump_trees(&*tree, "hybird_after_insertion");
    thread::sleep(Duration::new(30, 0));
    dump_trees(&*tree, "hybird_after_sleep");
    tree.ensure_trees_in_order();

    debug!("Start point search validations");
    (0..num).collect::<Vec<_>>().iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        debug!("checking: {}", i);
        let cursor = tree.seek(&key, Ordering::Forward);
        key_with_id(&mut key, &id);
        assert_eq!(cursor.current(), Some(&key), "{}", i);
    });
}
<commit_msg>LSM tree is still broken, I will leave it to the future<commit_after>use crate::index::btree::min_entry_key;
use crate::index::btree::test::u64_to_slice;
use crate::index::trees::*;
use crate::index::lsmtree::tree::KeyRange;
use crate::index::lsmtree::tree::LSMTree;
use itertools::Itertools;
use crate::ram::types::Id;
use rand::thread_rng;
use smallvec::SmallVec;
use std::env;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use rayon::prelude::*;
use rand::seq::SliceRandom;

fn dump_trees(lsm_tree: &LSMTree, name: &str) {
    for i in 0..lsm_tree.trees.len() {
        lsm_tree.trees[i].dump(&format!("{}_lsm_{}_dump.json", name, i));
    }
}

fn default_key_range() -> KeyRange {
    (min_entry_key(), min_entry_key())
}

#[test]
pub fn insertions() {
    let _ = env_logger::try_init();
    let tree = Arc::new(LSMTree::new(default_key_range(), Id::unit_id()));
    let num = env::var("LSM_TREE_TEST_ITEMS")
        // this value cannot do anything useful to the test
        // must arrange a long-term test to cover every levels
        .unwrap_or("331776".to_string())
        .parse::<u64>()
        .unwrap();

    let tree_clone = tree.clone();
    debug!("Testing LSM-tree");
    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(10));
        let tree_len = tree_clone.len();
        debug!(
            "LSM-Tree now have {}/{} elements, total {:.2}%",
            tree_len,
            num,
            tree_len as f32 / num as f32 * 100.0
        );
    });

    (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        key_with_id(&mut key, &id);
        tree.insert(key);
    });

    debug!("Start point search validations");
    tree.ensure_trees_in_order();
    (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        debug!("checking: {}", i);
        let cursor = tree.seek(&key, Ordering::Forward);
        key_with_id(&mut key, &id);
        assert_eq!(cursor.current(), Some(&key), "{}", i);
    });

    dump_trees(&*tree, "insertions_before_merge");
    for _ in 0..50 {
        tree.check_and_merge();
    }
    dump_trees(&*tree, "insertions_after_merge");
    tree.ensure_trees_in_order();

    debug!("Start point search validations");
    (0..num).collect::<Vec<_>>().iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        debug!("checking: {}", i);
        let cursor = tree.seek(&key, Ordering::Forward);
        key_with_id(&mut key, &id);
        assert_eq!(cursor.current(), Some(&key), "{}, looking for {:?}", i, key);
    });
}

#[test]
pub fn hybrid() {
    let _ = env_logger::try_init();
    let tree = Arc::new(LSMTree::new(default_key_range(), Id::unit_id()));
    let num = env::var("LSM_TREE_TEST_ITEMS")
        // this value cannot do anything useful to the test
        // must arrange a long-term test to cover every levels
        .unwrap_or("663552".to_string())
        .parse::<u64>()
        .unwrap();

    LSMTree::start_sentinel(&tree);
    let tree_clone = tree.clone();
    debug!("Testing LSM-tree");
    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(10));
        let tree_len = tree_clone.len();
        debug!(
            "LSM-Tree now have {}/{} elements, total {:.2}%",
            tree_len,
            num,
            tree_len as f32 / num as f32 * 100.0
        );
    });

    let mut test_data = (0..num).collect_vec();
    let mut rng = thread_rng();
    test_data.as_mut_slice().shuffle(&mut rng);
    test_data.par_iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        key_with_id(&mut key, &id);
        tree.insert(key);
    });

    tree.ensure_trees_in_order();
    dump_trees(&*tree, "hybird_after_insertion");
    thread::sleep(Duration::new(30, 0));
    dump_trees(&*tree, "hybird_after_sleep");
    tree.ensure_trees_in_order();

    debug!("Start point search validations");
    (0..num).collect::<Vec<_>>().iter().for_each(|i| {
        let i = *i;
        let id = Id::new(0, i);
        let key_slice = u64_to_slice(i);
        let mut key = SmallVec::from_slice(&key_slice);
        debug!("checking: {}", i);
        let cursor = tree.seek(&key, Ordering::Forward);
        key_with_id(&mut key, &id);
        assert_eq!(cursor.current(), Some(&key), "{}", i);
    });
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Average_loop_length

//! Accepts two command-line arguments

extern crate rand;

use rand::{ThreadRng, thread_rng};
use rand::distributions::{IndependentSample, Range};
use std::collections::HashSet;
use std::env;
use std::process;

fn help() {
    println!("usage: average_loop_length <max_N> <trials>");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut max_n: u32 = 20;
    let mut trials: u32 = 1000;

    match args.len() {
        1 => {}
        3 => {
            max_n = args[1].parse::<u32>().unwrap();
            trials = args[2].parse::<u32>().unwrap();
        }
        _ => {
            help();
            process::exit(0);
        }
    }

    let mut rng = thread_rng();

    println!(" N    average    analytical    (error)");
    println!("===  =========  ============  =========");
    for n in 1..(max_n + 1) {
        let the_analytical = analytical(n);
        let the_empirical = empirical(n, trials, &mut rng);
        println!(" {:>2}     {:3.4}        {:3.4}  ( {:>+1.2}%)",
                 n,
                 the_empirical,
                 the_analytical,
                 100f64 * (the_empirical / the_analytical - 1f64));
    }
}

fn factorial(n: u32) -> f64 {
    (1..n + 1).fold(1f64, |p, n| p * n as f64)
}

fn analytical(n: u32) -> f64 {
    let sum: f64 = (1..(n + 1))
                       .map(|i| factorial(n) / (n as f64).powi(i as i32) / factorial(n - i))
                       .fold(0f64, |a, v| a + v);
    sum
}

fn empirical(n: u32, trials: u32, rng: &mut ThreadRng) -> f64 {
    let sum: f64 = (0..trials)
                       .map(|_t| {
                           let mut item = 1u32;
                           let mut seen = HashSet::new();
                           let range = Range::new(1u32, n + 1);

                           for step in 0..n {
                               if seen.contains(&item) {
                                   return step as f64;
                               }
                               seen.insert(item);
                               item = range.ind_sample(rng);
                           }
                           n as f64
                       })
                       .fold(0f64, |a, v| a + v);
    sum / trials as f64
}

#[cfg(test)]
mod tests {
    use super::{factorial, analytical, empirical};
    use rand::{thread_rng};

    #[test]
    fn test_factorial() {
        assert_eq!(factorial(10), 3628800f64);
    }

    #[test]
    fn test_analytical() {
        assert!((analytical(10) - 3.6602).abs() < 0.0001);
        assert!((analytical(20) - 5.2936).abs() < 0.0001);
    }

    #[test]
    fn test_empirical() {
        let mut rng = thread_rng();
        let emp = empirical(20, 10000, &mut rng);
        let ana = analytical(20);
        assert!((emp / ana - 1f64).abs() < 0.05);
    }
}
<commit_msg>directly return bound expressions<commit_after>// http://rosettacode.org/wiki/Average_loop_length

//! Accepts two command-line arguments

extern crate rand;

use rand::{ThreadRng, thread_rng};
use rand::distributions::{IndependentSample, Range};
use std::collections::HashSet;
use std::env;
use std::process;

fn help() {
    println!("usage: average_loop_length <max_N> <trials>");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut max_n: u32 = 20;
    let mut trials: u32 = 1000;

    match args.len() {
        1 => {}
        3 => {
            max_n = args[1].parse::<u32>().unwrap();
            trials = args[2].parse::<u32>().unwrap();
        }
        _ => {
            help();
            process::exit(0);
        }
    }

    let mut rng = thread_rng();

    println!(" N    average    analytical    (error)");
    println!("===  =========  ============  =========");
    for n in 1..(max_n + 1) {
        let the_analytical = analytical(n);
        let the_empirical = empirical(n, trials, &mut rng);
        println!(" {:>2}     {:3.4}        {:3.4}  ( {:>+1.2}%)",
                 n,
                 the_empirical,
                 the_analytical,
                 100f64 * (the_empirical / the_analytical - 1f64));
    }
}

fn factorial(n: u32) -> f64 {
    (1..n + 1).fold(1f64, |p, n| p * n as f64)
}

fn analytical(n: u32) -> f64 {
    (1..(n + 1))
        .map(|i| factorial(n) / (n as f64).powi(i as i32) / factorial(n - i))
        .fold(0f64, |a, v| a + v)
}

fn empirical(n: u32, trials: u32, rng: &mut ThreadRng) -> f64 {
    let sum: f64 = (0..trials)
                       .map(|_t| {
                           let mut item = 1u32;
                           let mut seen = HashSet::new();
                           let range = Range::new(1u32, n + 1);

                           for step in 0..n {
                               if seen.contains(&item) {
                                   return step as f64;
                               }
                               seen.insert(item);
                               item = range.ind_sample(rng);
                           }
                           n as f64
                       })
                       .fold(0f64, |a, v| a + v);
    sum / trials as f64
}

#[cfg(test)]
mod tests {
    use super::{factorial, analytical, empirical};
    use rand::thread_rng;

    #[test]
    fn test_factorial() {
        assert_eq!(factorial(10), 3628800f64);
    }

    #[test]
    fn test_analytical() {
        assert!((analytical(10) - 3.6602).abs() < 0.0001);
        assert!((analytical(20) - 5.2936).abs() < 0.0001);
    }

    #[test]
    fn test_empirical() {
        let mut rng = thread_rng();
        let emp = empirical(20, 10000, &mut rng);
        let ana = analytical(20);
        assert!((emp / ana - 1f64).abs() < 0.05);
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate "calx_util" as util;
extern crate "calx_backend" as backend;

use std::num::{Float};
use util::{color, V2, Rgba, Rect};
use backend::{CanvasBuilder, Key, Event, Fonter, CanvasUtil};

fn main() {
    let mut t = 0i32;
    let mut mouse_pos = V2(-1i32, -1i32);

    for evt in CanvasBuilder::new().run() {
        match evt {
            Event::Render(ctx) => {
                let img = ctx.font_image('@').unwrap();

                ctx.clear();
                for y in 0..(360/8) {
                    for x in 0..(640/8) {
                        let col = if Rect(V2(x * 8, y * 8), V2(8, 8)).contains(&mouse_pos) {
                            color::WHITE } else { color::ORANGE };
                        ctx.draw_image(img, V2(x as f32 * 8.0, y as f32 * 8.0 + 8.0),
                            0.4, &col, &color::BLACK);
                    }
                }
                let center = V2(320.0, 180.0);
                let offset = V2(
                    ((t as f32 / 160.0).cos() * 128.0),
                    ((t as f32 / 160.0).sin() * 128.0));

                ctx.draw_line(3, center, center + offset, 0.3, &Rgba::new(0, 255, 255, 128));

                let fps = 1.0 / ctx.render_duration;
                let _ = write!(&mut ctx.text_writer(V2(0, 8), 0.1, color::LIGHTGREEN)
                               .set_border(color::BLACK),
                    "FPS {:.0}", fps);

                t += 1;
            }
            Event::KeyPressed(Key::Escape) => {
                return;
            }
            Event::KeyPressed(k) => {
                println!("Pressed {:?}", k);
            }
            Event::Char(c) => {
                println!("Typed {:?}", c);
            }
            Event::MouseMoved((x, y)) => {
                mouse_pos = V2(x, y);
            }
            _ => ()
        }
    }
}
<commit_msg>Demo draws outside the clip zone test bits<commit_after>#![allow(unstable)]

extern crate "calx_util" as util;
extern crate "calx_backend" as backend;

use std::num::{Float};
use util::{color, V2, Rgba, Rect};
use backend::{CanvasBuilder, Key, Event, Fonter, CanvasUtil};

fn main() {
    let mut t = 0i32;
    let mut mouse_pos = V2(-1i32, -1i32);

    for evt in CanvasBuilder::new().run() {
        match evt {
            Event::Render(ctx) => {
                let img = ctx.font_image('@').unwrap();

                ctx.clear();
                for y in 0..(360/8) {
                    for x in 0..(640/8) {
                        let col = if Rect(V2(x * 8, y * 8), V2(8, 8)).contains(&mouse_pos) {
                            color::WHITE } else { color::ORANGE };
                        ctx.draw_image(img, V2(x as f32 * 8.0, y as f32 * 8.0 + 8.0),
                            0.4, &col, &color::BLACK);
                    }
                }

                // These should be clipped off the screen.
                let img = ctx.font_image('#').unwrap();
                ctx.draw_image(img, V2(316.0, 0.0), 0.4, &color::GREEN, &color::BLACK);
                ctx.draw_image(img, V2(316.0, 368.0), 0.4, &color::GREEN, &color::BLACK);
                ctx.draw_image(img, V2(-8.0, 184.0), 0.4, &color::GREEN, &color::BLACK);
                ctx.draw_image(img, V2(640.0, 184.0), 0.4, &color::GREEN, &color::BLACK);

                let center = V2(320.0, 180.0);
                let offset = V2(
                    ((t as f32 / 160.0).cos() * 128.0),
                    ((t as f32 / 160.0).sin() * 128.0));

                ctx.draw_line(3, center, center + offset, 0.3, &Rgba::new(0, 255, 255, 128));

                let fps = 1.0 / ctx.render_duration;
                let _ = write!(&mut ctx.text_writer(V2(0, 8), 0.1, color::LIGHTGREEN)
                               .set_border(color::BLACK),
                    "FPS {:.0}", fps);

                t += 1;
            }
            Event::KeyPressed(Key::Escape) => {
                return;
            }
            Event::KeyPressed(k) => {
                println!("Pressed {:?}", k);
            }
            Event::Char(c) => {
                println!("Typed {:?}", c);
            }
            Event::MouseMoved((x, y)) => {
                mouse_pos = V2(x, y);
            }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2012-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in
//   the documentation and/or other materials provided with the
//   distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// no-pretty-expanded FIXME #15189

#![allow(non_snake_case)]

use std::from_str::FromStr;
use std::iter::count;
use std::cmp::min;
use std::os;
use std::sync::{Arc, RWLock};

fn A(i: uint, j: uint) -> f64 {
    ((i + j) * (i + j + 1) / 2 + i + 1) as f64
}

fn dot(v: &[f64], u: &[f64]) -> f64 {
    let mut sum = 0.0;
    for (&v_i, &u_i) in v.iter().zip(u.iter()) {
        sum += v_i * u_i;
    }
    sum
}

fn mult(v: Arc<RWLock<Vec<f64>>>, out: Arc<RWLock<Vec<f64>>>,
        f: fn(&Vec<f64>, uint) -> f64) {
    // We launch in different tasks the work to be done.  To finish
    // this function, we need to wait for the completion of every
    // tasks.  To do that, we give to each tasks a wait_chan that we
    // drop at the end of the work.  At the end of this function, we
    // wait until the channel hang up.
    let (tx, rx) = channel();

    let len = out.read().len();
    let chunk = len / 20 + 1;
    for chk in count(0, chunk) {
        if chk >= len {break;}
        let tx = tx.clone();
        let v = v.clone();
        let out = out.clone();
        spawn(proc() {
            for i in range(chk, min(len, chk + chunk)) {
                let val = f(&*v.read(), i);
                *out.write().get_mut(i) = val;
            }
            drop(tx)
        });
    }

    // wait until the channel hang up (every task finished)
    drop(tx);
    for () in rx.iter() {}
}

fn mult_Av_impl(v: &Vec<f64> , i: uint) -> f64 {
    let mut sum = 0.;
    for (j, &v_j) in v.iter().enumerate() {
        sum += v_j / A(i, j);
    }
    sum
}

fn mult_Av(v: Arc<RWLock<Vec<f64>>>, out: Arc<RWLock<Vec<f64>>>) {
    mult(v, out, mult_Av_impl);
}

fn mult_Atv_impl(v: &Vec<f64> , i: uint) -> f64 {
    let mut sum = 0.;
    for (j, &v_j) in v.iter().enumerate() {
        sum += v_j / A(j, i);
    }
    sum
}

fn mult_Atv(v: Arc<RWLock<Vec<f64>>>, out: Arc<RWLock<Vec<f64>>>) {
    mult(v, out, mult_Atv_impl);
}

fn mult_AtAv(v: Arc<RWLock<Vec<f64>>>, out: Arc<RWLock<Vec<f64>>>,
             tmp: Arc<RWLock<Vec<f64>>>) {
    mult_Av(v, tmp.clone());
    mult_Atv(tmp, out);
}

fn main() {
    let args = os::args();
    let args = args.as_slice();
    let n = if os::getenv("RUST_BENCH").is_some() {
        5500
    } else if args.len() < 2 {
        2000
    } else {
        FromStr::from_str(args[1].as_slice()).unwrap()
    };
    let u = Arc::new(RWLock::new(Vec::from_elem(n, 1f64)));
    let v = Arc::new(RWLock::new(Vec::from_elem(n, 1f64)));
    let tmp = Arc::new(RWLock::new(Vec::from_elem(n, 1f64)));
    for _ in range(0u8, 10) {
        mult_AtAv(u.clone(), v.clone(), tmp.clone());
        mult_AtAv(v.clone(), u.clone(), tmp.clone());
    }

    let u = u.read();
    let v = v.read();
    println!("{:.9f}", (dot(u.as_slice(), v.as_slice()) /
                        dot(v.as_slice(), v.as_slice())).sqrt());
}
<commit_msg>bench: Improve the spectralnorm shootout benchmark<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2012-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in
//   the documentation and/or other materials provided with the
//   distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// no-pretty-expanded FIXME #15189

#![allow(non_snake_case)]
#![feature(unboxed_closures, overloaded_calls)]

use std::iter::AdditiveIterator;
use std::mem;
use std::os;
use std::raw::Repr;
use std::simd::f64x2;

fn main() {
    let args = os::args();
    let answer = spectralnorm(if os::getenv("RUST_BENCH").is_some() {
        5500
    } else if args.len() < 2 {
        2000
    } else {
        from_str(args[1].as_slice()).unwrap()
    });
    println!("{:.9f}", answer);
}

fn spectralnorm(n: uint) -> f64 {
    assert!(n % 2 == 0, "only even lengths are accepted");
    let mut u = Vec::from_elem(n, 1.0);
    let mut v = Vec::from_elem(n, 1.0);
    let mut tmp = Vec::from_elem(n, 1.0);
    for _ in range(0u, 10) {
        mult_AtAv(u.as_slice(), v.as_mut_slice(), tmp.as_mut_slice());
        mult_AtAv(v.as_slice(), u.as_mut_slice(), tmp.as_mut_slice());
    }
    (dot(u.as_slice(), v.as_slice()) / dot(v.as_slice(), v.as_slice())).sqrt()
}

fn mult_AtAv(v: &[f64], out: &mut [f64], tmp: &mut [f64]) {
    mult_Av(v, tmp);
    mult_Atv(tmp, out);
}

fn mult_Av(v: &[f64], out: &mut [f64]) {
    parallel(out, |&: start, out| mult(v, out, start, |i, j| A(i, j)));
}

fn mult_Atv(v: &[f64], out: &mut [f64]) {
    parallel(out, |&: start, out| mult(v, out, start, |i, j| A(j, i)));
}

fn mult(v: &[f64], out: &mut [f64], start: uint, a: |uint, uint| -> f64) {
    for (i, slot) in out.iter_mut().enumerate().map(|(i, s)| (i + start, s)) {
        let mut sum = f64x2(0.0, 0.0);
        for (j, chunk) in v.chunks(2).enumerate().map(|(j, s)| (2 * j, s)) {
            let top = f64x2(chunk[0], chunk[1]);
            let bot = f64x2(a(i, j), a(i, j + 1));
            sum += top / bot;
        }
        let f64x2(a, b) = sum;
        *slot = a + b;
    }
}

fn A(i: uint, j: uint) -> f64 {
    ((i + j) * (i + j + 1) / 2 + i + 1) as f64
}

fn dot(v: &[f64], u: &[f64]) -> f64 {
    v.iter().zip(u.iter()).map(|(a, b)| *a * *b).sum()
}

// Executes a closure in parallel over the given mutable slice. The closure `f`
// is run in parallel and yielded the starting index within `v` as well as a
// sub-slice of `v`.
fn parallel<'a, T, F>(v: &'a mut [T], f: F)
                      where T: Send + Sync,
                            F: Fn(uint, &'a mut [T]) + Sync {
    let (tx, rx) = channel();
    let size = v.len() / os::num_cpus() + 1;

    for (i, chunk) in v.chunks_mut(size).enumerate() {
        let tx = tx.clone();

        // Need to convert `f` and `chunk` to something that can cross the task
        // boundary.
        let f = &f as *const _ as *const uint;
        let raw = chunk.repr();
        spawn(proc() {
            let f = f as *const F;
            unsafe { (*f)(i * size, mem::transmute(raw)) }
            drop(tx)
        });
    }
    drop(tx);
    for () in rx.iter() {}
}
<|endoftext|>


<commit_before>// ignore-windows: No libc on Windows

#![feature(rustc_private)]
extern crate libc;

use std::mem;

pub type Key = libc::pthread_key_t;

static mut RECORD : usize = 0;
static mut KEYS : [Key; 2] = [0; 2];
static mut GLOBALS : [u64; 2] = [1, 0];

static mut CANNARY : *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail.

pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
    let mut key = 0;
    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
    key
}

pub unsafe fn set(key: Key, value: *mut u8) {
    let r = libc::pthread_setspecific(key, value as *mut _);
    assert_eq!(r, 0);
}

pub fn record(r: usize) {
    assert!(r < 10);
    unsafe { RECORD = RECORD*10 + r };
}

unsafe extern fn dtor(ptr: *mut u64) {
    assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often
    let val = *ptr;

    let which_key = GLOBALS.iter().position(|global| global as *const _ == ptr).expect("Should find my global");
    record(which_key);

    if val > 0 {
        *ptr = val-1;
        set(KEYS[which_key], ptr as *mut _);
    }

    // Check if the records matches what we expect. If yes, clear the cannary.
    // If the record is wrong, the cannary will never get cleared, leading to a leak -> test fails.
    // If the record is incomplete (i.e., more dtor calls happen), the check at the beginning of this function will fail -> test fails.
    // The correct sequence is: First key 0, then key 1, then key 0.
    if RECORD == 0_1_0 {
        drop(Box::from_raw(CANNARY));
        CANNARY = 0 as *mut _;
    }
}

fn main() {
    unsafe {
        create(None); // check that the no-dtor case works

        // Initialize the keys we use to check destructor ordering
        for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) {
            *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64))));
            set(*key, global as *const _ as *mut _);
        }

        // Initialize cannary
        CANNARY = Box::into_raw(Box::new(0u64));
    }
}
<commit_msg>fix writing to read-only raw pointer in thread-local test<commit_after>// ignore-windows: No libc on Windows

#![feature(rustc_private)]
extern crate libc;

use std::mem;

pub type Key = libc::pthread_key_t;

static mut RECORD : usize = 0;
static mut KEYS : [Key; 2] = [0; 2];
static mut GLOBALS : [u64; 2] = [1, 0];

static mut CANNARY : *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail.

pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
    let mut key = 0;
    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
    key
}

pub unsafe fn set(key: Key, value: *mut u8) {
    let r = libc::pthread_setspecific(key, value as *mut _);
    assert_eq!(r, 0);
}

pub fn record(r: usize) {
    assert!(r < 10);
    unsafe { RECORD = RECORD*10 + r };
}

unsafe extern fn dtor(ptr: *mut u64) {
    assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often
    let val = *ptr;

    let which_key = GLOBALS.iter().position(|global| global as *const _ == ptr).expect("Should find my global");
    record(which_key);

    if val > 0 {
        *ptr = val-1;
        set(KEYS[which_key], ptr as *mut _);
    }

    // Check if the records matches what we expect. If yes, clear the cannary.
    // If the record is wrong, the cannary will never get cleared, leading to a leak -> test fails.
    // If the record is incomplete (i.e., more dtor calls happen), the check at the beginning of this function will fail -> test fails.
    // The correct sequence is: First key 0, then key 1, then key 0.
    if RECORD == 0_1_0 {
        drop(Box::from_raw(CANNARY));
        CANNARY = 0 as *mut _;
    }
}

fn main() {
    unsafe {
        create(None); // check that the no-dtor case works

        // Initialize the keys we use to check destructor ordering
        for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) {
            *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64))));
            set(*key, global as *mut _ as *mut u8);
        }

        // Initialize cannary
        CANNARY = Box::into_raw(Box::new(0u64));
    }
}
<|endoftext|>