[librsvg: 1/95] Generate a PHF of SVG attribute names



commit fe3297f336b712d44e70f4a6af5f8e08f9e0c59a
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Feb 7 12:31:54 2018 -0600

    Generate a PHF of SVG attribute names
    
    We will map SVG attribute names to enum values using a Perfect Hash
    Function, instead of doing string comparisons and hash table lookups
    everywhere.
    
    At build time, we generate the PHF mapping.  We do this with
    phf_codegen (in the build.rs script) instead of phf_macros, as the
    latter cannot be used on Rust stable yet.

 Makefile.am            |   2 +
 rust/Cargo.lock        |  42 ++++++++++++-
 rust/Cargo.toml        |   5 ++
 rust/build.rs          | 156 +++++++++++++++++++++++++++++++++++++++++++++++++
 rust/src/attributes.rs |  28 +++++++++
 rust/src/lib.rs        |   1 +
 6 files changed, 231 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index e7a7ae77..5cdf82d5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -64,7 +64,9 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
 
 RUST_SOURCES =                                 \
        rust/Cargo.toml                         \
+       rust/build.rs                           \
        rust/src/aspect_ratio.rs                \
+       rust/src/attributes.rs                  \
        rust/src/bbox.rs                        \
        rust/src/chars.rs                       \
        rust/src/clip_path.rs                   \
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 779a0046..f9179c55 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -220,7 +220,7 @@ version = "0.7.21"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -248,11 +248,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index";
 
 [[package]]
 name = "rand"
