diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-20 03:38:10 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-20 03:38:10 +0800 |
| commit | 5678e0ba37ce2c5c8161f0d48505e7993967e30c (patch) | |
| tree | e6035d2e8bf4139e634052fef8c0c48d4c97434a /mingling_macros/src/func | |
| parent | ec9edc294fd5e7e29977fc7b0e6fb953422bc0e2 (diff) | |
feat: add dispatch strategy features with auto-selection and benchmark
support
Add `dispatch_linear`, `dispatch_tree`, and `dispatch_phf` as mutually
exclusive features for selecting the command dispatch strategy. When no
strategy feature is enabled, an auto-selection heuristic picks the
optimal strategy based on command table characteristics (size, name
length, nesting depth).
Add the `bench_support` feature to compile all three generators for the
benchmark harness, and introduce `bench_cell!` to generate benchmark
cells comparing strategies.
The PHF generator uses a CHD minimal perfect hash for O(1) lookup
independent of table size, while the trie generator was refactored to
use a shared fallback method, keeping code size linear in table size.
Diffstat (limited to 'mingling_macros/src/func')
| -rw-r--r-- | mingling_macros/src/func/program_final_gen.rs | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/mingling_macros/src/func/program_final_gen.rs b/mingling_macros/src/func/program_final_gen.rs index ceee66d..b67531e 100644 --- a/mingling_macros/src/func/program_final_gen.rs +++ b/mingling_macros/src/func/program_final_gen.rs @@ -15,9 +15,17 @@ use crate::RENDERERS_EXIST; #[cfg(feature = "structural_renderer")] use crate::STRUCTURAL_RENDERERS; use crate::get_global_set; -#[cfg(not(feature = "dispatch_tree"))] +#[cfg(all(not(feature = "dispatch_phf"), not(feature = "dispatch_tree")))] +use crate::systems::dispatch_auto; +#[cfg(all(not(feature = "dispatch_phf"), not(feature = "dispatch_tree")))] use crate::systems::dispatch_list_gen; -#[cfg(feature = "dispatch_tree")] +#[cfg(feature = "dispatch_phf")] +use crate::systems::dispatch_phf_gen; +#[cfg(all(not(feature = "dispatch_phf"), not(feature = "dispatch_tree")))] +use crate::systems::dispatch_phf_gen; +#[cfg(all(not(feature = "dispatch_phf"), feature = "dispatch_tree"))] +use crate::systems::dispatch_tree_gen; +#[cfg(all(not(feature = "dispatch_phf"), not(feature = "dispatch_tree")))] use crate::systems::dispatch_tree_gen; #[cfg(feature = "async")] @@ -27,7 +35,8 @@ const ASYNC_ENABLED: bool = false; /// Generate the `get_nodes()` function body for a `ProgramCollect` impl. /// -/// Shared by both dispatch strategies (trie and linear list); it only depends +/// Shared by all three dispatch strategies (linear list, trie, perfect hash); +/// it only depends /// on the compile-time-collected `__internal_dispatcher_*` statics. fn gen_get_nodes(entries: &[(String, String, String)]) -> proc_macro2::TokenStream { let mut node_entries = Vec::new(); @@ -170,28 +179,67 @@ pub(crate) fn program_final_gen_impl(_input: TokenStream) -> TokenStream { }) .collect(); - // The `dispatch_tree` feature only selects the internal matching strategy: - // a char-level trie when enabled, a linear longest-prefix list otherwise. - #[cfg(feature = "dispatch_tree")] - let dispatch_gen = { + // The dispatch strategy is selected by features: + // - `dispatch_phf` (perfect hash) has priority + // - `dispatch_tree` (char-level trie) + // - `dispatch_linear`, or no dispatch feature at all ("auto" mode), picks + // the best strategy from the command table via + // `dispatch_auto::select_strategy`. + // The three dispatch features are mutually exclusive (see the crate-level + // `compile_error!` in lib.rs). + // + // `dispatch_extra` carries items that must live in an inherent impl of + // the program type (currently the trie's `__trie_fallback` method). + #[cfg(feature = "dispatch_phf")] + let (dispatch_gen, dispatch_extra) = { let get_nodes_fn = gen_get_nodes(&entries); - let dispatch_fn = dispatch_tree_gen::gen_dispatch_args_trie(&entries); + let dispatch_fn = dispatch_phf_gen::gen_dispatch_args_phf(&entries); - quote! { - #get_nodes_fn - #dispatch_fn - } + ( + quote! { + #get_nodes_fn + #dispatch_fn + }, + quote! {}, + ) }; - #[cfg(not(feature = "dispatch_tree"))] - let dispatch_gen = { + #[cfg(all(not(feature = "dispatch_phf"), feature = "dispatch_tree"))] + let (dispatch_gen, dispatch_extra) = { let get_nodes_fn = gen_get_nodes(&entries); - let dispatch_fn = dispatch_list_gen::gen_dispatch_args(&entries); + let (dispatch_fn, extra) = dispatch_tree_gen::gen_dispatch_args_trie(&entries); - quote! { - #get_nodes_fn - #dispatch_fn - } + ( + quote! { + #get_nodes_fn + #dispatch_fn + }, + extra, + ) + }; + + #[cfg(all(not(feature = "dispatch_phf"), not(feature = "dispatch_tree")))] + let (dispatch_gen, dispatch_extra) = { + let get_nodes_fn = gen_get_nodes(&entries); + let (dispatch_fn, extra) = match dispatch_auto::select_strategy(&entries) { + dispatch_auto::DispatchStrategy::Linear => { + (dispatch_list_gen::gen_dispatch_args(&entries), quote! {}) + } + dispatch_auto::DispatchStrategy::Trie => { + dispatch_tree_gen::gen_dispatch_args_trie(&entries) + } + dispatch_auto::DispatchStrategy::Phf => { + (dispatch_phf_gen::gen_dispatch_args_phf(&entries), quote! {}) + } + }; + + ( + quote! { + #get_nodes_fn + #dispatch_fn + }, + extra, + ) }; #[cfg(feature = "comp")] @@ -436,6 +484,7 @@ pub(crate) fn program_final_gen_impl(_input: TokenStream) -> TokenStream { pub fn this() -> &'static ::mingling::Program<#name> { &::mingling::this::<#name>() } + #dispatch_extra } }; |
