#perfect-hash #hashing #hash-map #codegen #mphf #generate-static

bin+lib quickphf_codegen

Code generator for creating static maps and sets for use with quickphf

2 releases

0.1.1 Nov 22, 2023
0.1.0 Oct 16, 2023

#1198 in Data structures

Zlib OR Apache-2.0 OR MIT

60KB
973 lines

QuickPHF-Codegen

Latest Release Documentation Minimum Supported Rust Version 1.56

quickphf_codegen is a Rust crate that allows you to generate static hash maps and hash sets at compile-time using PTHash perfect hash functions.

For the runtime code necessary to use these data structures check out the quickphf crate instead.

The minimum supported Rust version is 1.56. This crate uses #![forbid(unsafe_code)].

WARNING: quickphf and quickphf_codegen currently use the standard library Hash trait which is not portable between systems with different endianness.

Example

Currently, the only way to generate data structures for use with quickphf is by running one of build_raw_map, build_map, or build_set, displaying the result as a string, and then importing the resulting Rust code at the desired location.

For example, you can write a build.rs script such as:

use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

fn main() {
    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
    let mut file = BufWriter::new(fs::File::create(&path).unwrap());

    let keys = ["jpg", "png", "svg"];
    let values = ["image/jpeg", "image/png", "image/svg+xml"];
    let code = quickphf_codegen::build_map(&keys, &values);

    write!(&mut file, code).unwrap();
}

and then import the result in your lib.rs by:

static MIME_TYPES: quickphf::PhfMap<&'static str, &'static str> =
    include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

Advanced Usage

Using QuickPHF with custom types

To be usable as a key in a PhfMap or PhfSet, or as value in a RawPhfMap or a PhfMap, a type must implement the trait ConstInstantiable, which provides a way to generate code which instantiates any value of that type in a const context. This trait is already implemented for many built-in types, but users can also implement it for their own custom types, by one of two ways:

  1. If the code required to instantiate a value of a type is identical to its Debug representation, for example, like the following enum:
#[derive(Debug, Hash, PartialEq, Eq)]
enum PositionType {
    Contract { hours_per_week: u32 },
    Salaried,
    Managerial,
}

then it suffices to write

impl quickphf_codegen::DebugInstantiable for PositionType {}
  1. The user has to provide a custom implementation. For example, the following struct has private fields and thus its values cannot be instantiated using the {} syntax, but provides a new constructor that is const fn. Thus, given
#[derive(Debug, Hash, PartialEq, Eq)]
struct EmploymentRules {
    overtime_eligible: bool,
    bonus_eligible: bool,
}

impl EmploymentRules {
    pub const fn new(overtime_eligible: bool, bonus_eligible: bool) -> EmploymentRules {
        EmploymentRules {
            overtime_eligible,
            bonus_eligible,
        }
    }
}

we can provide a custom ConstInstantiable implementation by

use core::fmt;
use quickphf_codegen::*;

impl ConstInstantiable for EmploymentRules {
    fn fmt_const_new(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "EmploymentRules::new({}, {})",
            self.overtime_eligible, self.bonus_eligible
        )
    }
}

Performance

Generating a PHF-based data structure with quickphf_codegen is about 10 times faster than with phf. It can generate a 1,000,000 entry map in about 300 ms.

License

Licensed under any of:

by your choice.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be multi-licensed as above, without any additional terms or conditions.

Dependencies

~94KB