-version = "0.3.20"
+version = "0.3.22"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 dependencies = [
  "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -287,6 +298,8 @@ dependencies = [
  "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -355,6 +368,25 @@ name = "winapi"
 version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 
+[[package]]
+name = "winapi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+
 [metadata]
 "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = 
"d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = 
"b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
@@ -387,7 +419,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index";
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = 
"3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum procedural-masquerade 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = 
"dc1bcafee1590f81acb329ae45ec627b318123f085153913620316ae9a144b2a"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = 
"7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
-"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = 
"512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
+"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = 
"15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
+"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
 "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = 
"744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
 "checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
@@ -400,3 +433,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index";
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = 
"6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = 
"167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = 
"04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = 
"712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 487e91d8..ad20a0d9 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -2,6 +2,10 @@
 name = "rsvg_internals"
 version = "0.0.1"
 authors = ["Federico Mena Quintero <federico gnome org>"]
+build = "build.rs"
+
+[build-dependencies]
+phf_codegen = "0.7.21"
 
 [dependencies]
 libc = "0.2"
@@ -12,6 +16,7 @@ pango = "0.3.0"
 pango-sys = "0.5.0"
 cssparser = "0.23"
 lazy_static = "1.0.0"
+phf = "0.7.21"
 
 [dependencies.cairo-sys-rs]
 version = "0.5.0"
diff --git a/rust/build.rs b/rust/build.rs
new file mode 100644
index 00000000..de73fc26
--- /dev/null
+++ b/rust/build.rs
@@ -0,0 +1,156 @@
+extern crate phf_codegen;
+
+use std::env;
+use std::fs::File;
+use std::io::{BufWriter, Write};
+use std::path::Path;
+
+fn main() {
+    generate_phf_of_svg_attributes();
+}
+
+/// Creates a perfect hash function (PHF) to map SVG attribute names to enum values.
+fn generate_phf_of_svg_attributes() {
+    // (attribute name, Rust enum value, C enum value suffix
+    let attribute_defs = [
+        ( "alternate",          "Alternate",          "ALTERNATE" ),
+        ( "amplitude",          "Amplitude",          "AMPLITUDE" ),
+        ( "azimuth",            "Azimuth",            "AZIMUTH" ),
+        ( "baseFrequency",      "BaseFrequency",      "BASE_FREQUENCY" ),
+        ( "baseline-shift",     "BaselineShift",      "BASELINE_SHIFT" ),
+        ( "bias",               "Bias",               "BIAS" ),
+        ( "class",              "Class",              "CLASS" ),
+        ( "clip-path",          "ClipPath",           "CLIP_PATH" ),
+        ( "clip-rule",          "ClipRule",           "CLIP_RULE" ),
+        ( "color",              "Color",              "COLOR" ),
+        ( "comp-op",            "CompOp",             "COMP_OP" ),
+        ( "diffuseConstant",    "DiffuseConstant",    "DIFFUSE_CONSTANT" ),
+        ( "direction",          "Direction",          "DIRECTION" ),
+        ( "display",            "Display",            "DISPLAY" ),
+        ( "divisor",            "Divisor",            "DIVISOR" ),
+        ( "dx",                 "Dx",                 "DX" ),
+        ( "dy",                 "Dy",                 "DY" ),
+        ( "edgeMode",           "EdgeMode",           "EDGE_MODE" ),
+        ( "elevation",          "Elevation",          "ELEVATION" ),
+        ( "enable-background",  "EnableBackground",   "ENABLE_BACKGROUND" ),
+        ( "encoding",           "Encoding",           "ENCODING" ),
+        ( "exponent",           "Exponent",           "EXPONENT" ),
+        ( "fill",               "Fill",               "FILL" ),
+        ( "fill-opacity",       "FillOpacity",        "FILL_OPACITY" ),
+        ( "fill-rule",          "FillRule",           "FILL_RULE" ),
+        ( "filter",             "Filter",             "FILTER" ),
+        ( "filterUnits",        "FilterUnits",        "FILTERUNITS" ),
+        ( "flood-color",        "FloodColor",         "FLOOD_COLOR" ),
+        ( "flood-opacity",      "FloodOpacity",       "FLOOD_OPACITY" ),
+        ( "font-family",        "FontFamily",         "FONT_FAMILY" ),
+        ( "font-size",          "FontSize",           "FONT_SIZE" ),
+        ( "font-stretch",       "FontStretch",        "FONT_STRETCH" ),
+        ( "font-style",         "FontStyle",          "FONT_STYLE" ),
+        ( "font-variant",       "FontVariant",        "FONT_VARIANT" ),
+        ( "font-weight",        "FontWeight",         "FONT_WEIGHT" ),
+        ( "height",             "Height",             "HEIGHT" ),
+        ( "href",               "Href",               "HREF" ),
+        ( "id",                 "Id",                 "ID" ),
+        ( "in",                 "In",                 "IN" ),
+        ( "in2",                "In2",                "IN2" ),
+        ( "intercept",          "Intercept",          "INTERCEPT" ),
+        ( "k1",                 "K1",                 "K1" ),
+        ( "k2",                 "K2",                 "K2" ),
+        ( "k3",                 "K3",                 "K3" ),
+        ( "k4",                 "K4",                 "K4" ),
+        ( "kernelMatrix",       "KernelMatrix",       "KERNEL_MATRIX" ),
+        ( "kernelUnitLength",   "KernelUnitLength",   "KERNEL_UNIT_LENGTH" ),
+        ( "letter-spacing",     "LetterSpacing",      "LETTER_SPACING" ),
+        ( "lighting-color",     "LightingColor",      "LIGHTING_COLOR" ),
+        ( "limitingConeAngle",  "LimitingConeAngle",  "LIMITING_CONE_ANGLE" ),
+        ( "marker",             "Marker",             "MARKER" ),
+        ( "marker-end",         "MarkerEnd",          "MARKER_END" ),
+        ( "marker-mid",         "MarkerMid",          "MARKER_MID" ),
+        ( "marker-start",       "MarkerStart",        "MARKER_START" ),
+        ( "mask",               "Mask",               "MASK" ),
+        ( "mode",               "Mode",               "MODE" ),
+        ( "numOctaves",         "NumOctaves",         "NUM_OCTAVES" ),
+        ( "offset",             "Offset",             "OFFSET" ),
+        ( "opacity",            "Opacity",            "OPACITY" ),
+        ( "operator",           "Operator",           "OPERATOR" ),
+        ( "order",              "Order",              "ORDER" ),
+        ( "overflow",           "Overflow",           "OVERFLOW" ),
+        ( "parse",              "Parse",              "PARSE" ),
+        ( "pointsAtX",          "PointsAtX",          "POINTS_AT_X" ),
+        ( "pointsAtY",          "PointsAtY",          "POINTS_AT_Y" ),
+        ( "pointsAtZ",          "PointsAtZ",          "POINTS_AT_Z" ),
+        ( "preserveAlpha",      "PreserveAlpha",      "PRESERVE_ALPHA" ),
+        ( "primitiveUnits",     "PrimitiveUnits",     "PRIMITIVE_UNITS" ),
+        ( "radius",             "Radius",             "RADIUS" ),
+        ( "requiredExtensions", "RequiredExtensions", "REQUIRED_EXTENSIONS" ),
+        ( "requiredFeatures",   "RequiredFeatures",   "REQUIRED_FEATURES" ),
+        ( "result",             "Result",             "RESULT" ),
+        ( "scale",              "Scale",              "SCALE" ),
+        ( "seed",               "Seed",               "SEED" ),
+        ( "shape-rendering",    "ShapeRendering",     "SHAPE_RENDERING" ),
+        ( "slope",              "Slope",              "SLOPE" ),
+        ( "specularConstant",   "SpecularConstant",   "SPECULAR_CONSTANT" ),
+        ( "specularExponent",   "SpecularExponent",   "SPECULAR_EXPONENT" ),
+        ( "stdDeviation",       "StdDeviation",       "STD_DEVIATION" ),
+        ( "stitchTiles",        "StitchTiles",        "STITCH_TILES" ),
+        ( "stop-color",         "StopColor",          "STOP_COLOR" ),
+        ( "stop-opacity",       "StopOpacity",        "STOP_OPACITY" ),
+        ( "stroke",             "Stroke",             "STROKE" ),
+        ( "stroke-dasharray",   "StrokeDasharray",    "STROKE_DASHARRAY" ),
+        ( "stroke-dashoffset",  "StrokeDashoffset",   "STROKE_DASHOFFSET" ),
+        ( "stroke-linecap",     "StrokeLinecap",      "STROKE_LINECAP" ),
+        ( "stroke-linejoin",    "StrokeLinejoin",     "STROKE_LINEJOIN" ),
+        ( "stroke-miterlimit",  "StrokeMiterlimit",   "STROKE_MITERLIMIT" ),
+        ( "stroke-opacity",     "StrokeOpacity",      "STROKE_OPACITY" ),
+        ( "stroke-width",       "StrokeWidth",        "STROKE_WIDTH" ),
+        ( "style",              "Style",              "STYLE" ),
+        ( "surfaceScale",       "SurfaceScale",       "SURFACE_SCALE" ),
+        ( "systemLanguage",     "SystemLanguage",     "SYSTEM_LANGUAGE" ),
+        ( "tableValues",        "TableValues",        "TABLE_VALUES" ),
+        ( "targetX",            "TargetX",            "TARGET_X" ),
+        ( "targetY",            "TargetY",            "TARGET_Y" ),
+        ( "text-anchor",        "TextAnchor",         "TEXT_ANCHOR" ),
+        ( "text-decoration",    "TextDecoration",     "TEXT_DECORATION" ),
+        ( "text-rendering",     "TextRendering",      "TEXT_RENDERING" ),
+        ( "transform",          "Transform",          "TRANSFORM" ),
+        ( "type",               "Type",               "TYPE" ),
+        ( "unicode-bidi",       "UnicodeBidi",        "UNICODE_BIDI" ),
+        ( "values",             "Values",             "VALUES" ),
+        ( "visibility",         "Visibility",         "VISIBILITY" ),
+        ( "width",              "Width",              "WIDTH" ),
+        ( "writing-mode",       "WritingMode",        "WRITING_MODE" ),
+        ( "x",                  "X",                  "X" ),
+        ( "xChannelSelector",   "XChannelSelector",   "X_CHANNEL_SELECTOR" ),
+        ( "xlink:href",         "XlinkHref",          "XLINK_HREF" ),
+        ( "xml:lang",           "XmlLang",            "XML_LANG" ),
+        ( "xml:space",          "XmlSpace",           "XML_SPACE" ),
+        ( "y",                  "Y",                  "Y" ),
+        ( "yChannelSelector",   "YChannelSelector",   "Y_CHANNEL_SELECTOR" ),
+        ( "z",                  "Z",                  "Z" ),
+    ];
+
+    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("attributes-codegen.rs");
+    let mut file = BufWriter::new(File::create(&path).unwrap());
+
+    writeln!(&mut file, "#[repr(C)]").unwrap();
+    writeln!(&mut file, "#[derive(Debug, Clone, Copy, PartialEq)]").unwrap();
+    writeln!(&mut file, "pub enum Attribute {{").unwrap();
+
+    for &(_, rust, _) in attribute_defs.iter() {
+        writeln!(&mut file, "    {},", rust).unwrap();
+    }
+    
+    writeln!(&mut file, "}}").unwrap();
+
+    writeln!(&mut file, "static ATTRIBUTES: phf::Map<&'static str, Attribute> = ").unwrap();
+
+    let mut map = phf_codegen::Map::new();
+    map.phf_path("phf");
+    for &(name, rust, _) in attribute_defs.iter() {
+        let rust = ["Attribute::", rust].concat();
+        map.entry(name, &rust);
+    }
+
+    map.build(&mut file).unwrap();
+    writeln!(&mut file, ";").unwrap();
+}
diff --git a/rust/src/attributes.rs b/rust/src/attributes.rs
new file mode 100644
index 00000000..5c7d4c28
--- /dev/null
+++ b/rust/src/attributes.rs
@@ -0,0 +1,28 @@
+extern crate phf;
+
+use std::str::FromStr;
+
+include!(concat!(env!("OUT_DIR"), "/attributes-codegen.rs"));
+
+impl FromStr for Attribute {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Attribute, ()> {
+        ATTRIBUTES.get(s).cloned().ok_or(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parses_attributes() {
+        assert_eq!(Attribute::from_str("width"), Ok(Attribute::Width));
+    }
+
+    #[test]
+    fn unknown_attribute_yields_error() {
+        assert_eq!(Attribute::from_str("foobar"), Err(()));
+    }
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 95605b0a..1fbf438d 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -173,6 +173,7 @@ pub use viewbox::{
 mod coord_units;
 
 mod aspect_ratio;
+mod attributes;
 mod bbox;
 mod chars;
 mod clip_path;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]